C# 重构成抽象类的基本问题
这可能是一个初学者的问题,但是否有一种标准方法可以将Wheel属性的副本重构到抽象类中,同时仍然保持对零件类型的显式转换。让我们假设我们必须防止FastCarWheel被放在慢车上,并且有许多属性与此类似C# 重构成抽象类的基本问题,c#,inheritance,abstract-class,C#,Inheritance,Abstract Class,这可能是一个初学者的问题,但是否有一种标准方法可以将Wheel属性的副本重构到抽象类中,同时仍然保持对零件类型的显式转换。让我们假设我们必须防止FastCarWheel被放在慢车上,并且有许多属性与此类似 abstract class Car {} class FastCar : Car { public FastCarWheel Wheel { get; set; } } class SlowCar : Car { public SlowCarWheel Wheel {
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; }
}
抽象类汽车
其中P:零件
{
受保护的抽象P轮{get;set;}
}
感谢定义控制盘接口(IWheel):
实现FastCarWheel和SlowCarWheel的接口
public class FastCarWheel : IWheel
{
}
现在,您的抽象类变成:
abstract class Car
{
public IWheel Wheel { get; set; }
}
Car的子类可以自由使用他们选择的任何车轮实现:
FastCar fastCar = new FastCar();
fastCar.Wheel = new FastCarWheel();
我认为使用
Fast
或Slow
有助于为给定的车型安装正确的车轮(其中car
和wheel
都取决于策略,而car
对象具有私人车轮聚合),但如果您需要基类级别的可见性,则可能是您唯一的选择:
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; }
}
}
您可能需要评估基类是否做得太多。通过将类拆分为多个较小的类,可以解决您的问题。另一方面,有时这是不可避免的。我会创建一个ICar,然后以这种方式定义汽车,而不是抽象类
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 {}
由于您的目标似乎是允许客户端代码将属性作为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公开为basewheelpart类,那么这对客户和IMHO来说是一个更好的解决方案。这就是问题所在。他不希望任何汽车都有任何类型的轮子。他希望快车只有快轮,慢车只有慢跟。接口无法实现这一点。如果FastCar不能有一个SlowCarWheel,那么该逻辑属于FastCar,而不属于基类。我同意,但问题是您的代码会促进使用这个(FastCar.Wheel=new SlowCarWheel();),他明确表示不允许使用它。不过,我同意这种逻辑不属于基类。第二种解决方案似乎很好。
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;
}
}