java设计模式--模板设计模式

模板方法仅仅使用了Java的继承机制,但它是应用非常广泛的模式,抽象类的实际应用

模板方法定义了一个算法的步骤,并允许子类为一个或者多个步骤提供具体实现。

模板(模板方法)设计模式:基于抽象类

核心在一个方法定义一个算法的骨架,而将一些步骤延迟到子类中。模板模式可以使得子类在不改变算法的前提下,重新定义算法中的某些步骤。

注意:为了防止恶意操作,一般模板方法都加上final关键字, 不允许被覆写

模板方法的优点:
● 封装不变部分,扩展可变部分
● 提取公共部分代码,便于维护
● 行为由父类控制,子类实现

模板模式就是在模板方法中对基本方法的调用。

模板方法通用代码:

抽象模板类:

public abstract class AbstractClass {
     //基本方法
     protected abstract void doSomething();
     //基本方法
     protected abstract void doAnything();
     //模板方法
     public void templateMethod(){
             /*
              * 调用基本方法,完成相关的逻辑
              */
             this.doAnything();
             this.doSomething();
     }
}

具体模板类:注意:抽象模板中的基本方法尽量设计为protected类型,符合迪米特法则,不需要暴露的属性或方法尽量不要设置为protected类型。

public class ConcreteClass1 extends AbstractClass {
     //实现基本方法
     protected void doAnything() {
             //业务逻辑处理
     }
     protected void doSomething() {
             //业务逻辑处理
     }
}
public class ConcreteClass2 extends AbstractClass {
     //实现基本方法
     protected void doAnything() {
             //业务逻辑处理
     }
     protected void doSomething() {
             //业务逻辑处理
     }
}

场景类:

public class Client {
     public static void main(String[] args) {
             AbstractClass class1 = new ConcreteClass1();
             AbstractClass class2 = new ConcreteClass2();               
             //调用模板方法
             class1.templateMethod();
             class2.templateMethod();
     }
}

模板模式举例·:

星巴克咖啡冲泡法

  1. 将水煮沸 

  2. 用沸水冲泡咖啡

  3. 将咖啡倒进杯子 

  4.  加糖和牛奶

星巴克茶冲泡法

  1.  将水煮沸 

  2. 用沸水浸泡茶叶 

  3. 把茶倒进杯子

  4.  加柠檬

根据冲泡步骤使用代码实现咖啡和茶的类:

class Coffee{
    //咖啡冲泡法(算法)
    void prepareRecipe(){
        boilWater();
        brewCoffeeGrings();
        pourInCup();
        addSugarAndMilk();
    }
    public void boilWater(){
        System.out.println("将水煮沸");
    }
    public void brewCoffeeGrings(){
        System.out.println("冲泡咖啡");
    }
    public void pourInCup(){
        System.out.println("将咖啡倒进杯子中");
    }
    public void addSugarAndMilk(){
        System.out.println("加糖和牛奶");
    }
}
class Tea{
    void prepareRecipe(){
        boilWater();
        steepTeaBag();
        pourInCup();
        addLemon();
    }
    public void boilWater(){
        System.out.println("将水煮沸");
    }
    public void steepTeaBag(){
        System.out.println("浸泡茶");
    }
    public void pourInCup(){
        System.out.println("将茶倒进杯子中");
    }
    public void addLemon(){
        System.out.println("加柠檬");
    }
}
public class Test{
    public static void main(String[] args) {
        Coffee coffee=new Coffee();
        coffee.prepareRecipe();
        Tea tea=new Tea();
        tea.prepareRecipe();
    }
}

我们可以发现茶和咖啡非常相似,因此可以将二者相同的部分抽取出来,放进一个基类(父类)当中。

我们可以把“将水煮沸”和“将饮料倒进杯子中”放到一个基类中。

我们在可以从冲泡法和往饮料中加调料着手,将二者的冲泡算法合并成

  1. 将水煮沸

  2. 用热水泡饮料

  3. 将饮料倒进杯子

  4. 在饮料内加入适当的调料

抽象基类代码实现

//咖啡因饮料是一个抽象类
//抽象模板类
abstract class CaffeineBeverage{
    //使用同一个prepareBeverage()方法处理茶和咖啡
    //使用final关键字来防止子类覆盖这个方法
    //模板方法
    final void prepareRecipe(){
        boilWater();
        //冲饮料的方法
        brew();
        pourInCup();
        //往饮料中加的调料
        addCondiments();
    }
    //基本方法
    public void boilWater(){
        System.out.println("将水烧开");
    }
    //基本方法
    public void pourInCup(){
        System.out.println("将饮料倒进杯子");
    }
    //将咖啡和茶不同的处理方法声明为抽象,留给子类实现
    //基本方法
    public abstract void brew();
    //基本方法
    public abstract void addCondiments();
}
//具体模板类
class Coffee extends CaffeineBeverage{
    public void brew(){
        System.out.println("冲泡咖啡");
    }
    public void addCondiments(){
        System.out.println("加糖和牛奶");
    }
}
//具体模板类
class Tea extends CaffeineBeverage{
    public void brew(){
        System.out.println("冲泡茶");
    }
    public void addCondiments(){
        System.out.println("加柠檬");
    }
}
//场景类
public class Test{
    public static void main(String[] args) {
        //向上转型
        CaffeineBeverage coffee=new Coffee();
        coffee.prepareRecipe();
        //向上转型
        CaffeineBeverage tea=new Tea();
        tea.prepareRecipe();
    }
}

此时的类图:

模板方法定义了一个算法的步骤,并允许子类为一个或者多个步骤提供具体方法

使用模块方法所带来的优势

不好的茶或咖啡实现

模板方法提供的咖啡因饮料

Coffee或Tea主导一切,控制算法

由超类主导一切,它拥有算法,并且保护这个算法

Coffee与Tea之间存在重复代

有超类的存在,因此可以将代码复用最大化

对于算法所做的代码改变,需要打开各个子类修改很多地方

算法只存在一个地方,容易修改

弹性差,新种类的饮料加入需要做很多工作

弹性高,新饮料的加入只需要实现自己的冲泡和加料方 法即可

算法的知识和它的实现分散在许多类中

超类专注于算法本身,而由子类提供完整的实现。

钩子方法:是一类“默认不做事的方法”,子类可以选择性的覆盖他们

范例:扩展上述类,引入钩子方法

//咖啡因饮料是一个抽象类
abstract class CaffeineBeverage{
    //使用同一个prepareBeverage()方法处理茶和咖啡
    //使用final关键字来防止子类覆盖这个方法
    final void prepareRecipe(){
        boilWater();
        //冲饮料的方法
        brew();
        pourInCup();
        //判断顾客是否需要加入调料
        if(customerWantCondiments()){
            //往饮料中加的调料
            addCondiments();
        }
    }
    public void boilWater(){
        System.out.println("将水烧开");
    }
    public void pourInCup(){
        System.out.println("将饮料倒进杯子");
    }
    //将咖啡和茶不同的处理方法声明为抽象,留给子类实现
    public abstract void brew();
    public abstract void addCondiments();
    //钩子方法
    boolean customerWantCondiments(){
        return true;
    }
}
class Coffee extends CaffeineBeverage{
    public void brew(){
        System.out.println("冲泡咖啡");
    }
    public void addCondiments(){
        System.out.println("加糖和牛奶");
    }
}
class Tea extends CaffeineBeverage{
    public void brew(){
        System.out.println("冲泡茶");
    }
    public void addCondiments(){
        System.out.println("加柠檬");
    }
    public boolean customerWantCondiments(){
        String answer=getUserInput();
        if(answer.equals("y")){
            return true;
        }else{
            return false;
        }
    }
    //私有方法,获取用户的意愿
    private String getUserInput(){
        String answer=null;
        System.out.println("您想要在茶中加入柠檬吗(y/n)?");
        //写入用户的选择
        Scanner scanner=new Scanner(System.in);
        answer=scanner.nextLine();
        return answer;
    }
}
public class Test{
    public static void main(String[] args) {
        //向上转型
        CaffeineBeverage coffee=new Coffee();
        coffee.prepareRecipe();
        //向上转型
        CaffeineBeverage tea=new Tea();
        tea.prepareRecipe();
    }
}

猜你喜欢

转载自blog.csdn.net/ds19980228/article/details/83312775