不同类型的组合
Composition with different types
我有两个 Java classes B 和 C,它们都从 class A 延伸(我不拥有 class A)。
public class B extends A {…}
public class C extends A {…}
我需要一个“ListItem”类型的列表来保存 B 或 C 的实例,但由于(B 和 C)都已经被扩展,它们不能通过使用“ListItem”作为超级对象来进一步扩展class。
我认为唯一的出路是组合(“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);
}
}
我的意思是,你有:
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;
}
但这开始变得草率了,并且会限制您在 ListItem
.
中存储任何其他 A
派生的内容
您可能想在这里开始质疑您的设计。例如,如果您要向 A
添加一些功能,这些功能对于 B
和 C
是常见的,并且是 ListItem
[] 正常运行所必需的=63=],考虑从 A
派生一些 class 来添加共同的东西,从中派生 B
和 C
,然后让你的 ListItem
存储base(当然,如果你这样做,你就不能再存储 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
成为一个接口,或者 ,然后让您的 B
和 C
实施或扩展它。
我想你也可以 for ListItem
例如<? extends A>
,尽管这可能不合适,尤其是如果您的 ListItem
是混合的。使用泛型的主要好处是,例如getter 现在可以直接 return 子类型而无需强制转换,并且您可以在编译时将类型限制为函数参数和内容中的特定子类型,但除此之外它与仅存储 A
基本相同。
无论如何,除了将 A
存储在 ListItem
中并在更高级别处理不同类型的建议之外,我不能凭良心给您任何其他方法建议,因为对所有这些的需求对我来说似乎是有问题的。
根据您的描述,ListItem
似乎是 A 类(B 或 C,其他子 类 将来)项目的容器。我会推荐使用泛型,使用 <? extends A>
,这样你就不需要一个以上的构造函数,并且 A 的所有方法都应该可用。
我认为一个干净的方法是让你的 ListItem
是从 A
延伸的抽象 class,然后有 B
和 C
从 ListItem
.
扩展
为什么要ListItem
抽象?在 B
和 C
之间共享的任何行为都可以在抽象 class 中实现,并且您还可以在其子 class 上附加接口要求。
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.
}
}
然后你可以声明你的ListItem
列表,根据需要插入B
和C
的实例,并根据[中的具体方法或抽象接口操作它们。 =12=]:
ArrayList<ListItem> list = new ArrayList<>();
list.add(new B());
list.add(new C());
System.out.println(list.get(0).getAge());
list.get(1).manipulate();
我有两个 Java classes B 和 C,它们都从 class A 延伸(我不拥有 class A)。
public class B extends A {…}
public class C extends A {…}
我需要一个“ListItem”类型的列表来保存 B 或 C 的实例,但由于(B 和 C)都已经被扩展,它们不能通过使用“ListItem”作为超级对象来进一步扩展class。
我认为唯一的出路是组合(“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);
}
}
我的意思是,你有:
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;
}
但这开始变得草率了,并且会限制您在 ListItem
.
A
派生的内容
您可能想在这里开始质疑您的设计。例如,如果您要向 A
添加一些功能,这些功能对于 B
和 C
是常见的,并且是 ListItem
[] 正常运行所必需的=63=],考虑从 A
派生一些 class 来添加共同的东西,从中派生 B
和 C
,然后让你的 ListItem
存储base(当然,如果你这样做,你就不能再存储 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
成为一个接口,或者 B
和 C
实施或扩展它。
我想你也可以 ListItem
例如<? extends A>
,尽管这可能不合适,尤其是如果您的 ListItem
是混合的。使用泛型的主要好处是,例如getter 现在可以直接 return 子类型而无需强制转换,并且您可以在编译时将类型限制为函数参数和内容中的特定子类型,但除此之外它与仅存储 A
基本相同。
无论如何,除了将 A
存储在 ListItem
中并在更高级别处理不同类型的建议之外,我不能凭良心给您任何其他方法建议,因为对所有这些的需求对我来说似乎是有问题的。
根据您的描述,ListItem
似乎是 A 类(B 或 C,其他子 类 将来)项目的容器。我会推荐使用泛型,使用 <? extends A>
,这样你就不需要一个以上的构造函数,并且 A 的所有方法都应该可用。
我认为一个干净的方法是让你的 ListItem
是从 A
延伸的抽象 class,然后有 B
和 C
从 ListItem
.
为什么要ListItem
抽象?在 B
和 C
之间共享的任何行为都可以在抽象 class 中实现,并且您还可以在其子 class 上附加接口要求。
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.
}
}
然后你可以声明你的ListItem
列表,根据需要插入B
和C
的实例,并根据[中的具体方法或抽象接口操作它们。 =12=]:
ArrayList<ListItem> list = new ArrayList<>();
list.add(new B());
list.add(new C());
System.out.println(list.get(0).getAge());
list.get(1).manipulate();