繁体   English   中英

如何使用OOP对这种情况进行建模? (继承问题)

[英]How to model this scenario using OOP? (inheritance issue)

我有很多实现不同算法的不同引擎。 它们全部实现相同的接口,但具有不同的配置方法。 它们中的大多数都没有参数配置,其中一些具有一个整数,甚至更少具有两个整数。 将来我们将拥有三个甚至四个整数的可能性很小。

我需要创建一个引擎控制器来决定何时必须启动或停止引擎,因为这对于所有其他人都是常见的。 我认为的选项如下:

  1. 创建一个唯一的接口,其参数与可用的最大Configure方法一样多,并忽略引擎上不需要的参数。 这样,我将只有一个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
  • IEngine具有Start()方法。
  • 配置是IConfig参数的列表,可以通过bool来启动(如果所有参数都可以)。
  • 每个参数都有一个IsOkToStart,该IsOkToStart根据某些条件计算得出,也许这可以为您提供灵活性? 合并您需要的参数,并可能在将来添加调整后的参数。 我认为接口非常小且具有凝聚力是一件好事。 甚至可以将它们拆分为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的许多属性中看到了Optional参数的用法。 或使用对象参数列表获取所有输入,并且在调用时可以解析该列表并确定要调用的引擎。 它们都不难被抓住和使用

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM