Search code examples
c#oopinheritancecomposition

How to design inheritance for multilevel composition classes


I have to solve a quite tricky problem and I will try my best to explain the problem. I have a complicated object and it has two level composition and somehow I am supposed to define two classes for low level of composition and reflect the new types at higher level. In order to reflect the changes in low composition, I am defining two classes in higher levels as well.

I am using abstract factory approach to create instances of higher level classes. All classes are serializable.

C in below diagram is correspond to higher level classes and A is correspond to low level classes. Object of A classes are composed of objects of level 2 classes and they are composed of object of C classes.

In abstract factory approach, I am trying to deserialize the object and return as parent class. I am getting casting related error. However, I think there is some fundamental problem in design which I am unable to figure out. I know parent object can not be casted as child object.

enter image description here

public class A {
    public virtual Double [] Prop1 { get; set; }
    public virtual Double [] Prop2 { get; set; }
  }


  public class A1 : A {
    public override double[ ] Prop1 {
      get {
        // implementation other than base class
      }

      set {
        // implementation other than base class
      }
    }

  }


  public class A2 : A {
    public override double[ ] Prop2 {
      get {
        // implementation other than base class
      }

      set {
        // implementation other than base class
      }
    }
  }


  public class B {
    public virtual A A_obj { get; set; }
  }


  public class B1 : B {

    public override A A_obj {
      get {
        // want to retun the object of A1
      }

      set {
        // want to handle the object A1
      }
    }
  }


  public class B2 : B {
    public override A A_obj {
      get {
        // want to retun the object of A2
      }

      set {
        // want to handle the object A2
      }
    }
  }


  public class C {
    public virtual B [] B_obj { get; set; }

  }

  public class C1 : C {
    public override B[ ] B_obj {
      get {
        // want to retun the object of B1
      }

      set {
        // want to handle the object B1
      }
    }
  }

  public class C2 : C {
    public override B[ ] B_obj {
      get {
        // want to retun the object of B2
      }

      set {
        // want to handle the object B2
      }
    }
  }

Solution

  • Generics may be the way to go here. From my interpretation of your post, the issue seems to be that B1 can only reference A1 objects, B2 -> A2 and similar for C objects.

    The following idea will get you type safety and eliminate the necessity to cast:

        public abstract class A { };
        public class A1 : A { };
        public class A2 : A { };
    
        public abstract class B<T> where T : A {
            public T A_obj { get; set; }
        };
        public class B1 : B<A1>
        { 
        };
    
        public class B2 : B<A2>
        {
        };
    
        public abstract class C<T, U> where T : B<U> where U : A
        {
            public List<T> B_objs { get; private set; }
    
            public C() {
                B_objs = new List<T>();
            }
        };
    
        public class C1 : C<B1, A1>
        {
        };
    
        public class C2 : C<B2, A2>
        {
        };
    
        public static void Test()
        {
            A1 a1 = new A1();
            B1 b1 = new B1();
            b1.A_obj = a1;
    
            A2 a2 = new A2();
            B2 b2 = new B2();
            b2.A_obj = a2;
    
            // The following line fails: cannot implicitly convert A1 to A2
            //b2.A_obj = a1;
    
            C1 c1 = new C1();
            c1.B_objs.Add(b1);
    
            // The following fails:
            // c1.B_objs.Add(b2);
        }