デザインパターン-テンプレートメソッドデザインパターン

1はじめに

オブジェクト指向プログラミングの過程で、プログラマーはしばしばこの状況に遭遇します。システムを設計するとき、彼らはアルゴリズムに必要な主要なステップを知っており、これらのステップの実行順序を決定しますが、いくつかのステップの具体的な実装はまだ不明です。言い換えれば、特定のステップの実現は、特定の環境に関連しています。

たとえば、銀行に行ってビジネスを処理するには、通常、番号の取得、キューイング、特定のビジネスの処理、銀行スタッフのスコアリングなどの4つのプロセスが必要です。番号の取得、キューイング、銀行スタッフのスコアリングのビジネスは、顧客ごとに行われます。親クラスで実施されますが、処理される特定のビジネスは人によって異なります。それは、サブクラスに遅れる可能性がある預金、引き出し、または転送などである可能性があります。

そのような例は生活の中にたくさんあります。たとえば、人は毎日起きて、食べて、物事をして、寝て、「物事をする」という内容は毎日違うかもしれません。これらのプロセスまたは形式の例をテンプレートとして定義し、ユーザーが履歴書テンプレート、紙のテンプレート、Wordのテンプレートファイルなど、自分のニーズに応じてそれらを更新できるようにします。

以下に紹介するテンプレートメソッドモードは、上記の同様の問題を解決します

2.モデルの定義と特徴

テンプレートメソッド(テンプレートメソッド)モードは次のように定義されます。操作でアルゴリズムスケルトンを定義し、アルゴリズムの一部のステップをサブクラスに遅延させて、サブクラスがアルゴリズム固有の構造を変更せずにアルゴリズムの一部を再定義できるようにします。手順。それは一種の行動パターンです。

このモードの主な利点は次のとおりです。

  1. 不変部分をカプセル化し、可変部分を展開します。不変部分と見なされるアルゴリズムを親クラスにカプセル化し、サブクラスからの継承によって可変部分アルゴリズムを実装します。これは、サブクラスが拡張し続けるのに便利です。
  2. 親クラスのコードの共通部分を抽出して、コードの再利用を容易にします。
  3. 一部のメソッドはサブクラスによって実装されるため、サブクラスは、開閉の原則に準拠する拡張機能を介して対応する関数を追加できます。

このモデルの主な欠点は次のとおりです。

  1. 実装ごとに、サブクラスを定義する必要があります。これにより、クラスの数が増え、システムが大きくなり、設計がより抽象的になり、間接的にシステム実装の複雑さが増します。
  2. 親クラスの抽象メソッドはサブクラスによって実装され、サブクラスの実行結果は親クラスの結果に影響を与え、逆制御構造になり、コードの読み取りが困難になります。
  3. 継承関係の欠点により、親クラスが新しい抽象メソッドを追加した場合、すべてのサブクラスを再度変更する必要があります。

3.パターンの構造と実現

テンプレートメソッドパターンでは、抽象クラスと具象サブクラスの間のコラボレーションに注意を払う必要があります。仮想関数のポリモーフィズム技術と「電話しないで、電話させて」という逆制御技術を利用しています。それでは、その基本的な構造を紹介しましょう。

1.モデルの構造

テンプレートメソッドパターンには、次の主な役割が含まれています。

1)抽象クラス/抽象テンプレート(抽象クラ​​ス)

抽象テンプレートクラスは、アルゴリズムの概要とスケルトンを提供する役割を果たします。これは、テンプレートメソッドといくつかの基本的なメソッドで構成されています。これらのメソッドの定義は次のとおりです。

①テンプレートメソッド:アルゴリズムのスケルトンを定義し、それに含まれる基本的なメソッドを特定の順序で呼び出します。
②基本的な方法:以下のタイプを含むアルゴリズム全体のステップです。

  • 抽象メソッド:抽象クラスで宣言され、具象サブクラスによって実装されます。
  • 具象メソッド:抽象クラスに実装されており、具象サブクラスで継承または書き換えることができます。
  • フックメソッド:判断のための論理メソッドやサブクラスで書き直す必要のある空のメソッドなど、抽象クラスに実装されています。

2)コンクリートサブクラス/コンクリートクラス

具象実現クラスは、抽象クラスで定義された抽象メソッドとフックメソッドを実装し、トップレベルロジックの構成ステップです。

ここに画像の説明を挿入します

2.パターンの実装

public class TemplateMethodPattern {
    
    
    public static void main(String[] args) {
    
    
        AbstractClass tm = new ConcreteClass();
        tm.TemplateMethod();
    }
}

//抽象类
abstract class AbstractClass {
    
    
    //模板方法
    public void TemplateMethod() {
    
    
        SpecificMethod();
        abstractMethod1();
        abstractMethod2();
    }

    //具体方法
    public void SpecificMethod() {
    
    
        System.out.println("抽象类中的具体方法被调用...");
    }

    //抽象方法1
    public abstract void abstractMethod1();

    //抽象方法2
    public abstract void abstractMethod2();
}

//具体子类
class ConcreteClass extends AbstractClass {
    
    
    public void abstractMethod1() {
    
    
        System.out.println("抽象方法1的实现被调用...");
    }

    public void abstractMethod2() {
    
    
        System.out.println("抽象方法2的实现被调用...");
    }
}

抽象クラスの具象メソッドが呼び出されます...
抽象メソッド1
の実装が呼び出されます...抽象メソッド2の実装が呼び出されます...

3.パターンの適用例

【例1】テンプレートメソッドモデルを使用して、留学手順の設計手順を実現します。

分析:留学の手続きは、一般的に次のプロセスを経ます:学校情報の要求、入学申請書の提出、パスポート、出口カードの取り扱い、個人旅行の公証、ビザの申請、身体検査、航空券の予約、荷物の準備、到着対象校等で。学校は同じですが、事業によっては学校ごとに異なるため、テンプレートメソッドモデルを使用する方が適しています。

この例では、最初に留学用の抽象クラスStudyAbroadを定義します。これには、留学の手順を実行するプロセスのすべての基本メソッドを含むテンプレートメソッドTemplateMethod()が含まれます。一部のメソッドは異なる方法で処理されます。国。同じなので、抽象クラスで実装できますが、一部のメソッドは国によって異なり、特定のサブクラス(StudyInAmericaなど)で実装する必要があります。別の国を追加する場合は、サブカテゴリを追加するだけで済みます。図2にその構造を示します。

ここに画像の説明を挿入します

public class StudyAbroadProcess {
    
    
    public static void main(String[] args) {
    
    
        StudyAbroad tm = new StudyInAmerica();
        tm.TemplateMethod();
    }
}

//抽象类: 出国留学
abstract class StudyAbroad {
    
    
    public void TemplateMethod() //模板方法
    {
    
    
        LookingForSchool(); //索取学校资料
        ApplyForEnrol();    //入学申请
        ApplyForPassport(); //办理因私出国护照、出境卡和公证
        ApplyForVisa();     //申请签证
        ReadyGoAbroad();    //体检、订机票、准备行装
        Arriving();         //抵达
    }

    public void ApplyForPassport() {
    
    
        System.out.println("三.办理因私出国护照、出境卡和公证:");
        System.out.println("  1)持录取通知书、本人户口簿或身份证向户口所在地公安机关申请办理因私出国护照和出境卡。");
        System.out.println("  2)办理出生公证书,学历、学位和成绩公证,经历证书,亲属关系公证,经济担保公证。");
    }

    public void ApplyForVisa() {
    
    
        System.out.println("四.申请签证:");
        System.out.println("  1)准备申请国外境签证所需的各种资料,包括个人学历、成绩单、工作经历的证明;个人及家庭收入、资金和财产证明;家庭成员的关系证明等;");
        System.out.println("  2)向拟留学国家驻华使(领)馆申请入境签证。申请时需按要求填写有关表格,递交必需的证明材料,缴纳签证。有的国家(比如美国、英国、加拿大等)在申请签证时会要求申请人前往使(领)馆进行面试。");
    }

    public void ReadyGoAbroad() {
    
    
        System.out.println("五.体检、订机票、准备行装:");
        System.out.println("  1)进行身体检查、免疫检查和接种传染病疫苗;");
        System.out.println("  2)确定机票时间、航班和转机地点。");
    }

    public abstract void LookingForSchool();//索取学校资料

    public abstract void ApplyForEnrol();   //入学申请

    public abstract void Arriving();        //抵达
}

//具体子类: 美国留学
class StudyInAmerica extends StudyAbroad {
    
    
    @Override
    public void LookingForSchool() {
    
    
        System.out.println("一.索取学校以下资料:");
        System.out.println("  1)对留学意向国家的政治、经济、文化背景和教育体制、学术水平进行较为全面的了解;");
        System.out.println("  2)全面了解和掌握国外学校的情况,包括历史、学费、学制、专业、师资配备、教学设施、学术地位、学生人数等;");
        System.out.println("  3)了解该学校的住宿、交通、医疗保险情况如何;");
        System.out.println("  4)该学校在中国是否有授权代理招生的留学中介公司?");
        System.out.println("  5)掌握留学签证情况;");
        System.out.println("  6)该国政府是否允许留学生合法打工?");
        System.out.println("  8)毕业之后可否移民?");
        System.out.println("  9)文凭是否受到我国认可?");
    }

    @Override
    public void ApplyForEnrol() {
    
    
        System.out.println("二.入学申请:");
        System.out.println("  1)填写报名表;");
        System.out.println("  2)将报名表、个人学历证明、最近的学习成绩单、推荐信、个人简历、托福或雅思语言考试成绩单等资料寄往所申请的学校;");
        System.out.println("  3)为了给签证办理留有充裕的时间,建议越早申请越好,一般提前1年就比较从容。");
    }

    @Override
    public void Arriving() {
    
    
        System.out.println("六.抵达目标学校:");
        System.out.println("  1)安排住宿;");
        System.out.println("  2)了解校园及周边环境。");
    }
}

1.学校から次の情報を入手します
。1)留学先の国の政治的、経済的、文化的背景、教育システム、および学業レベルをより包括的に理解している
。2)を包括的に理解し、習得している。歴史、授業料、学校制度、専攻、教員、教育施設、学歴、学生数などを含む外国の学校の状況;
3)
学校の宿泊施設、交通機関、医療保険を知っている; 4)学校には、中国で学生を募集することを許可されている海外の研究機関がありますか?
5)学生ビザのステータスを知っている;
6)国の政府は留学生が合法的に働くことを許可していますか?
8)卒業後の移民はできますか?
9)卒業証書は私の国で認められていますか?
2.入学願書:
1)登録フォームに記入します
。2)登録フォーム、個人の成績証明書、最近の成績証明書、推薦状、履歴書、TOEFLまたはIELTS言語テストの成績証明書およびその他の資料を申請した学校に送信します
。3 )ビザの処理に十分な時間をかけるために、できるだけ早く申請することをお勧めします。通常、1年前にリラックスしてください。
3.
プライベートパスポート、出口カード、公証を申請します。1)プライベートパスポートと出口カードを、入国通知、世帯登録簿、またはIDカードで居住地が登録されている公安調査庁に申請します。
2)出生証明書の公証、教育、学位および学年の公証、経験証明書、親族の公証、および経済的保証の公証。
4.ビザの申請:
1)個人教育の証明、成績証明書、実務経験、個人および家族の収入、資金および財産の証明、家族の関係の証明など、外国ビザの申請に必要なあらゆる種類の資料を準備します。 、等;
2)中国に留学する予定の国の大使館(領事館)への入国ビザを申請してください。申請する際には、関連するフォームに記入し、必要な補足資料を提出し、必要に応じてビザを支払う必要があります。一部の国(米国、英国、カナダなど)では、ビザを申請する際に、申請者は大使館(領事館)に面接に行く必要があります。
V.身体検査、航空券の予約、梱包の準備:
1)身体検査、予防接種チェック、感染症の予防接種を実施します
。2)航空券の時刻、フライト、乗り換え場所を決定します。
6.対象の学校に到着します:
1)宿泊施設を手配します;
2)キャンパスと周辺環境を理解します。

4.モードのアプリケーションシナリオ

テンプレートメソッドパターンは通常、次のシナリオに適しています

  1. アルゴリズムの全体的な手順は非常に固定されていますが、それらの個々の部分が変更可能である場合、この時点でテンプレートメソッドパターンを使用して、サブクラスが実装する変更可能な部分を抽象化できます。
  2. 複数のサブクラスに共通の動作がある場合、コードの重複を避けるために、それらを抽出して共通の親クラスに集中させることができます。まず、既存のコードの違いを特定し、違いを新しい操作に分けます。最後に、これらの異なるコードを、これらの新しい操作を呼び出すテンプレートメソッドに置き換えます。
  3. サブクラスの拡張を制御する必要がある場合、テンプレートメソッドは特定のポイントでのみフック操作を呼び出すため、拡張はこれらのポイントでのみ許可されます。

5.モデルの拡張

テンプレートメソッドパターンの基本的なメソッドには、抽象メソッド、具象メソッド、フックメソッドがあります。「フックメソッド」を正しく使用すると、子クラスで親クラスの動作を制御できます。次の例のように、具象サブクラスのフックメソッドHookMethod1()とHookMethod2()をオーバーライドすることで、抽象親クラスの実行結果を変更できます。構造図を図3に示します。

ここに画像の説明を挿入します

public class HookTemplateMethod {
    
    
    public static void main(String[] args) {
    
    
        HookAbstractClass tm = new HookConcreteClass();
        tm.TemplateMethod();
    }
}

//含钩子方法的抽象类
abstract class HookAbstractClass {
    
    
    //模板方法
    public void TemplateMethod() {
    
    
        abstractMethod1();
        HookMethod1();
        if (HookMethod2()) {
    
    
            SpecificMethod();
        }
        abstractMethod2();
    }

    //具体方法
    public void SpecificMethod() {
    
    
        System.out.println("抽象类中的具体方法被调用...");
    }

    //钩子方法1
    public void HookMethod1() {
    
    
    }

    //钩子方法2
    public boolean HookMethod2() {
    
    
        return true;
    }

    //抽象方法1
    public abstract void abstractMethod1();

    //抽象方法2
    public abstract void abstractMethod2();
}

//含钩子方法的具体子类
class HookConcreteClass extends HookAbstractClass {
    
    
    public void abstractMethod1() {
    
    
        System.out.println("抽象方法1的实现被调用...");
    }

    public void abstractMethod2() {
    
    
        System.out.println("抽象方法2的实现被调用...");
    }

    public void HookMethod1() {
    
    
        System.out.println("钩子方法1被重写...");
    }

    public boolean HookMethod2() {
    
    
        return false;
    }
}

抽象メソッド1の実装が呼び出されます...
フックメソッド1が書き直されます...
抽象メソッド2の実装が呼び出されます...

おすすめ

転載: blog.csdn.net/saienenen/article/details/112652825