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

时间:2012-10-25 08:04:09

标签: c# .net oop inheritance interface

我有很多不同的引擎可以实现不同的算法。它们都实现了相同的接口,但具有不同的Configuration方法。它们中的大多数都是在没有参数的情况下配置的,其中一些是带有一个整数,有些是两个整数。将来我们将有三个甚至四个整数的可能性很小。

我需要创建一个引擎控制器,它决定何时启动或停止引擎,因为这对所有引擎都很常见。我认为的选项如下:

  1. 创建一个独特的界面,其参数与最大的可用配置方法一样多,并忽略引擎上不需要的参数。这样我就只有一个EngineController。
  2. 为每个不同的配置方法创建一个接口,并为每个不同的接口创建一个EngineController(但这会让我创建很多只在参数数量上有所不同的类,每个类需要2个新类将新参数添加到引擎的时间。
  3. ...
  4. 我对这两个解决方案中的任何一个都感到不舒服,因为传递不需要的参数看起来很“丑陋”,并且由于第二个选项产生的类数量很大(只有很小的差异)。

    避免此问题的任何设计或模式?

    编辑(感谢您的回答,这个编辑回答了所有问题并澄清了问题):

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

    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。控制器将在需要时调用Configure,Start和Stop:

    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或其他)传递未定义数量的参数。这个想法不错,但后来我将失去参数名称。但也许这是迄今为止最好的选择。

4 个答案:

答案 0 :(得分:2)

这对你有帮助吗。

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

答案 1 :(得分:2)

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

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()方法。
  • 配置是一个IConfigparameters列表,其中bool可以启动(如果所有参数都正常)。
  • 每个参数都有一个根据某些条件计算的IsOkToStart 也许这为您提供了灵活性?结合您需要的参数,并可能在将来添加ned参数。我认为界面非常小而且有凝聚力是件好事。甚至可能将它们分成IStartParameter和IStopParameter,然后组合成所需的配置?

答案 2 :(得分:1)

我会将其建模类似于:

 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>();

答案 3 :(得分:0)

IOC容器用于调用您需要的引擎或您需要的一堆引擎,并在运行时注入它们,您可以在调用容器时将它们与可选参数结合使用。我在.NET FW的许多属性中看到了Optional参数的用法。或者使用object参数列表来获取所有输入,并在被调用时可以解析列表并确定它要调用的引擎。其中没有一个难以掌握和使用