この記事では、Java の戦略パターンとテンプレート メソッド パターンを紹介します (コード付き)。必要な方は参考にしていただければ幸いです。
戦略パターン
はじめに
戦略パターンは、オブジェクトの動作パターンに属します。その目的は、各アルゴリズムを一連のアルゴリズムの共通インターフェイスを持つ独立したクラスにカプセル化して、相互に置き換えることができるようにすることです。戦略パターンにより、クライアントに影響を与えることなくアルゴリズムを変更できます。
主な目的は、同様のアルゴリズムを定義することで if else ステートメントの記述を置き換えることであり、いつでも相互に置き換えることができます。
戦略モードは主に環境役割(Context)、抽象戦略役割(Strategy)、具体戦略役割(ConcreteStrategy)の3つの役割で構成されます。
環境ロール (コンテキスト): 戦略クラスへの参照を保持し、それをクライアントに提供します。
抽象戦略ロール (戦略): これは抽象ロールであり、通常はインターフェイスまたは抽象クラスによって実装されます。この役割は、特定のポリシー クラスに必要なすべてのインターフェイスを提供します。
コンクリート戦略ロール (ConcreteStrategy): 関連するアルゴリズムまたは動作をパッケージ化します。
電卓を使った計算では、足し算、引き算、掛け算、割り算がよく使われます。 2 つの数値の加算の合計を取得するには「」記号を使用する必要があり、減算の差を取得するには「-」記号を使用する必要があります。文字列比較による if/else を使用した一般的なメソッドを作成できますが、計算シンボルが追加されるたびに、後続の計算メソッドが追加、変更、削除されると、対応するコードを元のメソッドに追加する必要があります。その後のメンテナンスが困難になります。
しかし、これらの手法のうち、現時点では基本的な手法が固定されており、後から他の計算ルールを追加しても、if/else による判断を効果的に回避できることがわかりました。調整を行います。
interface CalculateStrategy { int doOperation(int num1, int num2); }
class OperationAdd implements CalculateStrategy { @Override public int doOperation(int num1, int num2) { return num1 + num2; } } class OperationSub implements CalculateStrategy { @Override public int doOperation(int num1, int num2) { return num1 - num2; } } class OperationMul implements CalculateStrategy { @Override public int doOperation(int num1, int num2) { return num1 * num2; } } class Operationp implements CalculateStrategy { @Override public int doOperation(int num1, int num2) { return num1 / num2; } }
コードは次のとおりです:
class CalculatorContext { private CalculateStrategy strategy; public CalculatorContext(CalculateStrategy strategy) { this.strategy = strategy; } public int executeStrategy(int num1, int num2) { return strategy.doOperation(num1, num2); } }
テストコードは次のとおりです:
public static void main(String[] args) { int a=4,b=2; CalculatorContext context = new CalculatorContext(new OperationAdd()); System.out.println("a + b = "+context.executeStrategy(a, b)); CalculatorContext context2 = new CalculatorContext(new OperationSub()); System.out.println("a - b = "+context2.executeStrategy(a, b)); CalculatorContext context3 = new CalculatorContext(new OperationMul()); System.out.println("a * b = "+context3.executeStrategy(a, b)); CalculatorContext context4 = new CalculatorContext(new Operationp()); System.out.println("a / b = "+context4.executeStrategy(a, b)); }
出力結果:
a + b = 6 a - b = 2 a * b = 8 a / b = 2
ストラテジーモードの利点:
優れたスケーラビリティ。オブジェクト構造を変更せずに新しいクラスを追加して新しいアルゴリズムを実装できます。
優れた柔軟性。アルゴリズムを自由に切り替えることができます。
ストラテジー モードの欠点:
#使用シナリオ:より多くのストラテジー クラスを使用すると、システムの複雑さが増加します。 ;
#クライアントは呼び出す前にすべてのポリシー クラスを知っている必要があります;
#システム内に多数のクラスがあり、それらの唯一の違いがその動作である場合、ストラテジ パターンを使用すると、オブジェクトが多数の動作の中から 1 つの動作を動的に選択できるようになります。システムは、いくつかのアルゴリズムから 1 つを動的に選択する必要があります。
#オブジェクトに適切なパターンがない多くの動作がある場合、これらの動作を実現するには、複数の条件付き選択ステートメントを使用する必要があります。
テンプレート パターン
はじめに
テンプレート モードの主なアイデアは、テンプレートを作成し、それを呼び出し用にクライアントに提供することです。私たちが日常生活で頻繁に使用する履歴書テンプレート、契約書テンプレートなどに加えて、Java で使用される非常に古典的なテンプレート、つまり Servlet もあります。HttpService クラスには、7 つの do のうちの 1 つを呼び出す service() メソッドが用意されています。メソッドまたはクライアント呼び出しに対する複数の完全な応答。これらの do メソッドは、HttpServlet の特定のサブクラスによって提供される必要があります。
テンプレート モード主に、抽象テンプレート ロールと具象テンプレート ロールで構成されます。
抽象模板(Abstract Template): 定义了一个或多个抽象操作,以便让子类实现。这些抽象操作叫做基本操作,它们是一个顶级逻辑的组成步骤;定义并实现了一个模板方法。这个模板方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。顶级逻辑也有可能调用一些具体方法。
具体模板(Concrete Template): 实现父类所定义的一个或多个抽象方法,它们是一个顶级逻辑的组成步骤;每一个抽象模板角色都可以有任意多个具体模板角色与之对应,而每一个具体模板角色都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各不相同。
示例图如下:
这里为了方便理解,我们依旧使用一个简单的示例来加以说明。
我们以前在玩魂斗罗、双截龙、热血物语、忍者神龟等等游戏的时候,都需要在小霸王游戏机上插卡,然后启动游戏才能玩,其中魂斗罗这种游戏,启动游戏之后就可以直接玩了,但是忍者神龟这种游戏则在启动游戏之后,需要选择其中一个角色才能开始玩。那么我们可以根据这个场景写出一个通用的模板,主要包含启动游戏,玩游戏,结束游戏这几个必须实现的方法,选择人物这个方法改成可选。那么这个抽象类的代码如下:
abstract class Game{ //启动游戏 protected abstract void runGame(); //选择人物 protected void choosePerson() {}; //开始玩游戏 protected abstract void startPlayGame(); //结束游戏 protected abstract void endPlayGame(); //模板方法 public final void play() { runGame(); choosePerson(); startPlayGame(); endPlayGame(); } }ログイン後にコピー定义好该抽象类之后,我们再来定义具体模板实现类。这里定义两个游戏类,一个是魂斗罗,一个忍者神龟。
那么代码如下:
class ContraGame extends Game{ @Override protected void runGame() { System.out.println("启动魂斗罗II..."); } @Override protected void startPlayGame() { System.out.println("1P正在使用S弹打aircraft..."); } @Override protected void endPlayGame() { System.out.println("1P被流弹打死了,游戏结束!"); } } class TMNTGame extends Game{ @Override protected void runGame() { System.out.println("启动忍者神龟III..."); } @Override protected void choosePerson() { System.out.println("1P选择了Raph !"); } @Override protected void startPlayGame() { System.out.println("Raph正在使用绝技 “火箭头槌” "); } @Override protected void endPlayGame() { System.out.println("Raph 掉进井盖里死了,游戏结束了! "); } }ログイン後にコピー最后再来进行测试,测试代码如下:
public static void main(String[] args) { Game game = new ContraGame(); game.play(); System.out.println(); game = new TMNTGame(); game.play(); }ログイン後にコピー输出结果:
启动魂斗罗II...1P正在使用S弹打aircraft...1P被流弹打死了,游戏结束! 启动忍者神龟III...1P选择了Raph ! Raph正在使用绝技 “火箭头槌” Raph 掉进井盖里死了,游戏结束了!ログイン後にコピー模板模式优点:
扩展性好,对不变的代码进行封装,对可变的进行扩展;
可维护性好,因为将公共代码进行了提取,使用的时候直接调用即可;模板模式缺点:
因为每一个不同的实现都需要一个子类来实现,导致类的个数增加,会使系统变得复杂;
使用场景:
有多个子类共有逻辑相同的方法;
重要的、复杂的方法,可以考虑作为模板方法。注意事项:
为防止恶意操作,一般模板方法都加上 final 关键词!
以上がJava のストラテジー パターンとテンプレート メソッド パターンの紹介 (コード付き)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。