如何在C#中干净地设计并行继承结构?

cde*_*zaq 5 c# inheritance subclass

我有2组2个类,其中每对具有超/子类关系,并且正交对具有依赖关系.我想要确定的是如何处理属性的构造函数和/或主体,以尽可能简化模型,同时尽量减少数据重复.

这是代码中的结构:

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
}
Run Code Online (Sandbox Code Playgroud)

我已经考虑过覆盖子类中的基本属性,但这不太合适,因为子类中的属性没有相同的签名,因此我必须添加属性.

我还考虑在子类构造函数和set方法中设置base属性,但是如果更新了基类的属性,则无法更新子类属性.

还有哪些其他选择,哪些是最干净的(以及为什么)?

注意:上面的代码大大简化,以说明问题.真实类上还有其他属性和方法,但这个子集是我遇到的麻烦的本质.

Mat*_*att 2

我同意 Yaur 的观点,即仿制药可能会有所帮助。至于您的选择并尽可能保持模型简单 - 这可能取决于具体细节,例如您的 4 个类的职责。

假设您正在处理各种车辆和车辆零件的父/子关系。

场景一:继承关系带来正交能力。

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;}
}
Run Code Online (Sandbox Code Playgroud)

当然,Cars 应该特别了解 CarPart,而不是 ItemChild。所以你在这里求助于泛型。

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> {}
Run Code Online (Sandbox Code Playgroud)

您可以调用 subclass.MyChildren[] 就可以了,或者创建一个委托给 MyChildren 的 MyParts 属性。

在这个例子中,我认为模型非常简单,因为父/子隐喻很容易理解。另外,如果您添加 Truck-TruckParts(或 Household-Resident、Shape-Line 等),您并没有真正增加复杂性。

这里的另一种选择是将父/子“责任”移至集合对象(可能是自定义的),如下所示:

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); }}
}
Run Code Online (Sandbox Code Playgroud)

这里的缺点是,虽然很干净,但卡车和汽车可能不会共享很多代码(如果这就是您想要的)。

场景 2:继承关系是专门针对并行项目的。

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;}
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,卡车和汽车确实共享更多代码。但这开始遇到签名问题,即使使用泛型也不容易解决。在这里,我会考虑使基类更加通用(Vehicle-VehiclePart)。或者考虑将第二个场景重构为第一个场景。或者使用集合进行父/子管理,并严格使用继承来进行 Car-Truck 代码合并。

无论如何,我不太确定这两种情况是否符合您的情况。至少有一些因素取决于你如何(以及如何)安排你的关系。