2

Is it possible to mix composition and inheritance in Java? Fist I have some generic classes is a HAS-A (or HAS-MANY) relationship (Composition).

Generic classes:

Structure, TypeA, TypeB, TypeC, etc., where Structure is in a HAS-A relationship with TypeA, TypeB and TypeC.

But then I also have several sets of subclasses which inherit from the generic classes (Inheritance) and are in the same relationship.

Sets of subclasses:

Set 1:

Structure1, TypeA1, TypeB1, TypeC1, etc., where Structure1 is in the same HAS-A relationship with TypeA1, TypeB1 and TypeC1, just like the generic classes.

And: Structure1 extends Structure, TypeA1 extends TypeA, ..., TypeC1 extends TypeC, etc.

... until Set X:

StructureX, TypeAX, TypeBX, TypeCX, etc.

Each special structure has exactly ONE specific sub-TypeA, sub-TypeB and sub-TypeC, etc. The generic classes define some code (attributes and methods) which I would like ot reuse when dealing with special structures. The problems I am facing are best explained by the code below. (I do not know if this can somehow be solved by Java "generics" but I think not.)

/***********************************************************************************************
/ 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;
}
mimi
  • 31
  • 6
  • In `Structure1` your `instanceA` variable is hiding the parent class's `instanceA` variable. Just don't declare that field in the subclass. As long as the corresponding field in the parent class (`Structure`) isn't declared `private`, the subclass will have access to it. – mypetlion Apr 26 '18 at 16:49
  • That is what I did with instanceB. (It is not declared in Structure1.) But then the problem is that I cannot use it as instance of TypeB1 with a lot of additional attributes and methods. (Only if I apply this ugly casting "((TypeB1)instanceB" in each and every use.) – mimi Apr 27 '18 at 17:18

3 Answers3

1

Maybe Generics can help?

Declare Structure as generic:

class Structure<T1 extends TypeA, T2 extends TypeB, T3 extends TypeC> {
    T1 instanceA;
    T2 instanceB;
    T3 instanceC;
}

And your specific structures will just inherit from the generic Structure by specifying type arguments:

class Structure1 extends Structure<TypeA1, TypeB1, TypeC1> {
    // here instanceA will be of type TypeA1, instanceB will be TypeB1 etc.
}
Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • I finally used java generics, although it is more complicated in my real project, because Structure has Arrays of TypeA, TypeB etc, and TypeA has an Array of TypeB and vice versa. All the classes hold arrays of the other classes. And I want to reuse the code of the general structure, which is common to all special structures, but the general structure does not know the special classes. Difficult to explain ... – mimi Apr 30 '18 at 13:36
1

TL;DR Use method forwarding on your types and if that does work because things are too complex then look up SOLID principles and use design patterns to make your types and classes follow that.

  1. Add getters and setters to each type and never access fields directly. If you intend to access the fields directly use a inner class. With getters and setters you could have an infoObject that can carry values that can be passed on to the specific field that you want. Or you could pass in a data structure, or you use varargs. Either way you have flexibility.
  2. I can't tell if you're trying to handle structural design issues or behavior design issues, which is why you have are having issues. Look up SOLID principles. Your Structure class is trying to serve two purposes. You're trying to make a data object that is responsible for creating and containing objects, while also trying to process the data for the objects. You basically need to pick two design patterns to handle your intention. I would suggest the Bridge and Builder pattern. Make a builder class that builds the Type objects and then make your structural class only have fields of the top class. Then the structural class does not have to access type specific methods or fields. The builder will though, so you need to think about the best SOLID way of making a builder for the different types. You might need a builder for each type or each class depending on how complicated it is but if you have getters and setters that won't be too bad. Also you might want to think about using a factory or abstract factory with the builder so that the factory determines which type (and what class child/parent) the object will be and the builder takes that information to build an object of that specific class with all the specific fields populated.
  3. Method forwarding is your friend. You seem to have already had that idea but it wasn't used as much as you could. If you wanted to make general method that sets the values on different objects, than make the classes have overriden/overloaded methods that do the work for you. It's easier to see explain in the example below:

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

Continue this pattern and you'll have what you want without even trying.

Thatalent
  • 404
  • 2
  • 8
0

Your type hierarchy seems unnecessarily complex. It's typically challenging to implement inheritance around data, and this scenario is a typical example.

Points you can consider to redesign your types:

  1. Type and TypeB are identical, at least as far as the post is concerned. Unless there's specific behavior to each of these classes, you can make them coalesce:

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

    If they have specific behavior, you can make Type an interface and consider switching to getters and setters instead of a field (which is a better idea any way)

  2. Following that, TypeA1 and TypeB1 can extend the same parent, Type:

    class TypeA1 extends Type {
        int specificAttribute;
    }
    class TypeB1 extends Type {
        int specificAttribute;
    }
    
  3. Regarding the Structure class: you only needed this class because you wanted to implement "generic" behavior related to TypeA and TypeB. This distinction shouldn't be needed anymore as these two have been merged into Type, so you can dispense with this class, to be left with data to deal with. And data can move to Structure1 (there would be no need for a common, separate place for these fields, because Structure1 has both concrete types anyway):

    //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;
        }
    }
    
ernest_k
  • 44,416
  • 5
  • 53
  • 99
  • 1
    Thanks for this long answer. I am sorry if I did not make it clear that the provided code is highly simplified. TypeA and TypeB are completely different classes. They cannot be derived from the same parent. It is hard to find a real-world example. (Maybe this is why there is no appropriate software representation.) But think of spreadsheets with rows, tables, cells for different use-cases where they have some generic attribute and methods, but for each specific purpose they all have also specific attributes and methods on top. – mimi Apr 27 '18 at 17:28