EDIT4 Gave Truck显示SetNrOfWheels方法的属性是针对特定卡车量身定制的
EDIT3在B - 车辆和C1 - 卡车之间建立连接
EDIT2已删除B上的界面
EDIT1将汽车改为车辆
关于我遇到过多次问题,我有两个问题。我想知道我是否必须使用其他模式,或者是否有人可以指出我在正确/更好的方向。
如果你知道这里描述答案的文章,请告诉我,我会尝试删除这个。
考虑一个抽象基类B(即Vehicle),它由许多子类继承,C1,C2等(即Truck,Motor)假设这些类是纯数据载体,即数据契约,并且包含一些属性。尽管对于故事并非严格必要,但它们使用不带参数的默认构造函数,并且所有属性都是公共的,以及简单的值类型对象。它们可能会也可能不会继承一些预定义的属性,但最重要的是,B或多或少是一个标记,而不是强制执行功能(因为它是一个数据契约)。
示例:
abstract Vehicle {
int NrOfWheels { get; set;}
}
Truck : Vehicle {
bool HasExtraTrailer { get; set; }
}
现在考虑一个名为BM的B操纵器(即VehicleWheelSetter),它是一个抽象基类或一个接口(你决定这里最好的东西;))。它具有(至少是抽象的)功能来操纵B类。假设每个操纵器,即C1M,C2M,(TruckWheelSetter,MotorWheelSetter)继承自BM。重要的是,类型是强制执行的,ergo,C1M只操纵C1类的类。这可以通过BM是通用的来强制执行,例如BM< T>。其中T:B,虽然这是有限的(这将允许XM:BM< B>仍然)
示例:
interface IVehicleWheelSetter<in T> where T : Vehicle {
void SetNrOfWheels(T vehicle)
}
TruckWheelSetter : IVehicleWheelSetter<Truck> {
void SetNrOfWheels(Truck vehicle) {
vehicle.NrOfWheels = 2 * 3;
if (vehicle.HasExtraTrailer) vehicle.NrOfWheels += 2 * 2;
} } }
问题1:有没有办法确保混凝土BM(即C1M)始终操纵混凝土B(在这种情况下为C1)?或者这需要另一种模式吗?
让我们假设一般来说,这将比分配一个数字(显然可以从配置或数据库中检索)复杂得多。我写2 * 3并不是巧合,表明这可能是一个复杂的操作。
假设我知道我在一些必须进行操作的服务中一直得到B类,比如工厂,像这样:
VehicleWheelSetterFactory {
IVehicleWheelSetter<T> CreateVehicleWheelSetter<T>() where T : Vehicle {
// code to create the right selector here
} }
现在,有多种方法可以做到这一点:
if (typeof(T) == typeof(Truck))
return (IVehicleWheelSetter<T>)(new TruckWheelSetter());
throw new NotImplementedException();
或一些更高级的基于反射的选项。
这有一些问题,除了一些&#39;它感觉不对。还存在通用不起作用的情况,即T未知。在这种情况下,参数中的Type可以提供帮助:
object CreateVehicleWheelSetter(Type vehicleType) {
if (vehicleType == typeof(Truck))
return new TruckWheelSetter();
throw new NotImplementedException();
}
但是如何将对象强制转换为IVehicleWheelSetter&lt; T&gt;? T还是未知数!所以,也许接口应该是这样的:
interface ICarWheelSetter
{
void SetNrOfWheels(Vehicle vehicle);
}
但是现在我遇到了原来的问题:我无法保证Vehicle是TruckWheelSetter中的Truck。这也没有这样解决:
interface IVehicleWheelSetter
{
void SetNrOfWheels<T>(T car) where T : Vehicle;
}
问题2:有更好的方法吗?
答案 0 :(得分:0)
不确定我是否得到了您的问题(如果您解析具体实例,T怎么可能是未知的),但无论如何,这不容易:
public class CarWheelSetter
{
public static void SetNrOfWheels<T>(T car) where T : Car
{
WheelSetterFor<T>().SetNrOfWheels(car);
}
private static ICarWheelSetter<T> WheelSetterFor<T>() where T : Car
{
if (typeof(T) == typeof(Truck))
{
return new TruckWheelSetter() as ICarWheelSetter<T>;
}
throw new NotImplementedException();
}
}
答案 1 :(得分:0)
考虑一个抽象基类/接口B
这些不是任意可互换的东西。我希望public class abstract Car
不是一个接口。 interface
- C#关键字特定含义 - 的目的是为不相关的类定义“相同但不同”的行为。例如,我们可能需要一个IFly
接口,以便我们可以“飞行”错误,鸟类和轰炸机 - 这些都是不相关的类。
但是Car
和Truck
是相关的,所以通过继承和多态的基本机制,在处理Car
子类时不需要任意接口。
假设这些类是纯数据载体
类的基本OO概念是数据+其方法。 Car
及其衍生物的想法需要充实。这将告知汽车工厂的设计。
我希望很多Car
属性都是他们自己的类。如果车轮组件与建议的一样复杂,那么可能应该是一个类。
B或多或少是一个标记
Car
只是一个标记 - 基本上没什么?你怎么能建造什么?通过构建任何东西,我认为这是设计的目标。难怪你正在尝试构建像ICarWheelSetter
这样的粒度接口。但这些都是错误的。想象一下,当你为Car
及其衍生物中的每个属性执行此操作时,代码会是什么样子。在我看来,这是一个未充分定义的领域模型的症状。如图所示,我不知道Car
及其衍生物是什么。因为我们没有任何具体的工作,任何子类可能都是任何东西,代码似乎支持这种模糊的想法。
有没有办法确保混凝土BM(即C1M)始终操纵混凝土B(在这种情况下为C1)?或者这需要另一种模式吗?
我想起了visitor design pattern。我想Garage
修正Car
。 Garage
知道如何操纵Car
来修复它。此外,派生的BMWGarage
将知道如何修复BMW Car
子类。
所以我想象一个Garage
继承层次结构,它反映了Car
层次结构。可能不准确:ForeignCarGarage
可能会处理几种不同的Car
类型。
有没有办法确保混凝土BM总是操纵混凝土B?
当然。打电话给工厂并告诉它要开车,然后是那辆车的车库
var myBeamer = CarFactory.Create(carEnum.BMW);
var beamerGarage = GarageFactory.Create (typeof(myBeamer).FullName);
以上表明需要abstract factory。注意工厂有3个“级别”。使用哪个是需要构建的复杂性问题。此外,我们可能会看到builder pattern来协调汽车(或车库)创建中的复杂步骤。
这可能意味着我们为特定的Car
衍生物及其车库创建了一个工厂。 BMWFactory使用BMW零件 - 类似BMWWheelAssembly
。
var BMWFactory = new CarFactory(carEnum.Bmw);
var myBeamer = BMWFactory.Create();
现在CarFactory
可以实现interface
,或者是abstract
类 - 但我认为不是。如果有基础实现,我期望abstract
类。 abstract
类可以template汇编过程,因此汇编调用方法 - 按照正确的顺序完成。