I have 2 sets of 2 classes where each pair has a super/sub-class relationship, and the orthogonal pair has a dependency relationship. What I am trying to determine is what to do with the constructors and/or bodies of the properties to keep the model as simple as possible with minimal data duplication.
Here's the structure in code:
public class Base1 {
public List<Base2> MyBase2Things { get; set; }
// Do things with Base2 objects
}
public class Sub1 : Base1 {
public List<Sub2> MySub2Things { get; set; }
// Do things with Sub2 objects and also with Base2 objects
}
public class Base2 {
public Base1 MyBase1 { get; set; }
// Do things with the Base1 object
}
public class Sub2 : Base2 {
public Sub1 MySub1 { get; set; }
// Do things with the Sub1 object
}
I have considered overriding the base properties in the sub-classes, but that doesn't fit very cleanly because the properties in the sub-classes don't have the same signature and so I would have to add properties.
I have also considered setting the base property in the sub-class constructor and set
methods, but there is no way for the sub-class property to be updated if the base-class's property is updated.
What other options are there, and which is the cleanest (and why)?
Note: The above code is greatly simplified to illustrate the problem. There are additional properties and methods on the real classes, but this subset is the essence of the trouble I'm having.
I agree with Yaur that generics may help. As far as your options and keeping the model simple as possible - this probably depends on the specifics like the responsibilities of your 4 classes.
Let's say you're dealing with parent/child relationships of various vehicles & vehicle parts.
public class ItemParent { // formerly Base1
public List<ItemChild> MyChildren {get; set;}
}
public class ItemChild { // formerly Base2
public ItemParent MyParent {get; set;}
}
public class Car : ItemParent { // formerly Sub1
public List<CarPart> MyParts {get; set;}
}
public class CarPart : ItemChild { // formerly Sub2
public Car ParentCar {get; set;}
}
Of course, Cars should specifically know about CarPart, not ItemChild. So you fall back on generics here.
public class ItemParent<T> where T : ItemChild {
public List<T> MyChildren {get; set;}
}
public class ItemChild<T> where T : ItemParent {
public T MyParent {get; set;}
}
public class Car : ItemParent<CarPart> {}
public class CarPart : ItemChild<Car> {}
public class Truck : ItemParent<TruckPart> {}
public class TruckPart : ItemChild<Truck> {}
You can call subclass.MyChildren[] just fine, or make a MyParts property which delegates to MyChildren.
In this example, I think the model is pretty simple due to the fact that the parent/child metaphor is pretty easy to grok. Plus, if you add Truck-TruckParts (or Household-Resident, Shape-Line, etc.) you're not really increasing the complexity.
An alternative here would be to move the parent/child "responsibility" to a collection object (possibly custom), like so:
public class ParentChildCollection<TParent, TChild> {}
public class Car {
private ParentChildCollection<Car, CarPart> PartHierarchy;
public List<CarPart> MyParts {get { return PartHierarchy.GetMyChildren(this); } }
}
public class CarPart {
private ParentChildCollection<Car, CarPart> PartHierarcy;
public Car ParentCar {get { return PartHierarchy.GetMyParent(this); }}
}
The downside here is that, while clean, Truck and Car might not share a lot of code (if that's what you were wanting).
public class Car { // formerly Base1
public List<CarPart> MyParts {get; set;}
}
public class CarPart { // formerly Base2
public Car MyParent {get; set;}
}
public class Truck : Car { // formerly Sub1
public List<TruckPart> MyParts {get; set;}
}
public class TruckPart : CarPart { // formerly Sub2
public Truck MyParent {get; set;}
}
In this case, Truck and Car do share more code. But this starts running into signature problems that aren't easily solved even with generics. Here, I'd consider making the base class more generic (Vehicle-VehiclePart). Or consider refactoring this second scenario into the first scenario. Or use the collection for parent/child management and the inheritance stictly for Car-Truck code consolidation.
At any rate, I'm not really sure that either scenario matches your case. At least some factor are based on how you have (and how you can) arrange your relationships.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With