0

さまざまなアルゴリズムを実装するさまざまなエンジンがたくさんあります。それらはすべて同じインターフェースを実装していますが、構成メソッドが異なります。それらのほとんどはパラメーターなしで構成され、そのうちのいくつかは 1 つの整数で構成され、2 つの整数で構成されるものはさらに少なくなります。将来、整数が 3 つまたは 4 つになる可能性はわずかです。

エンジンをいつ開始または停止する必要があるかを決定するエンジン コントローラーを作成する必要があります。これは、すべてのエンジンに共通することです。私が考えたオプションは次のとおりです。

  1. 利用可能な最大のConfigureメソッドと同じ数のパラメーターを持つ一意のインターフェイスを作成し、エンジンで不要なものを無視します。このようにして、EngineController は 1 つだけになります。
  2. さまざまな構成メソッドごとにインターフェイスを作成し、さまざまなインターフェイスごとに EngineController を作成します (ただし、これにより、パラメーターの数だけが異なる多くのクラスが作成され、新しいクラスを作成するたびに 2 つの新しいクラスが必要になります)。パラメータがエンジンに追加されます。
  3. ...

不要なパラメーターを渡すのは「醜い」ように見え、2番目のオプションで生成されるクラスの数が多いため(非常に小さな違いしかないため)、2つのソリューションのいずれにも満足していません。

この問題を回避する設計またはパターンはありますか?

編集(回答ありがとうございます。この編集はそれらすべてに回答し、質問を明確にします):

例を挙げると、これらはエンジンです。

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など)を使用して未定義の数のパラメーターを渡す3番目のオプションがあります。アイデアは悪くありませんが、パラメーター名が失われます。しかし、おそらくそれは今までの最良の選択肢です。

4

4 に答える 4

2

それはあなたを助けますか。

    interface IEngine
    {
        void startEngine(params int[] engineParam);
    }
于 2012-10-25T08:16:24.517 に答える
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() メソッドがあります。
  • Configuration は、bool を含む IConfigparameters のリストであり、(すべてのパラメーターが問題ない場合) 開始しても問題ありません。
  • 各パラメーターには、いくつかの条件に応じて計算される IsOkToStart があります。必要なパラメーターを組み合わせて、将来的に ned パラメーターを追加する可能性があります。インターフェイスが非常に小さく、まとまりがあるのは良いことだと思います。たぶん、それらを IStartParameter と IStopParameter に分割して、目的の構成に組み合わせるだけですか?
于 2012-10-25T08:22:28.253 に答える
1

これを次のようにモデル化します。

 public interface IEngine1 {

 }

 public interface IEngine1Config {
     int Param1 {get;}
 }

 public Engine1 : IEngine1 {
     IEngine1Config _config;
     public Engine1(IEngine1Config config) {
        _config = config;
     }
 }

その後、必要に応じて、さまざまなエンジン構成を実装する 1 つのクラスを選択できます。

 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>();
于 2012-10-25T08:30:53.447 に答える
0

IOC コンテナーを使用して、必要なエンジンまたは必要な一連のエンジンを呼び出し、実行時にそれらを注入します。コンテナーの呼び出し中にオプションのパラメーターと組み合わせて使用​​できます。.NET FW の多くの属性でオプションのパラメーターが使用されているのを見てきました。または、オブジェクト パラメータのリストを使用してすべての入力を取得し、呼び出されたときにリストを解析して、呼び出すエンジンを決定できます。それらのどれも把握して使用するのが難しいことはありません

于 2012-10-25T08:19:04.870 に答える