2

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

通用类:

Structure、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 等。

每个特殊结构都有一个特定的 sub-TypeA、sub-TypeB 和 sub-TypeC 等。泛型类定义了一些我希望在处理时重用的代码(属性和方法)具有特殊结构。下面的代码最好地解释了我面临的问题。(我不知道这是否可以通过 Java“泛型”以某种方式解决,但我认为不能。)

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

3 回答 3

1

也许泛型可以提供帮助?

声明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.
}
于 2018-04-26T16:49:41.603 回答
1

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

  1. 为每种类型添加 getter 和 setter,并且永远不要直接访问字段。如果您打算直接访问这些字段,请使用内部类。使用 getter 和 setter,您可以拥有一个 infoObject,它可以携带可以传递到您想要的特定字段的值。或者你可以传入一个数据结构,或者你使用可变参数。无论哪种方式,你都有灵活性。
  2. 我不知道您是在尝试处理结构设计问题还是行为设计​​问题,这就是您遇到问题的原因。查找 SOLID 原则。你的Structure班级试图达到两个目的。您正在尝试创建一个负责创建和包含对象的数据对象,同时还尝试处理对象的数据。您基本上需要选择两种设计模式来处理您的意图。我建议使用 Bridge and 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;
        }
    }
    

继续这种模式,你会得到你想要的,甚至不用尝试。

于 2018-04-27T17:06:10.020 回答
0

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

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

  1. Type并且TypeB是相同的,至少就帖子而言。除非这些类中的每一个都有特定的行为,否则您可以使它们合并:

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

    如果它们有特定的行为,您可以创建Type一个接口并考虑切换到 getter 和 setter 而不是字段(无论如何这是一个更好的主意)

  2. 之后,TypeA1并且TypeB1可以扩展相同的父级,Type

    class TypeA1 extends Type {
        int specificAttribute;
    }
    class TypeB1 extends Type {
        int specificAttribute;
    }
    
  3. 关于Structure课程:您只需要这个课程,因为您想实现与TypeAand相关的“通用”行为TypeB。由于这两个已合并到 中,因此不再需要这种区别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;
        }
    }
    
于 2018-04-26T17:23:32.603 回答