Template Methodパターン。
ケース
紅茶とコーヒーは、コーヒーのステップの手順と非常によく似ています。
- お湯を沸かします
- コーヒーは、沸騰したお湯で淹
- 彼女はカップにコーヒーを注ぎました
- 砂糖とミルク
茶の手順:
- お湯を沸かします
- 沸騰水浸漬とお茶
- ティーカップに注ぎ
- レモン入り
以下のようにコーヒーコードは次のとおりです。
public class Coffee {
void prepareRecipe() {
boilWater();
brewCoffeeGrinds();
pourInCup();
addSugarAndMilk();
}
public void boilWater() {
System.out.println("Boiling water");
}
public void brewCoffeeGrinds() {
System.out.println("Dripping Coffee through filter");
}
public void pourInCup() {
System.out.println("Pouring into cup");
}
public void addSugarAndMilk() {
System.out.println("Adding Sugar and Milk");
}
}
ティーコード:
public class Tea {
void prepareRecipe() {
boilWater();
steepTeaBag();
pourInCup();
addLemon();
}
public void boilWater() {
System.out.println("Boiling water");
}
public void steepTeaBag() {
System.out.println("Steeping the tea");
}
public void addLemon() {
System.out.println("Adding Lemon");
}
public void pourInCup() {
System.out.println("Pouring into cup");
}
}
これは、コードの明らかな重複ですので、我々は共通部分を抽出することができます。
- お湯を沸かします
- ホットコーヒーまたは紅茶付き
- 飲料をカップに注ぎ
- 飲料中の適切なスパイスを追加します。
第一工程及び第三工程は、パブリックであり、第二の工程と第四の工程は、唯一の飲料または単にそれをしないシーズニング同じ場所ではないが、引き出すことができます。
私たちは、最初の3ステップは、スーパークラスに引き込ま。
public abstract class CaffeineBeverage {
public abstract void prepareRecipe();
public void boilWater() {
System.out.println("Boiling water");
}
public void pourInCup() {
System.out.println("Pouring into cup");
}
}
しかし、2,4-ステップは非常に似ているので、我々もそれを修正して、参照、スーパークラスで定義されています。
public abstract class CaffeineBeverage {
public final void prepareRecipe() {
boilWater();
brew();
pourInCup();
addCondiments();
}
protected abstract void addCondiments();
protected abstract void brew();
public void boilWater() {
System.out.println("Boiling water");
}
public void pourInCup() {
System.out.println("Pouring into cup");
}
}
我々は彼らの特定の機能を実現するために2つのステップ2,4抽象化、および他のサブカテゴリーを置きます。紅茶やコーヒーなどの形質転換後。
public class Tea extends CaffeineBeverage {
@Override
protected void addCondiments() {
System.out.println("Adding Lemon");
}
@Override
protected void brew() {
System.out.println("Steeping the tea");
}
}
public class Coffee extends CaffeineBeverage {
@Override
protected void addCondiments() {
System.out.println("Adding Sugar and Milk");
}
@Override
protected void brew() {
System.out.println("Dripping Coffee through filter");
}
}
紅茶とコーヒーはカフェイン飲料から継承されている、彼らは醸造()とaddCondiments()メソッド自身を実装する必要があります。これは、テンプレートメソッドパターンで、preareRecipe()メソッドは、このアルゴリズムは、カフェイン飲料の生産を指し、それはテンプレートアルゴリズムとして使用され、私たちのテンプレートです。アルゴリズムの各ステップは、表現する方法です。この方法は、テンプレートは、アルゴリズムを定義し、サブクラスは、1つのまたは複数のステップの実装を提供可能にするステップ。
定義
Template Methodパターンは、一つの方法では、サブクラス遅延にいくつかのステップをスケルトンアルゴリズムを定義します。アルゴリズムの構造を変更せずにテンプレートの方法、そのようなサブクラスは、アルゴリズムのステップのいくつかが再定義されます。
複数の類似のクラスのうち同様の手順を持って実際には、これらのステップは、抽象的なことができ、サブクラスによって実装され、このアルゴリズムは、部分的にサブクラスによって達成を提供しながら、構造は、変わらないままであることを保証することができます。
また、フックは、当社の抽象クラスやメソッドの中空のデフォルトの実装に、文が設定されていることができます。サブクラスは、サブクラスが同じステップ、特定しないか、またはサブクラスにリンクされていない異なるアルゴリズムをポイントする能力を持っているように、拡張のための左室とすることができます。私たちの最初の例をみましょう:
public abstract class CaffeineBeverageWithHook {
void prepareRecipe() {
boilWater();
brew();
pourInCup();
if (customerWantsCondiments()) {
addCondiments();
}
}
private boolean customerWantsCondiments() {
return true;
}
protected abstract void addCondiments();
protected abstract void brew();
public void boilWater() {
System.out.println("Boiling water");
}
public void pourInCup() {
System.out.println("Pouring into cup");
}
}
我々は条件である()メソッドはcustomerWantsCondimentsによって決定された値を返し、条件文を追加しました。顧客がスパイスに望んでいる場合は、trueを返す、フックで実行addCondiments()メソッドは、サブクラスはこのメソッドをオーバーライドすることができますが、必ずしも対象とする必要がありません。私たちは、コードを変更し続けます。
public class CoffeeWithHook extends CaffeineBeverageWithHook {
@Override
protected void addCondiments() {
System.out.println("Adding Sugar and Milk");
}
@Override
protected void brew() {
System.out.println("Dripping Coffee through filter");
}
public boolean customerWantsCondiments() {
String answer = getUserInput();
if (answer.toLowerCase().startsWith("y")) {
return true;
} else {
return false;
}
}
private String getUserInput() {
String answer = null;
System.out.println("Would you like milk and sugar with your coffee (y/n)?");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
try {
answer = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
if (answer == null) {
return "no";
}
return answer;
}
}
まず、我々はBREW()を達成しaddCondiments()メソッド、およびその後customerWantsCondimentsをカバー()メソッドは、ユーザのためのユーザ入力yは、ミルクと砂糖を追加する必要があり、N-逆に、我々は今、テストプログラムを実行します。
public class BeverageTestDrive {
public static void main(String[] args) {
CoffeeWithHook coffeeWithHook = new CoffeeWithHook();
coffeeWithHook.prepareRecipe();
}
}
非常に便利な、右フックは、実際には、我々はまた、スーパークラスに直接設定することができます。
私たちは今、新しいデザインの原則があります:「ハリウッドの原則を」
ハリウッドの原則:DOは(コール)お電話ではない、我々は(コール)お電話いたします。
低レベルのコンポーネントは、システムに自身をフックすることを許可するが、高いレベルで組み立てたときに、どのようにこれらの低レベルのコンポーネントを使用することを決定します。道の御馳走低レベルのコンポーネントに言い換えれば、ハイレベルのコンポーネントでは、「私たちを呼んではいけない、私たちはあなたを呼ぶことにします。」
テンプレートメソッドパターンでのJava
ソートテンプレート法により、ソート方法をソート配列(オブジェクト[] a)は、我々はそのコードを見る方法です。
public static void sort(Object[] a) {
Object[] aux = (Object[])a.clone();
mergeSort(aux, a, 0, a.length, 0);
}
この方法は、その後、ちょうどヘルパーメソッドは、配列のコピーを作成するために使用されているマージ()メソッドに渡します。
private static void mergeSort(Object src[], Object dest[], int low, int high, int off) {
for (int i=low; i<high; i++) {
for (int j=i; j>low && ((Comparable)dest[j-1].compareTo((Comparable)dest[j])>0; j--) {
swap(dest, j, j-1);
}
}
return;
}
compareTo()メソッドの実装のアルゴリズムに依存して、この方法は以下の工程を含む:ソートアルゴリズムを終了します。ここでは、テンプレートメソッドと考えることができ、あなたがのcompareTo()メソッドを実装する必要があります。今の例を見てみましょう。人の年齢の比較、我々はクラスの人を必要としています。
public class People implements Comparable {
String name;
int age;
public People(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Object o) {
People o1 = (People) o;
return Integer.compare(this.age, o1.age);
}
}
テストプログラム。
public class PeopleSortTestDrive {
public static void main(String[] args) {
People[] people = {
new People("Ab", 12),
new People("zhangsan", 123),
new People("lisi", 22),
new People("wangwu", 53),
new People("zhaoliu", 66)
};
System.out.println("Before sorting: ");
display(people);
Arrays.sort(people);
System.out.println("\nAfter sorting:");
display(people);
}
public static void display(People[] people) {
for (People person : people) {
System.out.println(person);
}
}
}
最初のプリント注文のうち、二次が小から大にあります。私たちは、ソートの成功であることをこの番組では、重要なステップはそう最終的に全体の配列はソートが完了した完璧なことができ、より達成するために整数を私たちのクラスに(int型のx、int型のy)を比較する方法をComparableインタフェースの私達のcompareToメソッドを実現することです。
スイングのプログラムウィンドウを書きます
次の例では、SwingのJFrameのです!JFrameのは、paint()メソッドを継承し、最も基本的なSwingコンテナである、(デフォルトの状態をペイント)、それはフックですので、物事を行う、それをカバーしていない、我々はJFrameのアルゴリズムに独自のコードを置くことができるようになります。
public class MyFrame extends JFrame {
public MyFrame(String title) {
super(title);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(300, 300);
this.setVisible(true);
}
public void paint(Graphics graphics) {
super.paint(graphics);
String msg = "I rule!!";
graphics.drawString(msg, 100,100);
}
public static void main(String[] args) {
new MyFrame("Head First Design Patterns");
}
}
我々は独自の定義のためのコードが、また、アプリケーションモードの外観を追加し、塗料()フックメソッドを使用します。