訪問者パターンの原理分析
デザインパターンシリーズの概要
デザインパターン | 航空券 |
---|---|
3つのファクトリーモデル | 搭乗口 |
戦略モード | 搭乗口 |
委任モード | 搭乗口 |
テンプレートメソッドパターン | 搭乗口 |
オブザーバーモード | 搭乗口 |
シングルトンモード | 搭乗口 |
プロトタイプモード | 搭乗口 |
エージェンシーモデル | 搭乗口 |
デコレータモード | 搭乗口 |
アダプターモード | 搭乗口 |
ビルダーモード | 搭乗口 |
責任連鎖モデル | 搭乗口 |
フライウェイトモデル | 搭乗口 |
コンビネーションモード | 搭乗口 |
ファサードパターン | 搭乗口 |
ブリッジモード | 搭乗口 |
中間モデル | 搭乗口 |
イテレーターモード | 搭乗口 |
状態モード | 搭乗口 |
通訳モード | 搭乗口 |
メモモード | 搭乗口 |
コマンドモード | 搭乗口 |
ビジターモード | 搭乗口 |
ソフトウェア設計の7つの原則と設計パターンの要約 | 搭乗口 |
序文
こちらのデザインパターンシリーズは、23のデザインパターンの最後のデザインパターンです。ビジターパターンは、すべてのデザインパターンの中で最も難しいデザインパターンとも言えます。もちろん、ほとんど使用していません。デザインパターンの作成者は、訪問者パターンを次のように評価します。ほとんどの場合、訪問者パターンを使用する必要はありませんが、使用する必要がある場合は、実際に使用する必要があります。
訪問者パターンは何ですか
ビジターパターン(ビジターパターン)は、データ構造とデータ操作を分離するデザインパターンです。特定のデータ構造内のさまざまな要素に作用するいくつかの操作のカプセル化を指します。データ構造を変更せずにこれらの要素に作用する新しい操作を定義できます。ビジターモードは動作モードです。
ビジターパターンの基本的な考え方は、システム内の特定の固定タイプのオブジェクト構造(要素)に対してビジターのオブジェクトを受け入れるためのaccept()メソッドを提供することです。訪問者が異なれば、同じ要素へのアクセスコンテンツも異なるため、同じ要素セットで異なる要素の結果を生成できます。accept()メソッドは、さまざまなビジターオブジェクトを受け入れることができ、その後、ビジターオブジェクトのvisit()メソッドに内部的に転送します。
ビジターパターンの中心的な考え方は、データ構造とデータ操作を分離して、要素の操作が優れたスケーラビリティを持つようにすることです。異なるデータ操作タイプ(ビジター)を拡張することで、同じ要素に異なる操作を実装できます。
この一連の理論的概念を読んだ後、少し目がくらむように感じますか?これは少し抽象的なように聞こえますが、心配しないでください。見下ろし続けてください。
ふりをする瞬間が再びやって来ました。話は安いです。コードを見せてください。例を挙げて、訪問者のパターンがどのように書かれているかを見てみましょう。
訪問者パターンのサンプル
顧客がメニューから注文を表示する必要があるレストランの注文の例を取り上げます。この例では、顧客が訪問者であり、料理は訪問者がアクセスする必要のある情報です。
1.最初に料理(レシピ)インターフェースを確立し、訪問者の訪問を受け入れる方法のみを定義します。
package com.zwx.design.pattern.visitor;
public interface IRecipe {
void accept(ICustomer customer);
}
次に、2種類のビデオ、1種類の焼き豚と1種類の季節の野菜のみをリストします。したがって、2つのクラスが必要です。
package com.zwx.design.pattern.visitor;
public class Meat implements IRecipe {
@Override
public void accept(ICustomer customer) {
customer.visit(this);
}
public String getPrice(){
return "88元/份";
}
}
package com.zwx.design.pattern.visitor;
public class Cabbage implements IRecipe {
@Override
public void accept(ICustomer customer) {
customer.visit(this);
}
public String getPrice(){
return "44元/份";
}
}
これらの2つのクラスでacceptメソッドを実装することに加えて、価格をチェックするメソッドも提供します。
3.この時点で、抽象的な訪問者を作成する必要があります。
package com.zwx.design.pattern.visitor;
public interface ICustomer {
void visit(Meat meat);
void visit(Cabbage cabbage);
}
内部では同じメソッド名の2つのメソッドが定義されていますが、パラメーターが異なり、パラメーターは要素に対応しています。理論的には、上記のいくつかのディッシュがあります。いくつかのメソッドを定義する必要があります。つまり、メソッドの数とアクセスする要素の数は等しくなければなりません。
4.次に、顧客Aの特定の訪問者ロールを作成して、抽象的な訪問者を実装します。
package com.zwx.design.pattern.visitor;
public class CustomerA implements ICustomer{
@Override
public void visit(Meat meat) {
System.out.println("肉类:" + meat.getPrice());
}
@Override
public void visit(Cabbage cabbage) {
System.out.println("时蔬:" + cabbage.getPrice());
}
}
来場者と料理が増えたので、メニューから料理情報を見て注文する必要があるため、メニューが1つ少なくなり、すべての料理を管理するためのメニューカテゴリも必要になります。
5.新しいメニュークラスを作成します。
package com.zwx.design.pattern.visitor;
import java.util.ArrayList;
import java.util.List;
public class RestaurantMenu {
private List<IRecipe> recipeList = new ArrayList<>();
public RestaurantMenu(IRecipe recipe) {
recipeList.add(recipe);
}
public void addRecipe(IRecipe recipe){
recipeList.add(recipe);
}
public void display(ICustomer customer){
for (IRecipe recipe : recipeList){
recipe.accept(customer);
}
}
}
メニュークラスは、リストを介してすべての料理を維持し、次にdisplayメソッドを介してすべての料理情報を表示します。
6.次に、テストするテストクラスを作成します。
package com.zwx.design.pattern.visitor;
public class TestVistor {
public static void main(String[] args) {
IRecipe recipe = new Meat();
RestaurantMenu menu = new RestaurantMenu(recipe);
menu.addRecipe(new Cabbage());
menu.display(new CustomerA());
}
}
次の情報を出力します。
肉类:88元/份
时蔬:44元/份
これはビジターパターンです。上記はビジターを頻繁に変更する必要があるためですが、追加する必要があるのはカスタマークラスだけなので、非常に便利です。
初めてビジターパターンに触れた場合は、まだ少し抽象的だと感じるかもしれませんので、何度か書き直していくと、だんだんと感じていくと思います。
訪問者の役割
上記の例から、訪問者パターンには主に5つの役割があると結論付けることができます。
- 抽象ビジター(Vistor):インターフェースまたは抽象クラス(例のICustomerなど)。この役割は主に特定の要素の訪問方法を定義することです。パラメータは特定の要素です。理論的には、方法の数は要素の数と同じです。したがって、要素が不安定で頻繁に変更される場合、訪問者は常に要素を変更する必要があり、訪問者モードの使用には適していないため、訪問者モードは要素構造が比較的安定しているシナリオに適しています。
- 具体的な訪問者(ConcreteVistor):特定の要素(例のCustomerAなど)へのアクセスを実現します。
- 抽象要素(要素):インターフェースまたは抽象クラス。訪問者のアクセスを受け入れるメソッドaccept(例のIRecipeなど)を定義します。
- 具体的な要素(ConcreteElement):通常はvisitor.visit()(例のCabbageやMeatなど)による訪問者のアクセスを受け入れるための特定の実装を提供します。
- 構造オブジェクト(ObjectStruture):要素を維持し、訪問者がすべての要素(例のRestaurantMenuなど)にアクセスできるようにするメソッドを提供するために使用されます。
ビジターモードのアプリケーションシナリオ
ビジターモードは、次のシナリオに適しています。
- 1.データ構造は安定している必要がありますが、データ構造に作用する操作は頻繁に変更されます(たとえば、上記の例でレシピが頻繁に変更される場合、訪問者オブジェクトは変更されるたびに変更する必要があります)。
- 2.特定のタイプのシーンを決定するためにブランチを使用せずに、さまざまなデータタイプ(要素)を操作する必要があります。
ビジターモードの長所と短所
利点:
- 1.データ構造とデータ操作が分離されているため、操作のセットを個別に変更できます。
- 2.訪問者の役割は非常に簡単に拡張できます。
- 3.各役割は独自の義務を果たし、単一の責任の原則に準拠しています。
不利益 - 1.要素タイプを増やすことは困難です。要素タイプが変更された場合、訪問者のソースコードを変更する必要があります。これは、開閉の原則に違反し、メンテナンスに役立ちません。
- 2.この例のビジターインターフェイスなどの依存関係反転の原則に違反すると、定義されたメソッドは抽象的な要素ではなく具体的な要素に依存します。
総括する
この記事では、最も難しいデザインパターンでもあるGoFの23のデザインパターンの最後のデザインパターンを主に紹介します。これは、デザインパターンの究極のBOSSと言えます。例を使用して、訪問者パターンの書き方を示し、最後に要約を示します。ビジターモデルの役割とその長所と短所。
私に注意を払い、孤独なオオカミを学び、進歩してください。