如何使用OOP对此方案进行建模?(继承问题)



我有许多实现不同算法的不同引擎。所有这些都实现了相同的接口,但具有不同的配置方法。它们中的大多数是没有参数的配置,其中一些具有一个整数,甚至具有两个整数。将来我们将使用三个甚至四个整数都有很小的概率。

我需要创建一个发动机控制器,该发动机控制器何时必须启动或停止发动机,因为所有引擎都很常见。我认为的选项如下:

  1. 创建一个独特的接口,其参数与可用的最大配置方法一样多,并忽略引擎上不需要的界面。这样,我将只有一个EngineController。
  2. 为每种不同的配置方法创建一个接口,并为每个不同接口创建一个EngineController(但这将使我创建很多类别的类,这些类别仅在参数上有所不同,每个类别都需要2个新类时间添加了一个新参数。
  3. ...

我真的对这两个解决方案中的任何一个都不满意,因为传递的不需要参数看起来"丑陋",并且由于第二种选项生成的类别数量很高(只有很小的差异)。

任何避免此问题的设计或图案?

编辑(感谢您的答案,此编辑回答所有内容并阐明问题):

举一个例子,这些是引擎。

abstract class EngineBase
{
    public void Start() {...}
    public void Stop() {...}
}
class EngineOne : EngineBase
{
    public void Configure(int parameter1) {...};
}
class EngineTwo : EngineBase
{
    public void Configure(int parameter1, int parameter2) {...};
}
class EngineThree : EngineBase
{
    public void Configure(int parameter1, int parameter2, int parameter3) {...};
}

由于所有引擎都具有相同的逻辑来决定何时或结束,因此我想创建一个处理它们的新类,称为EngineController。控制器将在需要时调用配置,开始和停止:

class EngineController
{
    EngineBase _engine; ??? or what?
    void SuperviseEngine() { ... _engine.Configure(x,x,...) ... _engine.Start() ... 
}

我的第一个想法是将下一个方法添加到Enginebase类中:

abstract class EngineBase
{
    public void Start() {...}
    public void Stop() {...}
    public void Configure(int parameter1, int parameter2, int parameter3) {...}
}
class EngineController
{
    EngineBase _engine;
    void SuperviseEngine() { ... _engine.Configure(x,y,z) ... _engine.Start() ... 
}

忽略了不需要的参数,但我不喜欢这个想法。然后,我考虑执行以下操作:

interface I1ParameterConfigurable
{
    public void Configure(int parameter1) {...};
}
interface I2ParameterConfigurable
{
    public void Configure(int parameter1, int parameter2) {...};
}
interface I3ParameterConfigurable
{
    public void Configure(int parameter1, int parameter2, int parameter3) {...};
}

然后为每种引擎创建3个不同的控制器:

class EngineController1Parameter
{
    EngineBase _engine;
    I1ParameterConfigurable _configurableEngine = _engine as I1ParameterConfigurable;
    void SuperviseEngine() { ... _configurableEngine .Configure(x) ... _engine.Start()
}
class EngineController2Parameter
{
    EngineBase _engine;
    I2ParameterConfigurable _configurableEngine = _engine as I2ParameterConfigurable;
    void SuperviseEngine() { ... _configurableEngine .Configure(x, y) ... _engine.Start()
}

您明白了,但是我觉得这将创建很多界面/类时,也许有办法避免这种情况。

多亏了您的答案,我有第三个选项与第一个选项相似,但使用数组(或iEnumerable或其他)传递不确定的参数。这个想法还不错,但是我将失去参数名称。但这也许是到目前为止的最佳选择。

对您有帮助的意愿。

    interface IEngine
    {
        void startEngine(params int[] engineParam);
    }

也许我不完全理解,但我认为您想要这样的东西:

public interface IEngineController //I dont see a need to expose the enigine here in this pseudo code
{
    void Start(); 
    IConfiguration Config { get; }
}
public interface IEngine
{
    void Start();
}
public interface IConfiguration
{
    bool IsOkToStart { get; }
}
public class Configuration : IConfiguration
{
    public Configuration(List<IConfigurationParameter> configurationParameters)
    {
        ConfigurationParameters = configurationParameters;
    }
    public bool IsOkToStart
    {
        get { return ConfigurationParameters.All(cfg=>cfg.IsOkToStart); }
    }
    protected List<IConfigurationParameter> ConfigurationParameters { get; private set; }
}
public interface IConfigurationParameter
{
    bool IsOkToStart { get; }
}
public interface IMaxTemp : IConfigurationParameter
{
    double MaxTemp { get; }
}
public interface ISafetyParameter : IConfigurationParameter
{
    ISafetyCondition SafetyCondition { get; }
}

这有点长,我省略了stop()。这个想法是:

  • 控制器具有IENGINE(未在接口中暴露)和ICONFIG
  • IENENGINE具有start()方法。
  • 配置是可以启动的IconFigParameters的列表(如果所有参数都可以)。
  • 每个参数都有一个ISOKTOSTART,该ISOKTOSTART根据某种条件进行计算也许这为您提供了灵活性?结合所需的参数,并可能在将来添加NED参数。我相信界面非常小且具有凝聚力是一件好事。也许甚至将它们分为iStartParameter和Istopparameter,然后将它们组合到所需的配置?

我会建模与此类似:

 public interface IEngine1 {
 }
 public interface IEngine1Config {
     int Param1 {get;}
 }
 public Engine1 : IEngine1 {
     IEngine1Config _config;
     public Engine1(IEngine1Config config) {
        _config = config;
     }
 }

然后,您可以选择选择一个类实现不同的引擎配置:

 class AllEnginesConfig : IEngine1Config, IEngine2Config {
      int Param1 {get;set;}
      // ... etc
 }

(当然,在您的情况下也可以在单独的类中实现配置更好)

如果您有很多引擎,我将使用IOC容器注册所有不同类型,并让其连接所有依赖项。

 container.Register<IEngine1, Engine1>();
 var theOneAndOnlyConfig = new AllEnginesConfig() {}; // properly initialized, of course
 container.RegisterInstance<IEngine1Config>(theOneAndOnlyConfig); 
 container.RegisterInstance<IEngine2Config>(theOneAndOnlyConfig); 
 // ...

然后,要实例化引擎,您只需使用容器:

 container.Get<IEngine1>();

ioc容器以调用所需的引擎或您需要的一堆引擎并在运行时注入它们,并且可以在调用容器时将它们与可选参数结合使用。我已经看到了.NET FW的许多属性中可选参数的用法。或使用对象参数的列表获取所有输入,而当调用时,可以解析列表并确定打算调用哪种引擎。他们都不难以理解和使用

最新更新