基类A具有基类B的性质,但派生类A1具有派生类B1
本文关键字:基类 派生 B1 A1 | 更新日期: 2023-09-27 18:24:01
我得到了以下真实世界的模式,其中基类BCA
持有基类类型BCB
的公共属性B
。BCA
和BCB
分别有两个派生类——DCA1
和DCA2
、DCB1
和DCB2
。在DCA1
和DCA2
中的每一个中,真实世界中的属性实际上分别为DCB1
和DCB2
类型。
如何最有效地将其转化为代码OOP设计?我是在BCA
中保留B
,还是在DCA1
和DCA2
中分别具体键入?我应该使用仿制药吗?这个设计有什么问题吗?碰巧我在这个项目中已经遇到过几次了,不知怎么的,感觉不对劲;但我想知道我的想法是不是错了。
编辑:我举了一个更具体的例子,使它更清楚。我很抱歉,但我不允许张贴图片在类图上显示它,但它是这样的:
Pet具有PetFood类型的DailyMeal属性。Cat’s DailyMeal属性属于CatFood类型,Dog’s Daily Meal属于DogFood类型。
我希望这能使模式更加清晰。
第2版:这个问题被重新表达为:你如何用OOP术语,特别是C#来建模这样一个真实世界的场景,在这个场景中,你有一辆带发动机的汽车、一辆带电动发动机的电动汽车和一辆带柴油发动机的柴油车等,这样你就可以使用多态性:
Car myCar = myElectricCar;
myCar.Engine = myElectricEngine;
同时确保每种汽车类型都具有正确的发动机类型。我们的目标是根据类、接口和/或泛型或任何需要来建模这个真实世界的场景,并获得OOP的全部好处。
让我们使用以下示例:所有汽车都有发动机,但电动汽车有电动发动机。
你不能用类来设计它,但你可以用协变接口:
interface ICar<out TEngine>
{
TEngine Engine { get; }
}
class Engine { }
class Car : ICar<Engine>
{
private readonly Engine engine;
public Car(Engine engine)
{
this.engine = engine;
}
public Engine Engine { get { return this.engine; } }
}
class ElectricEngine : Engine { }
class ElectricCar : ICar<ElectricEngine>
{
private readonly ElectricEngine engine;
public Car(ElectricEngine engine)
{
this.engine = engine;
}
public ElectricEngine Engine { get { return this.engine; } }
}
但是请注意,ElectricCar并不是从Car继承的。然而,ICar<ElectricEngine>
可分配给ICar<Engine>
,因此这是有效的:
ICar<Engine> myCar = new ElectricCar(new ElectricEngine());
当然,您也可以定义一个非通用接口ICar,它包含与引擎无关的所有属性和方法。
注意,ICar<out TEngine>
是协变的。它也不能是相反的。这意味着Engine属性必须是只读的。
更新
您询问了为什么属性必须是只读的,以及它的可写性是否存在固有的问题。是的,会的。考虑这个场景:
ICar<Engine> myCar = new ElectricCar();
// assume ICar<Engine> has a writabel property Engine of type Engine
myCar.Engine = new DieselEngine();
Engine类型的可写属性必须允许最后一条语句。但在运行时,这当然不能工作,因为myCar恰好是一辆电动汽车,而这些汽车不使用DieselEngines。
我建议你读一下利斯科夫替代原则。
ElectricCar
可以具有类型为ElectricEngine
的可写Engine
属性,其setter不能是ICar<TEngine>
接口的一部分。因此,属性的setter不能是多态的。
使用泛型。使BCA在其属性类型中具有泛型,并将其约束为从BCB:派生的
class BCA<T> where T: BCB
{
public T prop {get; set;}
}