所以,我相信你在问继承。好吧,一个可以做到的香草方式是这样的:
public interface ICar
{
void ShiftGearUp();
void ShiftGearDown();
void SwitchLightsOn();
void SwitchLightsOff();
void Brake();
void Accelerate();
}
public class Car : ICar
{
public virtual void ShiftGearUp() { }
public virtual void ShiftGearDown() { }
public virtual void SwitchLightsOn() { }
public virtual void SwitchLightsOff() { }
public virtual void Brake() { }
public virtual void Accelerate() { }
}
public class DeluxeCar : Car
{
public override void SwitchLightsOn()
{
//calls the implementation in the Car class.
base.SwitchLightsOn();
//implement custom behavior.
this.AdjustCabinAmbientLighting();
}
private void AdjustCabinAmbientLighting() { }
}
通过这种方式,您只会覆盖您想要更改的行为。
但是,有一条世界著名的规则,即优先组合而不是继承。
它将使我们以这种方式形成解决方案:
public interface ICar
{
void ShiftGearUp();
void ShiftGearDown();
void SwitchLightsOn();
void SwitchLightsOff();
void Brake();
void Accelerate();
}
public abstract class AbstractCar : ICar
{
protected ITransmission Transmission;
protected ILights Lights;
protected IEngine Engine;
protected IBrakes Brakes;
public void ShiftGearUp()
{
this.Transmission.ShiftUp();
}
public void ShiftGearDown()
{
this.Transmission.ShiftDown();
}
public void SwitchLightsOn()
{
this.Lights.SwitchOn();
}
public void SwitchLightsOff()
{
this.Lights.SwitchOff();
}
public void Brake()
{
this.Brakes.Brake();
}
public void Accelerate()
{
this.Engine.Accelerate();
}
}
public class Car : AbstractCar
{
public Car()
{
this.Lights = new AcmeLights();
//todo
//this.Engine = init engine object;
//this.Brakes = init brakes object;
//this.Transmission = init transmission object;
}
}
public class DeluxeCar : AbstractCar
{
public DeluxeCar()
{
this.Lights = new FancyLights();
//todo
//this.Engine = init engine object;
//this.Brakes = init brakes object;
//this.Transmission = init transmission object;
}
}
public interface ITransmission
{
void ShiftUp();
void ShiftDown();
}
public interface ILights
{
void SwitchOn();
void SwitchOff();
}
public interface IEngine
{
void Accelerate();
}
public interface IBrakes
{
void Brake();
}
public class AcmeLights : ILights
{
private LightSwitch Switch;
public void SwitchOn() { this.Switch.On(); }
public void SwitchOff() { this.Switch.Off(); }
}
public class FancyLights : ILights
{
private LightSwitch Switch;
private CabinAmbientLightingController AmbientLightingController;
public void SwitchOn()
{
this.Switch.On();
this.AmbientLightingController.AdjustLightLevel();
}
public void SwitchOff()
{
this.Switch.Off();
this.AmbientLightingController.AdjustLightLevel();
}
}
public class LightSwitch
{
public void On() { }
public void Off() { }
}
public class CabinAmbientLightingController
{
public void AdjustLightLevel() { }
}
编辑:然后您可以使用您选择的依赖项注入工具通过其构造函数注入 Car 和 Deluxe car 的依赖项。这可能是“AOP”。
编辑:为此目的,也许您可以使用动态代理。著名的教程就是这个。可能有点学习曲线(可能不是这个问题的最佳解决方案,但我不知道其他任何问题) - 但总而言之,它是一个很棒的框架和有趣的阅读。
我会做什么,请注意我的 DynProxy 有点生疏,声明一个空类,比如
public class RocketCar
{
}
然后生成一个没有目标的类代理并使用拦截器来转发调用。因此,我们应该编写一个通用的拦截器,我们可以向其中注入依赖项(就像上面两个具体的 Cars 一样)。因此,我们将只有一个这样的类,并根据需要配置和使用它。我相信这应该可以在一两天内编写代码:) 这个想法是这里的“不实现接口的类”部分。我们会让 RocketCar 实现 IRocket 和 ICar。
但!在一个类中实现多个接口并不是 imo 做事的最佳方式!您正在破坏SRP。如果我们仍然拥有所有这些接口,为什么不让客户端代码通过各个接口引用它们呢?毕竟,如果 RocketCar 实现了 ICar,那么它的 Accelerate 方法一定不会意识到它是不同汽车的一部分。换句话说,RocketCar 必须以这样一种方式运行,即我们可以在任何地方使用任何其他 ICar 实现来替换 RocketCar。否则我们会破坏LSP。
因此,最好将 ICar 和 IRocket 放在单独的类中。这些的具体实现可以具有彼此的具体类型引用,这些引用对它们的交互进行建模。
我并不是说你不应该让类实现多个接口,但这应该是一个例外而不是规则。