パターンの構造

古典的な "Design Patterns:Elements of Reusable Object-Oriented Software" と "Pattern-Oriented Software Architecture, Volume 1" は、同様の手順を使用してパターンを提示しています。今日は、このパターンの構造を紹介します。

パターンの構造について書く前に、同じページに移動して、Christopher Alexander によるパターンの定義から始めましょう。

  • パターン :"各パターンは、特定のコンテキスト、問題、解決策の間の関係を表す 3 つの部分からなるルールです。 "

これは、パターンが、特定のコンテキストで繰り返される設計上の問題に対する一般的な解決策を記述することを意味します。

  • コンテキスト は設計状況です。
  • 問題 このコンテキストで作用する力です。
  • 解決策 力のバランスをとる構成です。

Christopher Alexander は、パターンの利点を説明するために、有用、使用可能、および使用される 3 つの形容詞を使用しています。

  • 役に立つ :有用なパターンが必要です。
  • 使える :パターンは実装可能である必要があります。
  • 中古 :パターンは発見されているが、発明されていない。このルールは 3 のルールと呼ばれます。 ." (https://wiki.c2.com/?RuleOfThree)

では、パターンの構造について書きましょう。

パターンの構造

正直、不思議な現象があります。一方では、「デザイン パターン:再利用可能なオブジェクト指向ソフトウェアの要素」と「パターン指向ソフトウェア アーキテクチャ、第 1 巻」の両方の本は、ソフトウェア開発に関してこれまでに書かれた中で最も影響力のある本です。一方、両方の本には、眠りにつく要素がたくさんあります。この眠りに落ちる要因は主に、両方の本が単調に繰り返される 13 のステップでパターンを提示しているという事実によるものです。

飽きさせないために、「設計パターン:再利用可能なオブジェクト指向ソフトウェアの要素」の構造を戦略パターンに当てはめて、これらの 13 のステップを簡潔に示します。各ステップの意図は斜体で表示されます。斜体以外の内容は、戦略パターンを示しています。

名前

覚えやすい簡潔な名前

戦略パターン

意図

質問への答え:パターンの目的は何ですか?

アルゴリズムのファミリーを定義し、それらをオブジェクトにカプセル化し、プログラムの実行時にそれらを交換可能にします。

別名

既知の場合、パターンの代替名

ポリシー

モチベーション

パターンの動機付けの例

文字列のコンテナーは、さまざまな方法で並べ替えることができます。最初の n 文字に基づいて、文字列の長さに基づいて、辞書順、大文字と小文字を区別せず、逆順に並べ替えることができます ... .ソート基準をソートアルゴリズムにハードコーディングすることは、メンテナンスの悪夢です。結果として、ソート基準をカプセル化するオブジェクトにして、それを使用してソート アルゴリズムを構成します。

適用範囲

パターンを適用できる状況

戦略パターンは次の場合に適用されます

  • 関連するクラスの多くは、動作のみが異なります。
  • アルゴリズムのさまざまなバリアントが必要です。
  • アルゴリズムはクライアントに対して透過的であるべきです。

構造

パターンのグラフィック表示

参加者

このパターンに参加するクラスとオブジェクト .

  • Context :具体的な戦略を使用し、Strategy を実装します インターフェース
  • Strategy :さまざまな戦略のインターフェースを宣言します
  • ConcreteStrategyA, ConcreteStrategyB :戦略を実行する

コラボレーション

参加者とのコラボレーション

コンテキストと具体的な戦略により、選択したアルゴリズムが実装されます。使用された具象戦略にクライアント要求を転送するコンテキスト。

結果

パターンの長所と短所は何ですか?

戦略パターンの利点は次のとおりです。

  • 関連するアルゴリズムのファミリは均一に使用できます。
  • クライアントは実装の詳細から隠されています。
  • 実行時にアルゴリズムを交換できます。

実装

パターンの実装テクニック

<オール>
  • コンテキストと戦略インターフェースを定義する
  • 具体的な戦略を実行する
  • コンテキストは、実行時またはコンパイル時に引数をテンプレート パラメータとして受け取ることができます。
  • サンプル コード

    パターンの実装を示すコード スニペット。この本は Smalltalk と C++ を使用しています。

    戦略パターンは、標準テンプレート ライブラリの設計に組み込まれているため、表示されない場合があります。さらに、STL はしばしば戦略パターンの軽量バリアントを使用します。

    多くの例のうちの 2 つを次に示します。

    STL アルゴリズム

    std::sort ソート基準でパラメータ化できます。ソート基準は二項述語でなければなりません。ラムダは、このような二項述語に最適です:

    // strategySorting.cpp
    
    #include <algorithm>
    #include <functional>
    #include <iostream>
    #include <string>
    #include <vector>
    
    void showMe(const std::vector<std::string>& myVec) {
     for (const auto& v: myVec) std::cout << v << " ";
     std::cout << "\n\n";
    }
    
    
    int main(){
    
     std::cout << '\n';
    
     // initializing with a initializer lists
     std::vector<std::string> myStrVec = {"Only", "for", "Testing", "Purpose", "!!!!!"};
     showMe(myStrVec); // Only for Testing Purpose !!!!! 
    
     // lexicographic sorting
     std::sort(myStrVec.begin(), myStrVec.end());
     showMe(myStrVec); // !!!!! Only Purpose Testing for 
    
     // case insensitive first character
     std::sort(myStrVec.begin(), myStrVec.end(), 
     [](const std::string& f, const std::string& s){ return std::tolower(f[0]) < std::tolower(s[0]); });
     showMe(myStrVec); // !!!!! for Only Purpose Testing 
    
     // sorting ascending based on the length of the strings
     std::sort(myStrVec.begin(), myStrVec.end(), 
     [](const std::string& f, const std::string& s){ return f.length() < s.length(); });
     showMe(myStrVec); // for Only !!!!! Purpose Testing 
    
     // reverse 
     std::sort(myStrVec.begin(), myStrVec.end(), std::greater<std::string>() );
     showMe(myStrVec); // for Testing Purpose Only !!!!! 
    
     std::cout << "\n\n";
    
    }
    

    プログラム strategySorting.cpp ベクトルを辞書式に、大文字と小文字を区別せず、文字列の長さに基づいて昇順で、逆順に並べ替えます。逆ソートには、定義済みの関数オブジェクト std::greater. を使用します プログラムの出力は、ソース コードに直接表示されます。

    STL コンテナ

    ポリシーは、動作を構成できる汎用関数またはクラスです。通常、ポリシー パラメータにはデフォルト値があります。 std::vector そして std::unordered_map これらのポリシーを C++ で例示します。もちろん、ポリシーはコンパイル時にテンプレート パラメーターで構成される戦略です。

    template<class T, class Allocator = std::allocator<T>> // (1)
    class vector; 
    
    template<class Key,
     class T,
     class Hash = std::hash<Key>,  // (3)
     class KeyEqual = std::equal_to<Key>,  // (4)
     class allocator = std::allocator<std::pair<const Key, T>> // (2)
    class unordered_map;
    

    これは、 T に応じて、各コンテナーがその要素のデフォルト アロケーターを持っていることを意味します。 (1 行目) または std::pair<const Key, T> で (2行目)。さらに、 std::unorderd_map デフォルトのハッシュ関数 (3 行目) とデフォルトの等号関数 (4) があります。ハッシュ関数はキーに基づいてハッシュ値を計算し、equal 関数はバケット内の衝突を処理します。

    既知の用途

    パターンの既知の使用例を少なくとも 2 つ

    最新の C++ には、戦略の使用例がはるかに多くあります。

    • C++17 では、約 70 の STL アルゴリズムを実行ポリシーで構成できます。 std::sort の 1 つのオーバーロードを次に示します。 :
    template< class ExecutionPolicy, class RandomIt >
    void sort( ExecutionPolicy&& policy,
     RandomIt first, RandomIt last );
    

    実行ポリシーのおかげで、順番に並べ替えることができます (std::execution::seq )、並列 (std::execution::par )、または並列でベクトル化 (std::execution::par_unseq ).

    • C++20 では、従来の STL アルゴリズムのほとんどに範囲ペンダントがあります。これらの範囲のペンダントは、突起などの追加のカスタマイズ ポイントをサポートします。詳細については、以前の投稿「範囲を使用した射影」をご覧ください。

    このパターンに密接に関連するパターン。

    戦略オブジェクトは、軽量オブジェクトである必要があります。したがって、ラムダ式は理想的に適合します。

    次は?

    パターン、アルゴリズム、またはフレームワークの違いは何だろうと思うかもしれません。次回の投稿でこれを明確にし、パターン シーケンスやパターン言語などの用語を紹介します。


    No