テンプレートメソッドモード(Template Method Pattern).


定義:
操作中のアルゴリズムのフレームワークを定義し、いくつかのステップをサブクラスに遅延します.サブクラスは、アルゴリズムの構造を変更することなく、アルゴリズムの特定のステップを再定義することができる.
注意:悪意のある操作を防ぐため、一般的なテンプレートメソッドにはfinalキーワードが付けられており、上書きは許されません.
共通コード:
抽象テンプレートクラス
この方法は、次の2つに分類されます.
  • 基本方法
  • 基本メソッドは基本オペレーションとも呼ばれ,サブクラスによって実現されるメソッドであり,テンプレートメソッドで呼び出される.
  • テンプレートメソッド
  • 1つまたはいくつかあってもよく、一般的には具体的な方法、すなわちフレームワークであり、基本的な方法のスケジューリングを実現し、固定的な論理を完成する.
    public abstract class AbstractClass {
    
    //     
    
    protected abstract void doSomething();
    
    //     
    
    protected abstract void doAnything();
    
    //     
    
    public void templateMethod(){
    
    //       ,       
    
    this.doAnything();
    
    this.doSomething();
    
    }
    
    }

    テンプレートクラス
    public class ContreteClass1 extends AbstractClass {
    
    //       
    
    protected void doAnything(){
    
    //       
    
    }
    
    protected void doSomething(){
    
    //       
    
    }
    
    }

    シーンクラス
    public class Client {
    
    public static void main(String[] args) {
    
    AbstractClass class1 = new ConcreteClass1();
    
    AbstrcatClass class2 = new ConcreteClass2();
    
    //       
    
    class1.templateMethod();
    
    class2.templateMethod();
    
    }
    
    }

    注意:抽象テンプレートの基本的な方法はできるだけprotectedタイプに設計され、ディミットの法則に合致し、暴露や方法をできるだけprotectedタイプに設定しないでください.実装クラスが必要でない場合は、親のアクセス権を拡大しないようにします.
    メリット:
  • パッケージ不変部分、拡張可変部分
  • 不変部分と考えられるアルゴリズムを親実装にカプセル化し,可変部分は継承によって拡張を継続することができる.
  • 共通部分コードを抽出し、
  • のメンテナンスを容易にする.
  • 動作は親によって制御され、子は
  • を実現する.
    基本的な方法はサブクラスによって実現されるため,サブクラスは拡張によって対応する機能を増加させ,開閉の原則に合致することができる.
    欠点:
    私たちの設計習慣に従って、抽象クラスは最も抽象的で、最も一般的な物事の属性と方法を宣言し、クラスが具体的な物事の属性と方法を完成することを実現します.しかしテンプレートメソッドモードは逆転し,抽象クラスは一部の抽象メソッドを定義し,サブクラスによって実現され,サブクラス実行の結果は親クラスの結果,すなわち子クラスが親クラスに影響を及ぼし,複雑なプロジェクトではコード読解の難しさをもたらし,初心者に不快感を与える.
    シーンを使用:
  • 複数のサブクラスには共通の方法があり、論理は基本的に同じである.
  • 繰り返し、複雑なアルゴリズムは、コアアルゴリズムをテンプレートメソッドとして設計することができ、周辺の関連詳細機能は各サブクラスによって実現される.
  • 再構成の場合、テンプレートメソッドモードでよく使用されるモードで、同じコードを親クラスに抽出し、フック関数(「テンプレートメソッドモードの拡張」を参照)によって動作を制約します.
  •  

  • ケースコード:
    抽象悍馬モデル
    public abstract class HummerModel {
    
    //   ,            ,       ,      ,          ,            
    
    public abstract void start();
    
    //    ,      ,      
    
    public abstract void stop();
    
    //       ,    ,     
    
    public abstract void alarm();
    
    //         ,      
    
    public abstract void engineBoom();
    
    //         ,     ,       ,     
    
    public void run() {
    
    //    
    
    this.start();
    
    //       
    
    this.engineBoom();
    
    //        ,            ,    
    
    this.alarm();
    
    //         
    
    this.stop();
    
    }
    
    }

    H 1型ハマーモデル(H 2型ハマーモデルコードと一致、省略)
    public class HummerHiModel extends HummerModel {
    
    // H1        
    
    public void alarm() {
    
    System.out.println("  H1  ...");
    
    }
    
    //      
    
    public void engineBoom() {
    
    System.out.println("  H1        ...");
    
    }
    
    //     
    
    public void start() {
    
    System.out.println("  H1  ...");
    
    }
    
    //   
    
    public void stop() {
    
    System.out.println("  H1  ...");
    
    }
    
    }

    注意:ソフトウェア開発の過程で、同じコードが2回コピーされた場合、設計に疑問を抱く必要があります.アーキテクチャ担当者は、同じ論理が2回以上発生した理由を明確に説明します.
    シーンクラス
    public class Client {
    
    public static void main(String[] args) {
    
    // XX   H1     
    
    HummerModel h1 = new HummerH1Model();
    
    // H1    
    
    h1.run();
    
    }
    
    }

    テンプレート方式の拡張:
    環境シミュレーション:
    H 1型のハマーホーンは鳴らそうとすると鳴りますが、H 2型のホーンは音がしないでください.
    拡張された抽象テンプレートクラス
    public abstract class HummerModel {
    
    //   ,            ,       ,      ,          ,            
    
    public abstract void start();
    
    //    ,      ,      
    
    public abstract void stop();
    
    //       ,    ,     
    
    public abstract void alarm();
    
    //         ,      
    
    public abstract void engineBoom();
    
    //         ,     ,       ,     
    
    public void run() {
    
    //    
    
    this.start();
    
    //       
    
    this.engineBoom();
    
    //        ,            ,    
    
    if(this.isAlarm()) {
    
    this.alarm();
    
    }
    
    //         
    
    this.stop();
    
    }
    
    //     ,        
    
    protected boolean isAlarm() {
    
    return true;
    
    }
    
    }

    isAlarm()は実装方法である.テンプレートメソッドは、その戻り値に基づいてラッパを鳴らすかどうかを決定し、サブクラスはメソッド値を上書きすることができる.
    拡張後のH 1ハマー
    public class HummerHiModel extends HummerModel {
    
    private boolean alarmFlag = true; //     
    
    // H1        
    
    public void alarm() {
    
    System.out.println("  H1  ...");
    
    }
    
    //      
    
    public void engineBoom() {
    
    System.out.println("  H1        ...");
    
    }
    
    //     
    
    public void start() {
    
    System.out.println("  H1  ...");
    
    }
    
    //   
    
    public void stop() {
    
    System.out.println("  H1  ...");
    
    }
    
    protected boolean isAlarm() {
    
    reuturn this.alarmFlag;
    
    }
    
    //       ,        
    
    public void setAlarm(boolean isAlarm) {
    
    this.alarmFlag = isAlarm;
    
    }
    
    }

    広がるH 2ハマー
    public class Hummer2HiModel extends HummerModel {
    
    private boolean alarmFlag = true; //     
    
    // H1        
    
    public void alarm() {
    
    System.out.println("  H1  ...");
    
    }
    
    //      
    
    public void engineBoom() {
    
    System.out.println("  H1        ...");
    
    }
    
    //     
    
    public void start() {
    
    System.out.println("  H1  ...");
    
    }
    
    //   
    
    public void stop() {
    
    System.out.println("  H1  ...");
    
    }
    
    //        
    
    protected boolean isAlarm() {
    
    reuturn false;
    
    }
    
    }

    我々の抽象クラスにおけるisAlarmの戻り値はテンプレートメソッドの実行結果に影響し,このメソッドをフックメソッド(HookMethod)と呼ぶ.
    テンプレートメソッドモードとは、テンプレートメソッドにおいて一定のルールと順序で基本メソッドを呼び出すことであり、具体的には前述の例では、run()メソッドが所定の順序で本クラスの他のメソッドを呼び出し、isAlarm()メソッドの戻り値によってrun()における実行順序変更を決定する.
    ベストプラクティス:
    親クラスは子クラスのメソッドを呼び出すことができますか?答えはできるが、強く、極度にそうすることを提案しないなら、どうすればいいのだろうか.
  • は、子クラスを親クラスのパラメトリック構造に渡し、呼び出す.
  • 反射方式で呼び出されますが、反射を使用して誰が呼び出せませんか?
  • 親クラスが子クラスを呼び出す静的メソッド.

  • 親はフレームワークを構築し、子は親セクションのメソッドを書き換えた後、親から継承するメソッドを呼び出し、異なる結果を生成します(これはテンプレートメソッドモードです).これは親が子を呼び出した方法としても理解できるのではないでしょうか.あなたはサブクラスを修正して、親の行為の結果に影響して、曲線は国を救う方式で親がサブクラスに依存するシーンを実現して、テンプレートの方法のモードはこのような効果です.
    「xxx In Action」では、拡張機能が必要な場合は、この抽象クラスを継承し、protectedメソッドを上書きし、executeメソッドのようなメソッドを呼び出すことで、拡張開発を完了し、非常に拡張しやすいモードについて説明しています.