6

这可能是一个初学者的问题,但是否有一种标准方法可以将 Wheel 属性的副本重构到抽象类中,但仍保持对 Part 类型的显式转换。假设我们必须防止将 FastCarWheel 放在 SlowCar 上,并且有很多属性就像这个一样。

abstract class Car {}

class FastCar : Car
{
    public FastCarWheel Wheel { get; set; }
} 

class SlowCar : Car
{
    public SlowCarWheel Wheel { get; set; }
} 

abstract class WheelPart {}

class FastCarWheel: WheelPart {}

class SlowCarWheel: WheelPart {}

在这种情况下,只允许这种类型的复制是否很常见?我正在考虑使用泛型,但似乎我正在解决这个问题,并且对于每个以这种方式运行的附加属性来说,情况会变得更糟。

abstract class Car <P>
    where P : Part
{
    protected abstract P Wheel { get; set; }
}

谢谢

4

5 回答 5

1

我认为使用FastorSlow 策略可以帮助为给定的汽车类型放置正确的车轮(其中CarWheel都依赖于策略,并且Car对象具有例如车轮的私有聚合)。

于 2009-04-23T18:18:07.123 回答
1

此解决方案不是多态的,但如果您需要基类级别的可见性,它可能是您唯一的选择:

abstract class Car
{
    private CarWheel wheel;
    public CarWheel Wheel
    {
        get { return wheel; }
        protected set { wheel = value; }
    }
}

class FastCar : Car
{
    public new FastCarWheel Wheel
    {
        get { return base.Wheel as FastCarWheel; }
        set { base.Wheel = value; }
    }
}

class SlowCar : Car
{
    public new SlowCarWheel Wheel
    {
        get { return base.Wheel as SlowCarWheel ; }
        set { base.Wheel = value; }
    }
}

您可能想评估您的基类是否做得太多。可以通过将您的课程分成许多较小的课程来解决您的问题。另一方面,有时这是不可避免的。

于 2009-04-23T18:18:53.487 回答
1

我会创建一个 ICar 然后以这种方式定义你的 Cars,而不是一个抽象类

interface ICar
{
   IWheel Wheel {get; set;}
}

class FastCar: ICar
{
   FastWheel fastWheel;
   IWheel Wheel
   {
      get { return fastWheel; }
      set
      {
          if (value is FastWheel) fastWheel = (FastWheel)value;
      }    
   }         
}

class SlowCar: ICar
{
   SlowWheel slowWheel;
   IWheel Wheel
   {
      get { return slowWheel; }
      set
      {
          if (value is SlowWheel ) slowWheel = (SlowWheel )value;
      }    
   } 
}

class FastWheel: IWheel {}
class SlowWheel: IWheel {}
于 2009-04-23T18:19:31.363 回答
1

由于您的目标似乎是允许客户端代码将属性作为 WheelPart 取回,但仅将其设置为特定的子类,您有几个选项。虽然我担心他们都不是很干净。

首先,如果设置了错误的类型,您可能会引发运行时错误:

    public abstract class Car
    {
        public abstract WheelPart Wheel { get; set; }
    }

    public class FastCar : Car
    {
        private FastWheel _wheel;
        public override WheelPart Wheel
        {
            get { return _wheel; }
            set
            {
                if (!(value is FastWheel))
                {
                    throw new ArgumentException("Supplied wheel must be Fast");
                }
                _wheel = (FastWheel)value;
            }
        }
    }

但我不会这样做,因为客户端代码非常不清楚任何其他类型的轮子会抛出异常,并且他们不会得到编译器反馈。

否则,您可以将属性的 Getter 和 Setter 分开,以便非常清楚所需的类型:

    public abstract class Car
    {
        public abstract WheelPart Wheel { get; }
    }

    public class FastCar : Car
    {
        private FastWheel _wheel;
        public override WheelPart Wheel
        {
            get { return _wheel; }
        }

        public void SetWheel(FastWheel wheel)
        {
            _wheel = wheel;
        }
    }

如果您绝对必须将 getter 公开为基础 WheelPart 类,这对客户来说更清楚,恕我直言,这是一个更好的解决方案。

于 2009-04-23T18:32:51.503 回答
0

定义一个轮子接口(IWheel):

public interface IWheel
{
}

实现 FastCarWheel 和 SlowCarWheel 的接口,例如

public class FastCarWheel : IWheel
{
}

现在你的抽象类变成了:

abstract class Car 
{
 public IWheel Wheel { get; set; }
}

然后 Car 的子类可以自由使用他们选择的任何 Wheel 实现:

FastCar fastCar = new FastCar();
fastCar.Wheel = new FastCarWheel();
于 2009-04-23T18:14:50.330 回答