不同类型的组成

时间:2016-08-29 21:32:24

标签: java composition

我有两个Java类B和C,它们都从A类扩展(我没有A类)。

public class B extends A {…}
public class C extends A {…}

我需要一个类型为“ListItem”的列表来保存B或C的实例,但由于(B和C)都已经扩展,因此不能通过使用“ListItem”作为超类来进一步扩展它们。

我认为唯一的方法是使用构图(“has-a”关系......)。

由于“ListItem”永远不应该有B和C(但只有一个),我打算用2个构造函数创建ListItem并设置一个适当的 内部类型,以反映B或C是否被保留。

有没有更好的方法来实现这一目标?请参阅下面的伪代码。

public class ListItem {

    private enum elemType {
        TYPE_B, TYPE_C 
    } 

    private final B mBItem;
    private final C mCItem;
    private final elemType mType;

    // used to hold instance of B
    public ListItem(B b) {
        this.mBItem = b;
        this.mType = TYPE_B;
    } 

    // used to hold instance of C
    public ListItem(C c) {
        this.mCItem = c;
        this.mType = TYPE_C;
    }

    // sample method to demonstrate delegation
    private int getAge() {
        int age;

        if (containsB()) {
            age = mBItem.getAge();
        }
        else if (containsC()) {
            age = mCItem.getAge();
        }
        else {…}
        return age;
    }

    private boolean containsB() {
        return (mType == TYPE_B);    
    }

    private boolean containsC() {
        return (mType == TYPE_C);
    }
}

3 个答案:

答案 0 :(得分:3)

我的意思是,你有:

public class B extends A {…}
public class C extends A {…}

所以你可以让你的项目保持A

public class ListItem {

    private final A item;

    public ListItem (A item) { 
        this.item = item; 
    }

}

您可以从那里处理任何数量的选项,例如:简单地:

    public A getItem () {
        return item;
    }

从调用者处进行任何适当的演员表或测试。这是最灵活的方式。或者我想这样的事情:

    public B getB () {
        return item instanceof B ? (B)item : null;
    }

    public C getC () {
        return item instanceof C ? (C)item : null;
    }

但是,这开始变得草率,并且限制您在A中存储任何其他ListItem派生的内容。

您可能想在此处开始质疑您的设计。例如,如果您要为AB 常见的C添加一些功能,并且正确运行ListItem < / em>,考虑从A派生一些类来添加常见内容,从中派生BC,并使您的ListItem商店成为基础(当然,如果你这样做,你就不能再存储A了:

public class AgedA extends A {
    ...
    public int getAge () { return ... }
}

// Then your B and C both extend AgedA, and your ListItem stores an
// AgedA and can use getAge().

如果情况更合适,您可以将AgedA变为抽象,getAge()为虚拟。或者您可以声明一个定义getAge()的接口并使用它。

另一种选择是你可以(如评论中所指出的那样)使ListItem成为界面或a class that extends A,然后让你的BC实施或延伸。

我想您ListItem也可以use generics,例如{} <? extends A>,虽然这可能不合适,特别是如果您的ListItem是混合的。使用泛型的主要好处是例如getters现在可以直接返回没有强制类型的子类型,并且你可以自己编译时将类型限制为函数参数和东西中的特定子类型,但除此之外它与存储A基本相同。

在任何情况下,除了在A中存储ListItem并在更高级别处理不同类型的建议之外,我无法提供任何其他方法建议,因为所有这一切的需要对我来说都是值得怀疑的。

答案 1 :(得分:3)

我认为一个干净的方法是让您的ListItem成为从A延伸的抽象类,然后BC从{{1}延伸}。

为什么要ListItem抽象?在ListItemB之间共享的任何行为都可以在抽象类中实现,并且您还可以在其子类上强加接口要求。

C

然后你可以声明你的public abstract class ListItem extends A { public int getAge () { // Both B and C share this implementation } // But B and C behave differently for this method public abstract void manipulate (); } public class B extends ListItem { public void manipulate () { // Something specific to B here. } } public class C extends ListItem { public void manipulate () { // Something specific to C here. } } 列表,根据需要插入ListItemB的实例,并根据{{1中的具体方法或抽象接口来操纵它们}}:

C

答案 2 :(得分:0)

根据您的描述,$the_best_price = []; //initializing an empty array. foreach($best_price as $best_price_id) { $the_best_price[] = $best_price_id->shop_name; }; return $the_best_price; //this will return all as an array, 似乎是A类(B或C,以后的其他子类)项的容器。我建议使用泛型,使用return,您将不需要多个构造函数,并且所有A方法都应该可用。