在 Java 中混合组合和继承
Mixing Composition and Inheritance in Java
是否可以在 Java 中混合组合和继承?拳头我有一些通用的类是一个HAS-A(或HAS-MANY)关系(组合)。
通用 类:
Structure、TypeA、TypeB、TypeC等,其中Structure与TypeA、TypeB、TypeC是HAS-A关系。
但是后来我也有几组sub类继承自泛型类(继承)并且处于相同的关系
套子类:
第 1 组:
Structure1、TypeA1、TypeB1、TypeC1等,其中Structure1与TypeA1、TypeB1、TypeC1是同一个HAS-A关系,就像泛型类.
并且:Structure1 extends Structure,TypeA1 extends TypeA,...,TypeC1 extends TypeC,等等
...直到第 X 组:
StructureX、TypeAX、TypeBX、TypeCX 等
每个特殊结构都有一个特定的 sub-TypeA、sub-TypeB 和 sub-TypeC 等。通用 类 定义了一些代码(属性和方法),我希望在处理特殊结构时重用这些代码。 下面的代码可以很好地解释我面临的问题。 (我不知道这是否可以通过 Java "generics" 以某种方式解决,但我认为不能。)
/***********************************************************************************************
/ Generic Structure of Structure-Class with Instances of Generic other classes (Composition)
/***********************************************************************************************/
class Structure {
// Substructures
TypeA instanceA;
TypeB instanceB;
// Defining many methods using the instances of other generic classes like TypeA
void setGenericAttributeOfA(int value) {
instanceA.genericAttribute = value;
}
void setGenericAttributeOfB(int value) {
instanceB.genericAttribute = value;
}
}
class TypeA {
int genericAttribute;
}
class TypeB {
int genericAttribute;
}
/***********************************************************************************************
/ Specific implementation of a Structure-Class with specific implementation of the other classes (Inheritance)
/***********************************************************************************************/
// In the specific implementations I want to use the generic methods, because I do not want to
// rewrite the code for each and every specific implementation. But they should
class Structure1 extends Structure {
// This will create an additional attribute instanceA of specific TypeA1, so I will end up with two instances:
// (1) TypeA super.instanceA and (2) TypeA1 this.instanceA. But what I would like is to have only
// one instanceA of type TypeA1 that can also be used by the global methods of the generic Structure.
TypeA1 instanceA;
Structure1() {
// This creates an instance of type TypeA1, but it cannot be used in the generic methods
// because it is hold in a separate "local" variable that is not known to the generic Structure methods
instanceA = new TypeA1();
// This creates an instance of type TypeB1, but it cannot access the "local" specific attributes,
// because it is hold in a varable which is statically types as TypeB
instanceB = new TypeB1();
}
void specificMethod() {
setGenericAttributeOfA(42); // would fail, because instanceA of type generic TypeA is null
instanceA.specificAttribute = 13; // works only for "local" specific attributes
setGenericAttributeOfB(42); // works only for generic attributes
instanceB.specificAttribute = 13; // would fail, because instanceB is statically typed as generic TypeB which does not have this attribute
((TypeB1)instanceB).specificAttribute = 13; // works but is an ugly work-around and over-complicated if to be used many times
}
}
class TypeA1 extends TypeA {
int specificAttribute;
}
class TypeB1 extends TypeB {
int specificAttribute;
}
也许Generics可以帮忙?
声明 Structure
为通用:
class Structure<T1 extends TypeA, T2 extends TypeB, T3 extends TypeC> {
T1 instanceA;
T2 instanceB;
T3 instanceC;
}
并且您的特定结构将通过指定类型参数从泛型 Structure
继承:
class Structure1 extends Structure<TypeA1, TypeB1, TypeC1> {
// here instanceA will be of type TypeA1, instanceB will be TypeB1 etc.
}
您的类型层次结构似乎不必要地复杂。围绕数据实现继承通常具有挑战性,这个场景就是一个典型的例子。
您可以考虑重新设计类型的要点:
Type
和 TypeB
是相同的,至少就 post 而言是这样。除非这些 class 中的每一个都有特定的行为,否则您可以让它们合并:
// Replacement for TypeA and TypeB
class Type {
int genericAttribute;
}
如果它们有特定的行为,您可以制作 Type
接口并考虑切换到 getter 和 setter 而不是字段(无论如何这是一个更好的主意)
之后,TypeA1
和TypeB1
可以扩展同一个父级,Type
:
class TypeA1 extends Type {
int specificAttribute;
}
class TypeB1 extends Type {
int specificAttribute;
}
关于 Structure
class:你只需要这个 class 因为你想实现 "generic" 与 TypeA
和 TypeB
相关的行为。应该不再需要这种区别了,因为这两个已经合并到 Type
,所以你可以省去这个 class,留下数据来处理。并且数据可以移动到 Structure1
(不需要为这些字段设置一个公共的、单独的位置,因为 Structure1
无论如何都有两种具体类型):
//this doesn't need a parent any more
class Structure1 {
TypeA1 instanceA;
TypeB1 instanceB;
Structure1() {
instanceA = new TypeA1();
instanceB = new TypeB1();
}
//This doesn't have to be implemented like this
//I kept it to show the relation to your original
//design. I would simply add
//setGenericAttribute(int) to Type
void setGenericAttribute(Type type, int value) {
type.genericAttribute = value;
}
void specificMethod() {
setGenericAttribute(instanceA, 42);
instanceA.specificAttribute = 13;
setGenericAttribute(instanceB, 42);
instanceB.specificAttribute = 13;
}
}
TL;DR 在你的类型上使用方法转发,如果这确实有效,因为事情太复杂了,那么查找 SOLID 原则并使用设计模式来制作你的类型和 class紧随其后。
- 为每种类型添加 getter 和 setter,并且永远不要直接访问字段。如果您打算直接访问字段,请使用内部 class。使用 getter 和 setter,您可以拥有一个 infoObject,它可以携带可以传递给您想要的特定字段的值。或者你可以传入一个数据结构,或者你使用可变参数。无论哪种方式,你都有灵活性。
- 我不知道你是在尝试处理结构设计问题还是行为设计问题,这就是你遇到问题的原因。 查找 SOLID 原则。 您的
Structure
class 试图达到两个目的。您正在尝试创建一个负责创建和包含对象的数据对象,同时还尝试为对象处理数据。 您基本上需要选择两种设计模式来处理您的意图。我建议使用 Bridge and Builder 模式。 创建一个构建 Type 对象的构建器 class,然后使结构 class 仅包含顶部 class 的字段。然后结构 class 不必访问类型特定的方法或字段。构建器会,所以你需要考虑为不同类型制作构建器的最佳 SOLID 方法。您可能需要为每种类型或每个 class 构建器,具体取决于它的复杂程度,但如果您有 getter 和 setter,那也不会太糟糕。此外,您可能想考虑将工厂或抽象工厂与构建器一起使用,以便工厂确定对象的类型(以及 class child/parent 的类型),构建器将利用该信息构建一个该特定 class 的对象,其中填充了所有特定字段。
方法转发是你的朋友。你似乎已经有了这个想法,但没有尽可能多地使用它。如果你想制作通用方法来设置不同对象的值,那么 classes 有 overriden/overloaded 方法来为你完成工作。在下面的示例中更容易看到解释:
class TypeA {
int genericAttribute;
setAttributes(int genericAttribute){
this.genericAttribute = genericAttribute;
}
}
class TypeB {
int genericAttribute;
setAttributes(int genericAttribute){
this.genericAttribute = genericAttribute;
}
}
class TypeA1 extends TypeA {
int specificAttribute;
setAttributes(int genericAttribute, int specificAttribute){
setAttributes(genericAttribute);
this.specificAttribute = specificAttribute;
}
}
class TypeB1 extends TypeB {
int specificAttribute;
setAttributes(int genericAttribute, int specificAttribute){
setAttributes(genericAttribute);
this.specificAttribute = specificAttribute;
}
}
继续这个模式,你会得到你想要的,甚至不用尝试。
是否可以在 Java 中混合组合和继承?拳头我有一些通用的类是一个HAS-A(或HAS-MANY)关系(组合)。
通用 类:
Structure、TypeA、TypeB、TypeC等,其中Structure与TypeA、TypeB、TypeC是HAS-A关系。
但是后来我也有几组sub类继承自泛型类(继承)并且处于相同的关系
套子类:
第 1 组:
Structure1、TypeA1、TypeB1、TypeC1等,其中Structure1与TypeA1、TypeB1、TypeC1是同一个HAS-A关系,就像泛型类.
并且:Structure1 extends Structure,TypeA1 extends TypeA,...,TypeC1 extends TypeC,等等
...直到第 X 组:
StructureX、TypeAX、TypeBX、TypeCX 等
每个特殊结构都有一个特定的 sub-TypeA、sub-TypeB 和 sub-TypeC 等。通用 类 定义了一些代码(属性和方法),我希望在处理特殊结构时重用这些代码。 下面的代码可以很好地解释我面临的问题。 (我不知道这是否可以通过 Java "generics" 以某种方式解决,但我认为不能。)
/***********************************************************************************************
/ Generic Structure of Structure-Class with Instances of Generic other classes (Composition)
/***********************************************************************************************/
class Structure {
// Substructures
TypeA instanceA;
TypeB instanceB;
// Defining many methods using the instances of other generic classes like TypeA
void setGenericAttributeOfA(int value) {
instanceA.genericAttribute = value;
}
void setGenericAttributeOfB(int value) {
instanceB.genericAttribute = value;
}
}
class TypeA {
int genericAttribute;
}
class TypeB {
int genericAttribute;
}
/***********************************************************************************************
/ Specific implementation of a Structure-Class with specific implementation of the other classes (Inheritance)
/***********************************************************************************************/
// In the specific implementations I want to use the generic methods, because I do not want to
// rewrite the code for each and every specific implementation. But they should
class Structure1 extends Structure {
// This will create an additional attribute instanceA of specific TypeA1, so I will end up with two instances:
// (1) TypeA super.instanceA and (2) TypeA1 this.instanceA. But what I would like is to have only
// one instanceA of type TypeA1 that can also be used by the global methods of the generic Structure.
TypeA1 instanceA;
Structure1() {
// This creates an instance of type TypeA1, but it cannot be used in the generic methods
// because it is hold in a separate "local" variable that is not known to the generic Structure methods
instanceA = new TypeA1();
// This creates an instance of type TypeB1, but it cannot access the "local" specific attributes,
// because it is hold in a varable which is statically types as TypeB
instanceB = new TypeB1();
}
void specificMethod() {
setGenericAttributeOfA(42); // would fail, because instanceA of type generic TypeA is null
instanceA.specificAttribute = 13; // works only for "local" specific attributes
setGenericAttributeOfB(42); // works only for generic attributes
instanceB.specificAttribute = 13; // would fail, because instanceB is statically typed as generic TypeB which does not have this attribute
((TypeB1)instanceB).specificAttribute = 13; // works but is an ugly work-around and over-complicated if to be used many times
}
}
class TypeA1 extends TypeA {
int specificAttribute;
}
class TypeB1 extends TypeB {
int specificAttribute;
}
也许Generics可以帮忙?
声明 Structure
为通用:
class Structure<T1 extends TypeA, T2 extends TypeB, T3 extends TypeC> {
T1 instanceA;
T2 instanceB;
T3 instanceC;
}
并且您的特定结构将通过指定类型参数从泛型 Structure
继承:
class Structure1 extends Structure<TypeA1, TypeB1, TypeC1> {
// here instanceA will be of type TypeA1, instanceB will be TypeB1 etc.
}
您的类型层次结构似乎不必要地复杂。围绕数据实现继承通常具有挑战性,这个场景就是一个典型的例子。
您可以考虑重新设计类型的要点:
Type
和TypeB
是相同的,至少就 post 而言是这样。除非这些 class 中的每一个都有特定的行为,否则您可以让它们合并:// Replacement for TypeA and TypeB class Type { int genericAttribute; }
如果它们有特定的行为,您可以制作
Type
接口并考虑切换到 getter 和 setter 而不是字段(无论如何这是一个更好的主意)之后,
TypeA1
和TypeB1
可以扩展同一个父级,Type
:class TypeA1 extends Type { int specificAttribute; } class TypeB1 extends Type { int specificAttribute; }
关于
Structure
class:你只需要这个 class 因为你想实现 "generic" 与TypeA
和TypeB
相关的行为。应该不再需要这种区别了,因为这两个已经合并到Type
,所以你可以省去这个 class,留下数据来处理。并且数据可以移动到Structure1
(不需要为这些字段设置一个公共的、单独的位置,因为Structure1
无论如何都有两种具体类型)://this doesn't need a parent any more class Structure1 { TypeA1 instanceA; TypeB1 instanceB; Structure1() { instanceA = new TypeA1(); instanceB = new TypeB1(); } //This doesn't have to be implemented like this //I kept it to show the relation to your original //design. I would simply add //setGenericAttribute(int) to Type void setGenericAttribute(Type type, int value) { type.genericAttribute = value; } void specificMethod() { setGenericAttribute(instanceA, 42); instanceA.specificAttribute = 13; setGenericAttribute(instanceB, 42); instanceB.specificAttribute = 13; } }
TL;DR 在你的类型上使用方法转发,如果这确实有效,因为事情太复杂了,那么查找 SOLID 原则并使用设计模式来制作你的类型和 class紧随其后。
- 为每种类型添加 getter 和 setter,并且永远不要直接访问字段。如果您打算直接访问字段,请使用内部 class。使用 getter 和 setter,您可以拥有一个 infoObject,它可以携带可以传递给您想要的特定字段的值。或者你可以传入一个数据结构,或者你使用可变参数。无论哪种方式,你都有灵活性。
- 我不知道你是在尝试处理结构设计问题还是行为设计问题,这就是你遇到问题的原因。 查找 SOLID 原则。 您的
Structure
class 试图达到两个目的。您正在尝试创建一个负责创建和包含对象的数据对象,同时还尝试为对象处理数据。 您基本上需要选择两种设计模式来处理您的意图。我建议使用 Bridge and Builder 模式。 创建一个构建 Type 对象的构建器 class,然后使结构 class 仅包含顶部 class 的字段。然后结构 class 不必访问类型特定的方法或字段。构建器会,所以你需要考虑为不同类型制作构建器的最佳 SOLID 方法。您可能需要为每种类型或每个 class 构建器,具体取决于它的复杂程度,但如果您有 getter 和 setter,那也不会太糟糕。此外,您可能想考虑将工厂或抽象工厂与构建器一起使用,以便工厂确定对象的类型(以及 class child/parent 的类型),构建器将利用该信息构建一个该特定 class 的对象,其中填充了所有特定字段。 方法转发是你的朋友。你似乎已经有了这个想法,但没有尽可能多地使用它。如果你想制作通用方法来设置不同对象的值,那么 classes 有 overriden/overloaded 方法来为你完成工作。在下面的示例中更容易看到解释:
class TypeA { int genericAttribute; setAttributes(int genericAttribute){ this.genericAttribute = genericAttribute; } } class TypeB { int genericAttribute; setAttributes(int genericAttribute){ this.genericAttribute = genericAttribute; } } class TypeA1 extends TypeA { int specificAttribute; setAttributes(int genericAttribute, int specificAttribute){ setAttributes(genericAttribute); this.specificAttribute = specificAttribute; } } class TypeB1 extends TypeB { int specificAttribute; setAttributes(int genericAttribute, int specificAttribute){ setAttributes(genericAttribute); this.specificAttribute = specificAttribute; } }
继续这个模式,你会得到你想要的,甚至不用尝试。