テンプレートメソッドパターン
動作中のアルゴリズムのフレームワークを定義し、サブクラスへのいくつかのステップを遅らせます。テンプレートメソッドパターンを使用すると、サブクラスは、アルゴリズムの構造を変更せずに、アルゴリズムの特定のステップを再定義できます。これは、継承と動作モデルに基づくコード再利用テクノロジーです。
クラス図
成し遂げる
抽象クラス
一連の基本操作が定義されています。これらの基本操作は具体的または抽象的です。各基本操作はアルゴリズムのステップに対応し、これらのステップはそのサブクラスで再定義または実装できます。同時に、アルゴリズムフレームワークを定義するために、テンプレートメソッドが抽象クラスに実装されます。テンプレートメソッドは、抽象クラスに実装された基本メソッドだけでなく、抽象クラスのサブクラスに実装された基本メソッドも呼び出すことができます。また、他のオブジェクトのメソッドを呼び出すこともできます
package design.templatemethod.realize;
/*
*
*@author:zzf
*@time:2020-12-21
*
*/
public abstract class AbstractClass {
//模板方法
public void templateMethod(){
}
//基本方法——具体方法
public void primitiveOperation1(){
}
//基本方法——抽象方法
public abstract void primitiveOperation2();
//基本方法——钩子方法
public void primitiveOperation3(){
}
}
具体的なサブカテゴリ
package design.templatemethod.realize;
/*
*
*@author:zzf
*@time:2020-12-21
*
*/
public class ConcreteClass extends AbstractClass {
@Override
public void primitiveOperation2() {
//实现
}
@Override
public void primitiveOperation3() {
//实现
}
}
アプリケーション
ソフトウェア会社は、銀行のビジネスサポートシステム用の利息計算モジュールを開発したいと考えています。利息計算プロセスは次のとおりです。
(1)システムは、口座番号とパスワードに従ってユーザー情報を検証します。ユーザー情報が間違っている場合は、システムはエラーメッセージを表示します。
(2)ユーザー情報が正しければ、さまざまな利息計算式を使用して、さまざまなユーザータイプに応じて利息を計算します(たとえば、当座預金口座と定期口座の利息計算式は異なります)。
(3)システムは関心を示します。
次に、テンプレートメソッドモデルを使用して、利息計算モジュールを設計します。
コード
抽象クラスとして機能するアカウントクラス
package design.templatemethod;
public abstract class Accout {
// 基本方法:具体方法
public boolean validata(String account, String password) {
System.out.println("账号:" + account);
System.out.println("密码:" + password);
if (account.equalsIgnoreCase("张无忌") && password.equalsIgnoreCase("123456")) {
return true;
} else {
return false;
}
}
// 基本方法:抽象方法
public abstract void calculateInterst();
// 基本方法:具体方法
public void display() {
System.out.println("显示利息!");
}
// 模板方法
public void handle(String account, String password) {
if (!validata(account, password)) {
System.out.println("账户或密码错误!");
return;
}
calculateInterst();
display();
}
}
具体的なサブカテゴリ
package design.templatemethod;
public class CurrentAccount extends Accout {
// 覆盖父类抽象基本方法
public void calculateInterst() {
System.out.println("按活期利率计算利息!");
}
}
package design.templatemethod;
public class SavingAccount extends Accout {
@Override
public void calculateInterst() {
System.out.println("按定期利率计算利息!");
}
}
構成ファイル
<?xml version="1.0" encoding="UTF-8"?>
<config>
<className>design.templatemethod.CurrentAccount</className>
</config>
ツール
package design.templatemethod;
import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class XMLUtil {
public static Object getBean() {
try {
// 创建DOM文档对象
DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dFactory.newDocumentBuilder();
Document doc;
doc = builder.parse(new File("src//design//templatemethod//config.xml"));
// 获取包含类名的文本节点
NodeList nl = doc.getElementsByTagName("className");
Node classNode = nl.item(0).getFirstChild();
String cName = classNode.getNodeValue();
// 通过类名生成实例对象
Class c = Class.forName(cName);
Object obj = c.newInstance();
return obj;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
クライアント
package design.templatemethod;
public class Client {
public static void main(String[] args) {
Accout accout;
accout = (Accout) XMLUtil.getBean();
accout.handle("张无忌", "123456");
}
}
特定のサブクラスを変更する必要がある場合は、開始と終了の原則のフックメソッドに準拠するように構成ファイルを変更するだけで済みます。
フックメソッドには、抽象クラスまたは具象クラスの宣言と実装があり、そのサブクラスは拡張できます。通常、親クラスで指定された実装は空の実装であり、空の実装がメソッドのデフォルトの実装として使用されます。もちろん、フックメソッドは空でないデフォルトの実装を提供することもできます
テンプレートメソッドパターンには2つのタイプのフックメソッドがあります。最初のタイプのフックメソッドは、いくつかの特定のステップにリンクして、さまざまな条件下でテンプレートメソッドのさまざまなステップを実装できます。このタイプのフックメソッドの戻り
タイプは通常、ブール値です。タイプ、メソッド名前は通常isXXX()で、特定の条件を判断するために使用されます。条件が満たされている場合は特定のステップを実行し、そうでない場合は実行されません。
2番目のタイプのフックメソッドは、実装本体が空の特定のメソッドであり、サブクラスは必要に応じてこれらのフックメソッドをオーバーライドまたは継承できます。抽象メソッドと比較して、このタイプのフックメソッドの利点は、サブクラスが親クラスで定義されたフックメソッドをオーバーライドしない場合、コンパイルは正常にパスできますが、親クラスで宣言された抽象メソッドがカバーされていない場合、コンパイルはエラーを報告します。
フックメソッドの使用
ソフトウェア会社は、販売管理システムにデータチャート表示機能を提供したいと考えています。この機能の実現には、次の手順が含まれます。
(1)データソースからデータを取得する
(2)データをXML形式に変換する
(3)を使用する特定のチャート方式データ
をXML形式で表示するこの関数は複数のデータソースと複数のチャート表示方式をサポートしますが、すべてのチャート表示操作はXML形式のデータに基づいているため、データの変換が必要になる場合があります。データから取得したデータの場合ソースはすでにXMLデータであり、変換する必要はありません
コード
抽象親クラス
package design.templatemethod.hookmethod;
/*
*
*@author:zzf
*@time:2020-12-21
*
*/
public abstract class DataViewer {
//抽象方法,获取数据
public abstract void getData();
//具体方法,转换数据
public void convertData(){
System.out.println("将数据转换成XML格式");
}
//抽象方法,显示数据
public abstract void displayData();
//钩子方法,判断是否为XML格式数据
public boolean isNotXMLData(){
return true;
}
//模板方法
public void process(){
getData();
//如果不是XML格式的数据则进行数据转换
if(isNotXMLData()){
convertData();
}
displayData();
}
}
具体的なサブカテゴリ
package design.templatemethod.hookmethod;
/*
*
*@author:zzf
*@time:2020-12-21
*
*/
public class XMLDataViewer extends DataViewer {
@Override
public void getData() {
System.out.println("从XML文件中获取数据");
}
@Override
public void displayData() {
System.out.println("以柱状图显示数据");
}
//覆盖父类的钩子方法,返回false表示已经是XML格式数据,无需转换
@Override
public boolean isNotXMLData() {
return false;
}
}
クライアント
package design.templatemethod.hookmethod;
/*
*
*@author:zzf
*@time:2020-12-21
*
*/
public class Client {
public static void main(String[] args) {
DataViewer dv;
dv=new XMLDataViewer();
dv.process();
}
}
運転結果
テンプレートメソッドパターンの長所と短所
利点:
(1)正式に親クラスのアルゴリズムを定義し、そのサブクラスは、詳細な処理を実装する場合サブクラス実装詳細な処理アルゴリズム、アルゴリズムにおけるステップの実行順序が変更されません。
(2)で公共行動をクラスライブラリが抽出され、パブリックビヘイビアが親クラスに配置され、そのサブクラスを通じてさまざまなビヘイビア
を実現できます。(3)逆制御構造を実現でき、優れたスケーラビリティを持ち、単一の責任の原則に準拠します。および開閉の原則
短所:
基本メソッドごとに異なる実装のサブクラスを提供する必要があります。親クラスに可変基本メソッドが多すぎると、クラスの数が増え、システムが大きくなり、設計が多くなります。概要
該当する環境
(1)アルゴリズムの不変部分を一度に実装し、可変動作をサブクラスに任せて実装します
(2)コードを回避するために、各サブクラスの共通動作を抽出して共通の親クラスに集中させる
必要があります(3)必要親クラスへのサブクラスの逆制御を実現するために、親クラスアルゴリズムの特定のステップがサブクラスを介して実行されるかどうかを決定するため。
Javaデザインパターンを参照してください