合工大很牛很牛牛

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  14 Posts :: 1 Stories :: 37 Comments :: 0 Trackbacks

 

茶和咖啡是两个功能类似的类:咖啡的制作包括boil water, brew, pour, add condiments四步,而沏茶的过程包括boil water, steep, pour, add lemon四步。

它们的一,三两步相同,二,四两步类似,如下:

class Coffee {

    public void boilWater() {

        System.out.println("Boiling water");

    }

    public void brew() {

        System.out.println("Brewing Coffee in the water");

    }

    public void pour() {

        System.out.println("Pour Coffee in cup");

    }

    public void addCondiments() {

        System.out.println("Add sugar and Milk in the coffee");

    }

}

class Tea {

    public void boilWater() {

        System.out.println("Boiling water");

    }

    public void steep() {

        System.out.println("Steep te                                                                                                                                         a in the water");

    }

    public void pour() {

        System.out.println("Pour tea in cup");

    }              

    public void addLemon() {

        System.out.println("Add lemon in the tea");

    }

}

为了减少重复,增加复用,我们给它们加一个共同的抽象父类:CaffeineBeverage

两个子类中相同的部分移到了父类中,变成父类的方法;不同的部分在父类中写成抽象方法,具体实现放到子类中(对比工厂方法,工厂方法是把对象的创建方法放到了子类中)。

另外,添加了一个prepareRecipe方法,相当于“一键”功能(这个和façade pattern的一键功能是有区别的,这里“一键”是写在抽象父类中,而在façade pattern里,是写在客户端和类库之间的一个新增的类中)。如下:

package javaapplication36;

public class Main {

    public static void main(String[] args) {

        CaffeineBeverage beverage = new Coffee();

        beverage.prepareRecipe();

        beverage = new Tea();

        beverage.prepareRecipe();

    }

}

abstract class CaffeineBeverage {

    public void prepareRecipe() {

        boilWater();

        brew();

        pour();

        addCondiments();

    }

    public void boilWater() {

        System.out.println("Boiling water");

    }

    public abstract void brew();

    public void pour() {

        System.out.println("Pour into the cup");

    }

    public abstract void addCondiments();

}

class Coffee extends CaffeineBeverage {

    public void brew() {

        System.out.println("Brewing Coffee in the water");

    }

    public void addCondiments() {

        System.out.println("Add sugar and Milk in the coffee");

    }

}

class Tea extends CaffeineBeverage {

    public void brew() {

        System.out.println("Steep the tea");

    }

    public void addCondiments() {

        System.out.println("Add lemon in the tea");

    }

}

在以上代码中:父类的prepareRecipe方法实际上就是所谓的Template 方法,template方法中所调用的其他函数,有的在父类中已经实现,有的会根据不同的子类,而采用不同的实现。

Template pattern:即算法(prepareRecipe方法)在父类中写好了,会调用父类里的各种方法来实现(boilingwaterbrewpouraddCondiments),这些方法有的会在父类中就已经实现,有的会放到子类中实现之。

再把程序写的更完善些:由于算法prepareRecipe是不会变动的,所以我们给它加上final,而对于addCondiments ,有的饮料有可能需要配料,而有的饮料根本不可能添加配料。(也就是说有的子类, prepareRecipe方法中需要执行addCondiments功能,而有的子类不需要。)

为了不写几种重复prepareRecipe方法(prepareRecipe1, prepareRecipe2….每种方法只是有个别步骤不一样),我们使用Hook方式来做(Hook就是指一个包含空内容的实体方法,不同于抽象方法),如下:

package javaapplication36;

public class Main {

    public static void main(String[] args) {

        CaffeineBeverage beverage = new Coffee();

        beverage.prepareRecipe();

        beverage = new Tea();

        beverage.prepareRecipe();

        beverage = new Milk();

        beverage.prepareRecipe();

    }

}

abstract class CaffeineBeverage {

    public void prepareRecipe() {

        boilWater();

        brew();

        pour();

        addCondiments();

    }

    public void boilWater() {

        System.out.println("Boiling water");

    }

    public abstract void brew();

    public void pour() {

        System.out.println("Pour into the cup");

    }

    public void addCondiments() { //HOOK,一个空方法,不做任何事情,继承的子类根据需//要覆盖或者保持它为空。

    }

}

class Coffee extends CaffeineBeverage {

    public void brew() {

        System.out.println("Brewing Coffee in the water");

    }

    public void addCondiments() { //addCondiments重写

        System.out.println("Add sugar and Milk in the coffee");

    }

}

class Tea extends CaffeineBeverage {

    public void brew() {

        System.out.println("Steep the tea");

    }

    public void addCondiments() { //addCondiments重写

        System.out.println("Add lemon in the tea");

    }

}

class Milk extends CaffeineBeverage { //没有对addCondiments重写

    public void brew() {

        System.out.println("Brewing Milk in the water.");

    }

}

最后,我们试图更进一步完善代码,即使子类有addCondiments这个方法,我们也可以根据客户端的需要,选择在执行prepareRecipe的时候是否进行addCondiments这一步。

package javaapplication36;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.util.logging.Level;

import java.util.logging.Logger;

public class Main {

    public static void main(String[] args) {

        CaffeineBeverage beverage = new Coffee();

        beverage.prepareRecipe();

        beverage = new Tea();

        beverage.prepareRecipe();

        beverage = new Milk();

        beverage.prepareRecipe();

    }

}

abstract class CaffeineBeverage {

    public void prepareRecipe() {

        boilWater();

        brew();

        pour();

        if (customerWantCondiments()) {

            addCondiments();

        }

    }

    public void boilWater() {

        System.out.println("Boiling water");

    }

    public abstract void brew();

    public void pour() {

        System.out.println("Pour into the cup");

    }

    public void addCondiments() {

    }

    public boolean customerWantCondiments() {

        return true;//相当于不做任何判断就直接让prepareRecipe执行addCondiments()

    }

}

class Coffee extends CaffeineBeverage {

    public void brew() {

        System.out.println("Brewing Coffee in the water");

    }

    @Override

    public void addCondiments() {

        System.out.println("Add sugar and Milk in the coffee");

    }

    @Override

    public boolean customerWantCondiments() {

        String answer = getUserInput();

        if (answer.startsWith("y")) {

            return true;

        }

        else {

            return false;

        }

    }

    private String getUserInput() { //获取输入,确定是否要Condiments

        System.out.println("Would you love some condiments? (y/n)");

        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

        String answer = null;

        try {

            answer = in.readLine();

        }

        catch (IOException ex) {

            Logger.getLogger(Coffee.class.getName()).log(Level.SEVERE, null, ex);

        }

        answer = answer.toLowerCase();

        return answer;

    }

}

class Tea extends CaffeineBeverage {

    public void brew() {

        System.out.println("Steep the tea");

    }

    @Override

    public void addCondiments() {

        System.out.println("Add lemon in the tea");

    }

}

class Milk extends CaffeineBeverage {

    public void brew() {

        System.out.println("Brewing Milk in the water.");

    }

}

再举一例,很常见的,自定义类型数组的比较就是用到了Template pattern,如下:

package javaapplication37;

import java.util.Arrays;

public class Main {

    public static void main(String[] args) {

        Duck[] ducks = {new Duck("duck1", 10), new Duck("duck2", 13), new Duck("duck3", 9)};

        displayDucks(ducks);

        Arrays.sort(ducks);//Arrays相当于template pattern中的抽象父类,sort是该类中的//算法函数

        displayDucks(ducks);

    }

    private static void displayDucks(Duck[] ducks) {

        for (int i = 0; i < ducks.length; i++) {

            System.out.println(ducks[i].toString());

        }

    }

}

class Duck implements Comparable {

    String name;

    int weight;

    Duck(String name, int weight) {

        this.name = name;

        this.weight = weight;

    }

    @Override

    public String toString() {

        return name + ":" + weight;

    }

    public int compareTo(Object o) { //compareTo方法相当于HOOK

        Duck otherDuck = (Duck) o;

        if (this.weight < otherDuck.weight) {

            return -1;

        }

        else if (this.weight == otherDuck.weight) {

            return 0;

        }

        else {

            return 1;

        }

    }

}

我们来看看Arrays这个类是如何使用template pattern的。

public class Arrays {

public static void sort(Object[] a) { //sort是算法函数

        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) {

         int length = high - low;

         // Insertion sort on smallest arrays

        if (length < INSERTIONSORT_THRESHOLD) {

            for (int i=low; i<high; i++)

                for (int j=i; j>low &&

                             ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)

                    swap(dest, j, j-1);

            return;

        }

}

}

public interface Comparable<T> {

    public int compareTo(T o); //compareToHOOK

}

再举一例,看看Swing中的JFrame是如何使用template pattern的:

package javaapplication38;

import java.awt.Graphics;

import javax.swing.JFrame;

public class Main {

    public static void main(String[] args) {

        MyFrame frame = new MyFrame("my first frame");

    }

}

class MyFrame extends JFrame { //JFrame 相当于template pattern中的父类,而它里面的//update方法就是其算法函数

    public MyFrame(String title) {

        super(title);

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        this.setSize(300, 300);

        this.setVisible(true);

    }

    public void paint(Graphics g) { //paintHOOK

        super.paint(g);

        String msg = "i rule";

        g.drawString(msg, 100, 50);

    }

}

posted on 2008-07-09 15:38 化的了 阅读(1559) 评论(3)  编辑  收藏 所属分类: 设计模式

Feedback

# re: template pattern 2008-07-09 17:21 深圳朋悦速8酒店梅林店
http://www.blogjava.net  回复  更多评论
  

# re: template pattern 2008-07-09 19:20 leekiang
貌似抽象类实现几个方法,留几个接口,实现的方法要调接口,这就是模板了。  回复  更多评论
  

# re: template pattern 2008-07-09 22:23 化的了
@leekiang
其实模板的目的就是保持算法的稳定,然后就搞了一大堆类似工厂方法的东西。。。  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: