访问从接口契约中分类的派生属性

时间:2014-07-21 20:59:26

标签: c# oop interface

我正在创建一个类库,用于创建具有特定功能的其他应用程序。库应该实现所有具体功能,实现应用程序将向类添加特定的业务规则。通常,这是一些对象的简单表示:

在课程库中:

interface IWheel
{
   int Radius { get; set; }
   string Color { get; set; }
}

abstract class Wheel : IWheel
{
   int Radius { get; set; }
   string Color { get; set; } 
}

interface ICar 
{
   string Color { get; set; }
   List<IWheel> Wheels { get; set; }
}

abstract class Car : ICar 
{
   string Color { get; set; }
   List<IWheel> Wheels { get; set; }

   public Car()
   {
      List<IWheel> Wheels = new List<IWheel>();
   }
}

实施应用程序业务逻辑:

class SpecialWheel : Wheel 
{
    int SpecialWheelProperty { get; set; }
}

class SpecialCar : Car
{
   string SpecialCarProperty { get; set; }
}

在实现应用程序实例化时:

SpecialWheel wheel1 = new SpecialWheel { SpecialWheelProperty = 6 };
SpecialWheel wheel2 = new SpecialWheel { SpecialWheelProperty = 6 };
SpecialWheel wheel3 = new SpecialWheel { SpecialWheelProperty = 8 };
SpecialWheel wheel4 = new SpecialWheel { SpecialWheelProperty = 8 };

SpecialCar car = new SpecialCar();
car.Wheels.Add(wheel1);
car.Wheels.Add(wheel2);
car.Wheels.Add(wheel3);
car.Wheels.Add(wheel4);

到目前为止一切都很好,直到我尝试做类似的事情:

// Cant do this as "SpecialWheelProperty" is not in the Interface contract
int wheelSpecialProperty = car.Wheels.First().SpecialWheelProperty; 

我当然可以添加&#34; SpecialWheelProperty&#34;到IWheel接口并使其成为Wheel类的抽象属性,但这将破坏我在派生类中实现业务逻辑的最终目标。

我脑子里浮现了一些想法(也许是泛型),但是,在这种情况下,最好的方法是什么,以及这种方法的一个例子?

3 个答案:

答案 0 :(得分:1)

问题是您的代码表示SpecialCarSpecialWheel类之间没有关系,但期望SpecialCar的接口公开SpecialWheel个实例。您实际添加所有SpecialWheel个实例的事实完全是巧合。

这似乎是泛型的任务,基类接受实现IWheel的类型参数。

abstract class Car<TWheel> : ICar where TWheel : IWheel
{
   string Color { get; set; }
   ICollection<TWheel> Wheels { get; set; }

   public Car()
   {
      Wheels = new List<TWheel>();
   }
}

class SpecialCar : Car<SpecialWheel> {
    // Whatever
}

现在你仍然可以做到这一点而不会失去任何类型的安全性:

int swp = car.Wheels.First().SpecialWheelProperty;

需要注意的是:虽然这种技术可以使您想要的代码成为可能,但如果在深层次结构中使用它,它很快就会失控。请谨慎使用。

答案 1 :(得分:0)

据我所知     SpecialWheel

是否存在业务逻辑,因此为了获得特定属性,似乎是正常的:

int wheelSpecialProperty = (car.Wheels.First() as SpecialWheel).SpecialWheelProperty; 

一个问题:为什么要在中创建一个构造函数     汽车 既然它是抽象的?

答案 2 :(得分:0)

我认为,很难以一种精确的方式回答这个问题。问题是要了解你的系统。在这里,你只有我称之为&#34;技术&#34;。在这种情况下,继承和多态。但是当你构建系统时,它通常不止于此。如果您愿意,您可以拥有一个框架,管道,所有操作都在接口级别完成。工厂。然后,在专业领域,您可以使用以下特定于业务的代码:

class CarFactory 
{ 
    public static ICar BuildCar(int kind); 
    if (int == 0)
        return new RegularCar();
    else 
        return new SpecialCar();
}

所以在你的&#34; Special&#34;代码可以添加特殊属性值

SpecialCar sc = (SpecialCar)CarFactory.BuildCar(1); // notice casting
sc.SpecialProperty = "special value";

因此,只有特定的客户/消费者才会知道特殊属性。您的申请将与

一起运作
ICar, IWheel, // etc

例如,当您获得普通汽车时,您的客户不知道1,只有0。

RegularCar rc = (RegularCar)CarFactory.BuildCar(0); // notice casting

但是调用&#34; AddWheels&#34;不知道它是什么车,并宣布为

CarBuilderWheelHandler.AddWheels(ICar c, List<IWheel> w)

CarBuilderWheelHandler可能需要安装轮胎,给每个轮胎充气和平衡。但是你的特殊车轮可能安装了轮胎压力监测系统而不是常规阀门。在这种情况下,您的专用车有一个监控TPMS的设备,并知道如何处理特殊的车轮属性。但是当它从处理程序流向处理程序时,那些处理程序并不知道&#34;特殊的&#34;的东西。 Hadlers使用接口。

void AddWheels(ICar c, List<IWheel> w)
{ 
    MountRubber(w);
    Inflate(w);
    Balance(w);
    c.Wheels = w;
}

然后在特殊车内某处,它知道如何监控压力

void Timer_Tick(...)
{
    foreach(SpecialWheel w in _wheels)
    {
        if w.Pressure < _pressureSetByDriver //'Pressure' is not part of IWheel
            SendPressureWarningToDashboard();
    }
}

这是一个非常抽象的例子,可能只对你有用,了解OOP中抽象对象的目的是什么。

我相信您的问题可以有很多答案,而且我们没有确切的工作环境