セクション4ポリシー・モード


一、策略モード動機
  • ソフトウェア構築では、いくつかのオブジェクトアルゴリズムが多様であり、常に変更され、それらをオブジェクトに符号化すると、オブジェクトが非常に複雑になり、適用されないアルゴリズムをサポートすることもパフォーマンスの負担になる場合があります.
  • 実行時にオブジェクトのアルゴリズムを透明に変更し、アルゴリズムをオブジェクト自体とデカップリングして、上記の問題を回避するにはどうすればいいですか?

  • 二、策略モード定義(GOF定義)
    一連のアルゴリズムを定義し、それらを1つずつカプセル化し、互いに置換(変化)することができます.このモードにより、アルゴリズムは、クライアントプログラム(安定)を用いることに独立して変化することができる.
    三、コード例
    3.1再構築前コード
    #include 
    
    enum TaxBase           //       
    {
        CN_Tax = 0,
        US_Tax = 1,
        DE_Tax = 2
    };
    
    class SalesOrder
    {
    public:
        SalesOrder(TaxBase tax) { this->tax = tax; }
        ~SalesOrder() {}
    public:
        double CalculateTax()
        {   //        ,    ,        
    	if (tax == CN_Tax) {}       //   1...
    	else if (tax == US_Tax) {}  //   2...
    	else if (tax == DE_Tax) {}  //   3...
    	return 0;
        }
    private:
        TaxBase tax;
    };
    
    int main()
    {
        SalesOrder sales_order(TaxBase::CN_Tax);
        sales_order.CalculateTax();
        renturn 0;
    }
    

    3.2問題を考える
    プログラムはどう見ても問題ありませんが、プログラムの後続の拡張性を考慮していますか?例えば、いくつかの国(列挙体)を増やすと、対応するアルゴリズムも増加します.原則に背く:多拡張開放、修正閉鎖.この例のコードでは、将来他の国の税率計算の拡張が実現するように、doubleCalculateTax()のコードはそれに応じて変化する必要がある.
    3.3再構築後のコード
    #include 
    
    //     ,           
    class TaxStrategy {
    public:
        virtual double CalculateTax(const Context& contex) = 0;  //     
        virtual ~TaxStrategy() {}                                //      ,          
    };
    
    //     1:       
    class CNTax :public TaxStrategy {
    public:
        virtual double CalculateTax(const Context& contex) {     //           
    	// Override:  China   
    	return 0;
        }
    };
    
    //     2:       
    class USTax :public TaxStrategy {
    public:
        virtual double CalculateTax(const Context& contex) {     //           
    	//  Override:  US    
    	return 0;
        }
    };
    
    //     3:       
    class DETax :public TaxStrategy {
    public:
        virtual double CalculateTax(const Context& contex) {     //           
    	//  Override:  DE   
    	return 0;
        }
    };
    
    //   ,         
    
    //        ,SalesOrder           
    class SalesOrder
    {
    public:
        SalesOrder(StrategyFactory* strategyFactory){
    		this->strategy = strategyFactory->NewStrategy();
        }
        ~SalesOrder() { delete this->strategy; }
    public:
        double CalculateTax()
        {
    	Context contex;
    	double val = strategy->CalculateTax(contex);
    	return val;
        }
    private:
        TaxStrategy* strategy;          //     ,        ,              
    };
    
    //               ,                    
    class StrategyFactory
    {
    public:
        StrategyFactory()  {}
        ~StrategyFactory() {}
    public:
        TaxStrategy* NewStrategy() {
    	//               ,          ,          ,      
        }
    };
    
    //                 ,           
    int main()
    {
        StrategyFactory* strategyFactory;
        SalesOrder2 sales_order2(strategyFactory);        
        sales_order2.CalculateTax();
    
        return 0;
    }
    

    四、戦略モデルの要点まとめ
  • Strategyおよびサブクラスは、コンポーネントにいくつかのカラム再利用可能なアルゴリズムを提供し、これにより、タイプが実行時に必要に応じて各アルゴリズム間で容易に切り替えることができる.
  • ポリシーモードは、条件判断文以外の拡張可能な選択を提供し、条件文の結合性を解消し、複数の条件分岐を含むコードは通常ポリシーモードを必要とする.
  • ポリシーオブジェクトにインスタンス変数がない場合、各コンテキストはポリシーオブジェクトを共有することができ、オブジェクトのオーバーヘッドを節約することができる.

  • 五、考え方の総括
  • ポリシーモードを使用してif文を再構成する場合は、ifの場合が常に変化する場合である.
  • ifブランチの状況が永遠に変わらない場合、ifブランチでよい.Case1
  • ifブランチが変わらない場合、場合によってはブランチが実行されない確率が高い場合があり、これはパフォーマンスの負担をもたらす可能性があり、ポリシーモードも使用することができる.Case2