1

私はストラテジパターンを読んでいましたが、実装しようとしていましたが、私がオープンクローズドの原則に違反していると感じるストラテジ実装を決定するのに苦労しました。ストラテジーパターンとオープンクローズド原則コンフリクト

戦略パターンでは、私たちはインターフェイスに基づいてコードを作成し、クライアントとのやりとりに基づいて戦略の実装を行います。私たちは、クライアントが上記オープン閉鎖原則どおり今

IStrategy str; 
    if(stragety1) { 
    str = new Strategy1() 
    } else if (stragety2) { 
    str = new Strategy2() 
    } and so on.. 
str.run() 

のようなものを選択する戦略の条件を使用して決定する必要があるので、我々は戦略の束を持っている場合今

は延長に開いているが、そうではありません変更を完了しました

将来、別の戦略(拡張機能)を追加する必要がある場合は、このコードを変更する必要があります。

これは回避できますか、それとも戦略パターンを実装する必要があるのでしょうか?

+0

私の経験では、実際にはオープン/クローズドの原則はほとんど価値がありません。主な実装には、新しいコードをベースに追加せずに後でカスタマイズすることができるアーキテクチャ上のフックがあります(新しいカスタム部分への新しいコードのみ)。これが実際に失敗する主な理由は、コードが野生であり、誰もが計画していない拡張性の問題にぶつかるまで、アーキテクチャーのフックで考慮する必要がある可変性の次元が何であるかをほとんど決して知らないことです。 – ely

+0

あまりにも多くの計画を立てようとすると、抽象度の高い建築用スープになりますが、それが正しい抽象であるかどうかは誰にも分かりません(使いやすさと保守性に深刻な影響を与える可能性があります)。最終的には、可変性の次元である可能性が非常に高いいくつかのものに対してカスタマイズ可能性を組み込もうとする可能性があります。残りの部分では、ソースコードを変更して解決する必要がありますそれ。 – ely

+1

あなたのコードは私の工場のパターンのようです。 – bpjoshi

答えて

2

これは実際には変更できませんが、これは初期化の方法によるものです。値(列挙型?)を使用して、どの戦略サブクラスを使用するかを決定しています。 @bpjoshiはcommentを指摘しているので、これはFactoryパターンの詳細です。

ウィキペディアでは、戦略パターンがどのようにして妨げられるのではなくsupport the Open/Closed Principleであるかについて説明します。
この例では、Brake戦略でCarクラスを使用しています。車の中にはABSで制動するものもあれば、そうでないものもある。異なるCarのサブクラスとインスタンスには、制動のための異なる戦略を与えることができます。

変更のためにコードをクローズするには、戦略を別々に選択する必要があります。新しい行動やサブクラスが定義されている場所で戦略を選択したいとします。特定のStrategyサブクラスがコードが拡張されるポイントに適用されるように、コードをリファクタリングする必要があります。

+1

wikiの記事は私が探していた答えを説明しています。 –

0

私は、修正のために閉鎖について誤解があると思います。 1988年

、メイヤーは言った:作品
ソフトウェアがすべきとき可能アプリケーションが新しい機能で拡張されたときに変更することはありません。

とローベルC. Matrin

は言った:

この定義は明らかに日付を記入されます。 それについて非常に注意深く考えてください。システム内のすべてのモジュールの動作を変更せずに変更できる場合は、そのシステムに新しい機能を追加することができます古いコードを変更することなく。新しいコードを書くことによって、機能はに追加されます。 https://8thlight.com/blog/uncle-bob/2014/05/12/TheOpenClosedPrinciple.html

古いコードを変更せずにいくつかの新しいコードを追加することは、オープンクローズド原理と競合しません。

-1

あなたが指している決定は、工場クラスの責任であるべきだと思います。以下は、いくつかのサンプルコードです:

public interface ISalary 
{ 
    decimal Calculate(); 
} 

public class ManagerSalary : ISalary 
{ 
    public decimal Calculate() 
    { 
     return 0; 
    } 
} 

public class AdminSalary : ISalary 
{ 
    public decimal Calculate() 
    { 
     return 0; 
    } 
} 

public class Employee 
{ 
    private ISalary salary; 

    public Employee(ISalary salary) 
    { 
     this.salary = salary; 
    } 

    public string Name { get; set; } 

    public decimal CalculateSalary() 
    { 
     return this.salary.Calculate(); 
    } 
} 

Employeeクラスは、Strategyパターンを使用し、オープン/クローズの原則に従って、それはコンストラクタを介して注射により、新たな戦略の種類(ISalary実装)に開かれている。すなわち、これらだけに閉じました変形。

不足している部分は何か、Employeeオブジェクトを作成するコードです:

public enum EmployeeType 
{ 
    Manager, 
    Admin 
} 

public class EmployeeFactory 
{ 
    public Employee CreateEmployee(EmployeeType type) 
    { 
     if (type == EmployeeType.Manager) 
      return new Employee(new ManagerSalary()); 

     else if (type == EmployeeType.Admin) 
      return new Employee(new AdminSalary()); 

     etc 

    } 
} 

これは非常に単純なファクトリパターンです。これを行うより良い方法がありますが、これは概念を説明する最も簡単な方法です。

+0

戦略を選ぶために 'if-else'を使用することは、コードがOCPを壊すのを防ぐためには本当に悪い考えです。 –

+0

@Igor Soloydenko - はい私はこれを行うより良い方法があると言いました。私は、戦略ピッキングロジックが実際の戦略パターンの一部ではない理由を説明しようとしていました。 –

2

1)具体的なの使い方を選択/作成する必要があります。 I. selectStrategyを使用して、(コンストラクタ)パラメータなどとして渡します。

2)条件付きの作成を完全に回避する方法はありませんが、非表示にすることができます(たとえば、state => strategyのマッピングに辞書を使用するなど)。それをアプリケーションの別のレベルに移します。最後のアプローチは非常に強力で柔軟性がありますが、タスクに依存します。場合によっては、それを使用するのと同じレベルで選択/作成することもできます。他のケースでは、最高/最低レベルへの委任/選択を作成することもできます。

2.1)Registryパターンを使用すると、新しい戦略を追加するときに「コア」オブジェクトの変更を避けることができます。