在Java中混合组合和继承

时间:2018-04-26 16:44:28

标签: java inheritance object-composition

是否可以在Java中混合使用组合和继承?拳头我有一些泛型类是HAS-A(或HAS-MANY)关系(作文)。

通用类:

结构,TypeA,TypeB,TypeC等,其中Structure与TypeA,TypeB和TypeC处于HAS-A关系。

但是后来我也有几组继承自泛型类(继承)的子类,它们处于相同的关系中。

子类集:

设置1:

Structure1,TypeA1,TypeB1,TypeC1等,其中Structure1与TypeA1,TypeB1和TypeC1处于相同的HAS-A关系,就像通用类一样。

并且:Structure1扩展了Structure,TypeA1扩展了TypeA,...,TypeC1扩展了TypeC等等。

......直到设置X:

StructureX,TypeAX,TypeBX,TypeCX等。

每个特殊结构都有一个特定的子类型A,子类型B和子类型C等。泛型类定义了一些代码(属性和方法),我想在处理特殊结构时不再使用它们。 我面临的问题最好用以下代码解释。 (我不知道这是否能以某种方式通过Java和#34; generics&#34来解决;但我认为不是。)

/***********************************************************************************************
/ 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;
}

3 个答案:

答案 0 :(得分:0)

也许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.
}

答案 1 :(得分:0)

您的类型层次结构似乎不必要地复杂。实现数据继承通常具有挑战性,这种情况就是一个典型的例子。

您可以考虑重新设计类型的要点:

  1. TypeTypeB相同,至少就帖子而言。除非每个类都有特定的行为,否则可以使它们合并:

    // Replacement for TypeA and TypeB
    class Type {
        int genericAttribute;
    }
    

    如果他们有特定的行为,你可以使Type成为一个界面,并考虑切换到getter和setter而不是字段(这是一个更好的主意)

  2. 在此之后,TypeA1TypeB1可以扩展同一个父级Type

    class TypeA1 extends Type {
        int specificAttribute;
    }
    class TypeB1 extends Type {
        int specificAttribute;
    }
    
  3. 关于 Structure 类:您只需要此类,因为您希望实现&#34; generic&#34;与TypeATypeB相关的行为。不应再需要这种区别,因为这两者已经合并到Type中,所以你可以省去这个类,留下数据来处理。数据可以移到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;
        }
    }
    

答案 2 :(得分:0)

TL; DR 在您的类型上使用方法转发,如果确实有效,因为事情过于复杂,那么请查看SOLID原则并使用设计模式使您的类型和类遵循该原则。

  1. 为每种类型添加getter和setter,并且永远不会直接访问字段。如果您打算直接访问字段,请使用内部类。使用getter和setter,你可以拥有一个infoObject,它可以携带可以传递给你想要的特定字段的值。或者您可以传入数据结构,或者使用varargs。无论哪种方式,你都有灵活性。
  2. 我无法判断您是否正在尝试处理结构设计问题或行为设计问题,这就是您遇到问题的原因。 查找SOLID原则。您的Structure课程正在努力实现两个目的。您正在尝试创建一个负责创建和包含对象的数据对象,同时还尝试处理对象的数据。 您基本上需要选择两种设计模式来处理您的意图。我建议使用Bridge和Builder模式。创建一个构建Type对象的构建器类,然后使结构类只包含顶级类的字段。然后结构类不必访问特定于类型的方法或字段。但是构建器会,因此您需要考虑为不同类型构建构建器的最佳SOLID方法。您可能需要为每种类型或每个类别构建一个构建器,具体取决于它的复杂程度,但是如果您的getter和setter不会太糟糕。您还可以考虑将工厂或抽象工厂与构建器一起使用,以便工厂确定对象将使用哪种类型(以及子类/父类),构建器将使用该信息构建该特定类的对象。填写了所有特定字段。
  3. 方法转发是您的朋友。您似乎已经有了这个想法,但它并没有尽可能多地使用。如果要创建在不同对象上设置值的通用方法,那么使类具有覆盖/重载方法,为您完成工作。在下面的示例中更容易看到解释:

    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;
        }
    }
    
  4. 继续这种模式,即使没有尝试,你也会得到你想要的东西。