最有用的设计模式之一-模板方法

今天是设计模式学习系列的第9篇,为大家带来一个使用特别广的设计模式 – 模板方法模式

从问题出发

  1. 什么是模板方法模式?
  2. 常说的钩子方法是什么?和模板方法的关联?
  3. 模板方法模式和策略模式好像有点像,如何区分?
  4. JDK 中的具体体现?

模式解析

一如既往的为了方便理解,我们从一个日常开发中的例子出发。
做保险系统的都知道,保险分为很多种类,比如:产险、寿险、养老险、健康险、车险等。 我们作为后台开发者在设计开发这些保险产品上线的时候,首先要分析下这几个险种购买流程的共同点?

这些保险在产品购买时的流程如下(举个例子,实际情况有所差异,核心流程属于公司机密,必须严格保密,开个玩笑啦!):

健康险、产险、养老险、寿险、车险:

  1. 保费试算
  2. 健康告知(车险没有,是检验车牌)
  3. 核保
  4. 支付(统一的)
  5. 承保

可以看到,核心的购买流程是非常相似的,但是不同的险种具体实现是不一样的,比如健康险和产险他们健康告知的内容就是不一样的。

如果直接搞定几个对应的类实现,肯定会存在很多重复的代码,如果让你来设计,肯定第一个想法就是定义一个超类,将共同的方法放在其中,然后购买 createOrder() 方法由于在子类(车险和产寿养健)中的流程调用方法是不一样的,所以定义成抽象,然后例子中的健康告知等方法是不公用的所以放到具体的子类中。

但是这样的设计,还是可以优化的,因为投保下单的流程各个险种基本上是一样的,至于每个险种可能在每个步骤上的实现不一样,我们可以将其抽象化。比如将健康告知和检验车牌统一抽象成 check() 方法。 这样一来新的 createOrder() 方法看起来就是这样:

void createOrder() {
    
    
    calculate();
    check();
    underwriting();
    pay();
    accept();
}

然后我们在超类中将公用的方法实现,然后 不一样的方法 我们定义为抽象,推迟到子类去实现,比如 check() 方法,就放到对应的 车险 和 寿险等子类中去各自实现,这样一来就简化了代码,实现了复用。

认识模板方法

基本的に、ここで示した例はテンプレートメソッドパターンです。上記の保険基本クラスのcreateOrder()は、テンプレートメソッドです。何故ですか?

なぜなら:

  1. 結局それはメソッドです。
  2. これは、アルゴリズムのテンプレートとして使用されます。この例では、アルゴリズムを使用して、損害保険の申請プロセスを完了します。

このテンプレートでは、アルゴリズムの各ステップはメソッドによって表されます。一部のメソッドはこのクラス(スーパークラス)によって処理され、一部のメソッドはサブクラスによって処理されます。サブクラスで提供する必要のあるメソッドは、スーパークラスで抽象として宣言する必要があります。

テンプレートメソッドパターンの定義

テンプレートメソッドパターンは、メソッドのアルゴリズムのスケルトンを定義し、サブクラスへのいくつかのステップを遅らせます。テンプレートメソッドを使用すると、サブクラスはアルゴリズムの構造を変更せずに、アルゴリズムの特定のステップを再定義できます。

このモードでは、アルゴリズムの構造が変更されないままであり、実装の一部がサブクラスによって提供されることが保証されます。次のクラス図を見てみましょう。

ここに画像の説明を挿入

テンプレートメソッドは何をもたらすか

  1. すべてがAbstractClassクラスによって支配されており、アルゴリズムは不変です。
  2. サブクラスの場合、AbstractClassの存在により、コードの再利用を最大化できます。
  3. アルゴリズムは1か所にしか存在しないため、変更は簡単です。
  4. このテンプレートメソッドは、独自のメソッドを実装する限り、他の保険クラスの追加など、他のサブクラスを挿入できるフレームワークを提供します。
  5. AbstractClassクラスはアルゴリズム自体に焦点を当てていますが、サブクラスは完全な実装を提供します。

フック方式とは

これまでにフックについて聞いたことがあると思いますが、いつでも理解できないかもしれません。これは、抽象クラスで宣言されたメソッドですが、空またはデフォルトの実装しかありませんフックの存在により、サブクラスはアルゴリズムのさまざまなポイントをフックすることができます。フックするかどうかは、サブクラスによって決まります。

たとえば、上で定義した保険アルゴリズムcreateOrder()は、新しいメソッド呼び出しが追加され、テンプレートメソッドが変更されることを前提としています。ただし、このメソッドをすべてのサブクラスで実装する必要はありません。この選択の機能をサブクラスの選択に与える場合は、このメソッドをスーパークラスで空のメソッドまたはデフォルトの実装として定義できます。サブクラスはオーバーライドを選択できますが、それが行われなければならない、これはフックが行うことです。

テンプレート方式と戦略モードの違いは何ですか?

戦略モードについては最初の記事で説明しましたが、覚えていない友達がたくさんいるので、繰り返しになります。戦略モードはアルゴリズムのファミリーを定義し、これらのアルゴリズムを交換可能にします。各アルゴリズムはカプセル化されているため、顧客はさまざまなアルゴリズムを簡単に使用できます。

どちらもアルゴリズムをカプセル化しますが、意図は異なります。テンプレートメソッドの仕事はアルゴリズムの概要を定義することであり、サブクラスはいくつかのステップの内容を定義します。これにより、個々のステップの実装の詳細を変更できますが、アルゴリズムの構造は変わりませんそのまま。ただし、戦略モードでは、組み合わせ委譲の方法を使用します。これにより、顧客はオブジェクトの組み合わせを通じてアルゴリズムの実装を選択できます。

つまり、テンプレートメソッドはアルゴリズムをより細かく制御でき、コードを繰り返す必要はありません。一般に、テンプレートメソッドはより効率的であり、戦略モードはより柔軟で柔軟です。

テンプレートメソッド周り

  1. Java配列によって提供される並べ替えは、テンプレートメソッドstatic Arrays.sort(Object [])です。特定の実装では、JDKソースコードを確認できます。簡単に言えば、並べ替えはテンプレートメソッドであり、compareTo()をカスタマイズする必要があります。テンプレートメソッドの欠陥を「埋める」ために使用されるメソッド。
  2. Java同時実行パッケージのコア、AbstactQueuedSynchronizer(略してAQS)、ソースコードは、誰もが今日学んだテンプレートメソッドをチェックおよび検証することを期待されています。簡単な説明は、提供されるacquire()メソッドがロックの取得に使用されますが、特定のロック実装が必要です。このクラスは、tryAcquire()メソッドをカスタマイズしてロック取得プロセスを完了します。つまり、このフックとAQSロック取得アルゴリズムを使用してフックします。これは非常に古典的です。

ナイトトーク

  • 「テンプレートメソッド」は、アルゴリズムのステップを定義し、これらのステップの実装をサブクラスに遅らせます。
  • テンプレートメソッドパターンは、コードを再利用するための重要な手法を提供します。
  • テンプレートメソッドの抽象クラスは、具象メソッド、抽象メソッド、およびフックを定義できます。
  • 抽象メソッドはサブクラスによって実装されます。
  • フックは、抽象クラスで何も行わないか、デフォルトの処理のみを行うメソッドであり、サブクラスはそれをオーバーライドするかどうかを選択できます。
  • サブクラスがテンプレートメソッドのアルゴリズムを変更しないようにするために、テンプレートメソッドをfinalとして定義できます。
  • 戦略モードとテンプレートメソッドモードの両方がアルゴリズムをカプセル化します。1つは組み合わせを使用し、もう1つは継承を使用します。
  • ファクトリメソッドはテンプレートメソッドの特別なバージョンであり、本来の目的はオブジェクトを作成して返すことです。

みんなが稼げることを願っています!

個人公開口座

ここに画像の説明を挿入

  • 彼らが上手に書いていると感じている友人は気に入ることができて、フォローすることができます
  • 記事が正しくない場合は、指摘してください。読んでいただきありがとうございます。
  • 私は公式アカウントに注意を払うことをお勧めします。私は定期的にオリジナルの乾物記事をプッシュし、あなたを高品質の学習コミュニティに引き込みます。
  • githubアドレス:github.com/coderluojust/qige_blogs

おすすめ

転載: blog.csdn.net/taurus_7c/article/details/107584205