java - 不同类型的组合

标签 java composition

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

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

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

我认为唯一的出路是组合(“has-a”关系……)。

因为“ListItem”永远不应该有 B 和 C(但只有其中一个),我计划用 2 个构造函数创建 ListItem 并设置一个适当的 反射(reflect) 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);
    }
}

最佳答案

我的意思是,你有:

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 .

您可能想在这里开始质疑您的设计。例如,如果您要向 A 添加一些功能这对 B 很常见和 C 并且是 ListItem 正常运行所必需的,考虑从 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() 的接口(interface)并使用它。

另一种选择是您可以(如评论中指出的那样)制作 ListItem要么是一个接口(interface),要么是a class that extends A , 然后有你的 BC实现或扩展它。

我想你也可以 use generics对于 ListItem例如<? extends A> ,尽管这可能不合适,尤其是如果您的 ListItem s 是混合的。使用泛型的主要好处是,例如getters 现在可以直接返回子类型而无需强制转换,并且您可以在编译时将类型限制为函数参数和内容中的特定子类型,但除此之外它与仅存储 A 基本相同。 .

无论如何,除了存储 A 的建议之外在 ListItem并在更高级别处理不同的类型,凭良心我不能给你任何其他方法建议,因为对所有这些的需求对我来说似乎是有问题的。

关于java - 不同类型的组合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39215554/

相关文章:

dependency-injection - 依赖于具有不同范围的其他组件的组件(具有不同范围的组件层次结构)

java - 在jsp中调用java方法

java - 这是什么“拉动刷新” View ?

Java 使用 ProcessBuilder 以静默方式运行程序

java - 用于 RESTful Web 服务的 JAX-WS 与 JAX-RS

oop - 组合与继承

java - 类调用其他类

java - 以线程安全的方式发布非线程安全的对象字段

java - 如何在 Java 中获取平铺 map

ruby-on-rails - 具有 composed_of 模型和验证的 Rails 3