我的具体类可以是下面所示的类型排列之一。但是,由于我无法从两个类(案例 4 和 5)继承,我必须将其中一个类转换为接口,这会引入下面FIX部分中所示的代码重复。我知道有人会说“使用组合”,但我不知道如何更改设计以考虑到这一点。
类型排列:
ControllerSimulator
MovingControllerSimulator
RegistersControllerSimulator
ControllerSimulator
+ RegistersControllerSimulator
MovingControllerSimulator
+ RegistersControllerSimulator
代码
public abstract class ControllerSimulator
{
protected virtual void OnTurningOn() { }
public void TurnOn()
{
...
}
protected virtual void OnTurningOff() { }
public void TurnOff()
{
...
}
// more base methods
...
}
public abstract class MovingControllerSimulator : ControllerSimulator
{
public virtual void Disable() { }
public void SetMotionDuration(TimeSpan duration)
{
_motionDuration = duration;
}
protected void OnMoveStarted()
{
MoveStarted?.Invoke();
}
// more base methods
...
}
public abstract class RegistersControllerSimulator : ControllerSimulator
{
protected Dictionary<string, object> Registers;
protected abstract void OnRegisterChanged(string regName, object regVal);
public void UpdateRegister(string regName, object regVal)
{
Registers[regName] = regVal;
OnRegisterChanged(...);
}
// more base methods
...
}
修复
由于我无法继承两个类,因此我决定将
RegistersControllerSimulator
转换为接口并创建 RegistersMovingControllerSimulator
和 RegistersNonMovingControllerSimulator
。但是,这需要重复代码,我可以通过将其移至 utils 来解决。
interface IRegistersControllerSimulator
{
void UpdateRegister(string regName, object regVal);
}
public abstract class RegistersMovingControllerSimulator : MovingControllerSimulator, IRegistersControllerSimulator
{
protected Dictionary<string, object> Registers;
protected abstract void OnRegisterChanged(string regName, object regVal);
public void UpdateRegister(string regName, object regVal)
{
Registers[regName] = regVal;
OnRegisterChanged(...);
}
}
public abstract class RegistersNonMovingControllerSimulator : ControllerSimulator, IRegistersControllerSimulator
{
protected Dictionary<string, object> Registers;
protected abstract void OnRegisterChanged(string regName, object regVal);
public void UpdateRegister(string regName, object regVal)
{
Registers[regName] = regVal;
OnRegisterChanged(...);
}
}
public class Concrete_Registers_Moving_Controller : RegistersMovingControllerSimulator
{
// Uses "await Task.Delay(_motionDuration)" to imitate motion
}
public class Concrete_Registers_NonMoving_Controller : RegistersNonMovingControllerSimulator
{
}
public class Concrete_NonRegisters_Moving_Controller : MovingControllerSimulator
{
// Uses "await Task.Delay(_motionDuration)" to imitate motion
}
public class Concrete_NonRegisters_NonMoving_Controller : ControllerSimulator
{
}
我知道有人会说“使用组合”
是的,使用组合。
你可以用继承来做的事情,你也可以用组合来做。反之则不然,因为您可以组合具有多种功能的对象,但不能从多个基类继承。
那么在这种情况下你会如何处理呢?
我并不完全清楚 OP 层次结构中的各个类应该如何协同工作,但由于听起来好像有两个可变轴,因此您需要两个服务:
public interface IMovingThingy
{
// ...
}
public interface IRegistersThingy
{
// ...
}
在这里,我使用了 Dan North 的 Thingy 命名约定作为占位符名称,直到想到更好的东西。
现在将它们注入到 Controller 类中:
public sealed class ControllerSimulator
{
private readonly IMovingThingy moving;
private readonly IRegistersThingy registers;
public ControllerSimulator(IMovingThingy moving, IRegistersThingy registers)
{
this.moving = moving;
this.registers = registers;
}
public void TurnOn()
{
// ...
}
public void TurnOff()
{
// ...
}
// More methods...
}
您现在可以独立改变运动和注册。
如果你想在另一个对象中重用一个对象的方法,你可以定义接口方法,以便其他类将自己作为参数传递,但要小心,因为它表示双向耦合,这将使得更难维护代码。此类设计通常有更好的替代方案。