在我的案例中如何解决多类继承而不重复代码?

问题描述 投票:0回答:1

我的具体类可以是下面所示的类型排列之一。但是,由于我无法从两个类(案例 4 和 5)继承,我必须将其中一个类转换为接口,这会引入下面FIX部分中所示的代码重复。我知道有人会说“使用组合”,但我不知道如何更改设计以考虑到这一点。

类型排列:

  1. ControllerSimulator
  2. MovingControllerSimulator
  3. RegistersControllerSimulator
  4. ControllerSimulator
    +
    RegistersControllerSimulator
  5. 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
{
}
c# oop design-patterns multiple-inheritance
1个回答
0
投票

我知道有人会说“使用组合”

是的,使用组合。

你可以用继承来做的事情,你也可以用组合来做。反之则不然,因为您可以组合具有多种功能的对象,但不能从多个基类继承。

那么在这种情况下你会如何处理呢?

我并不完全清楚 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...
}

您现在可以独立改变运动和注册。

如果你想在另一个对象中重用一个对象的方法,你可以定义接口方法,以便其他类将自己作为参数传递,但要小心,因为它表示双向耦合,这将使得更难维护代码。此类设计通常有更好的替代方案。

© www.soinside.com 2019 - 2024. All rights reserved.