机械手厂

时间:2014-09-29 12:14:42

标签: c# .net wcf generics inheritance

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:有更好的方法吗?

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接口,以便我们可以“飞行”错误,鸟类和轰炸机 - 这些都是不相关的类。

但是CarTruck是相关的,所以通过继承和多态的基本机制,在处理Car子类时不需要任意接口。

  

假设这些类是纯数据载体

类的基本OO概念是数据+其方法Car及其衍生物的想法需要充实。这将告知汽车工厂的设计。

我希望很多Car属性都是他们自己的类。如果车轮组件与建议的一样复杂,那么可能应该是一个类。

  

B或多或少是一个标记

Car只是一个标记 - 基本上没什么?你怎么能建造什么?通过构建任何东西,我认为这是设计的目标。难怪你正在尝试构建像ICarWheelSetter这样的粒度接口。但这些都是错误的。想象一下,当你为Car及其衍生物中的每个属性执行此操作时,代码会是什么样子。在我看来,这是一个未充分定义的领域模型的症状。如图所示,我不知道Car及其衍生物是什么。因为我们没有任何具体的工作,任何子类可能都是任何东西,代码似乎支持这种模糊的想法。

  

有没有办法确保混凝土BM(即C1M)始终操纵混凝土B(在这种情况下为C1)?或者这需要另一种模式吗?

我想起了visitor design pattern。我想Garage修正CarGarage知道如何操纵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汇编过程,因此汇编调用方法 - 按照正确的顺序完成。