设计模式-模板方法模式 策略模式

来源:互联网 发布:阿里算法工程师p6待遇 编辑:程序博客网 时间:2024/06/06 02:08

模板方法模式定义

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

  模板方法非常常见,对创建框架来说,由框架控制如何做事情,而由你(使用这个框架的人)指定框架算法中每个步骤的细节。


举个咖啡和茶的例子

用模版方法实现代码复用,让茶,咖啡等一类制作方法类似的饮料借用一个算法框架来实现


茶的制作方法:1.把水煮沸 2.用沸水浸泡茶叶 3.把茶倒进杯子4.加柠檬

咖啡的制作方法1.把水煮沸 2.用沸水冲泡咖啡 3.把咖啡倒进杯子4.加牛奶或者糖

可以看出两者的制作过程其实是采用了相同的算法:

1.把水煮沸 

2.用沸水冲泡咖啡或者茶

3.把饮料倒进杯子

4.加入调料

我们把这个咖啡因类饮料的制作方法抽象出来 实现一个模板方法,模板方法定义了一个算法的步骤,并允许子类为一个或者多个步骤提供实现

public abstract class CaffeineBeverage { //prepareRecipe是我们的模板方法final void prepareRecipe() {boilWater();   //煮水brew();      //冲泡pourInCup();   //倒进杯子addCondiments();  ///加调料} abstract void brew();  abstract void addCondiments(); void boilWater() {System.out.println("Boiling water");}  void pourInCup() {System.out.println("Pouring into cup");}}
接下来实现咖啡和茶的两个具体子类
public class Tea extends CaffeineBeverage {public void brew() {System.out.println("Steeping the tea");}public void addCondiments() {System.out.println("Adding Lemon");}}
public class Coffee extends CaffeineBeverage {public void brew() {System.out.println("Dripping Coffee through filter");}public void addCondiments() {System.out.println("Adding Sugar and Milk");}}
对模板方法进行挂钩

  钩子(hook)是一种被声明在抽象类中的方法,但只有空的或者默认的实现钩子的存在,可以让子类有能力对算法的不同点进行挂钩。要不要挂钩,由子类自行决定。

  某些步骤是可选的,所以可以将这些步骤实现成钩子,而不是实现成抽象方法,这样就可以让抽象类的子类的负荷减轻。

 比如,也可以利用钩子做条件控制,影响抽象类中的算法流程:钩子方法在抽象类中有默认实现返回true,放在抽象类的if条件语句中,子类可以覆盖也可以不覆盖这个钩子方法


上述例子可以对ddCondiments()方法进行挂钩,让子类自由选择要不要加调料,抽象类重写如下:

public abstract class CaffeineBeverageWithHook { void prepareRecipe() {boilWater();brew();pourInCup();if (customerWantsCondiments()) {addCondiments();}}abstract void brew(); abstract void addCondiments();void boilWater() {System.out.println("Boiling water");}void pourInCup() {System.out.println("Pouring into cup");}boolean customerWantsCondiments() {return true;}}
子类需要实现customerWantsCondiments方法,进行判断是否要进行加调料的操作。而实现这个方法要根据顾客的需求来定,getUserInput()方法得到顾客输入的需求信息

//咖啡子类 挂钩版import java.io.*;public class CoffeeWithHook extends CaffeineBeverageWithHook { public void brew() {System.out.println("Dripping Coffee through filter");} public void addCondiments() {System.out.println("Adding Sugar and Milk");} public boolean customerWantsCondiments() {String answer = getUserInput();if (answer.toLowerCase().startsWith("y")) {return true;} else {return false;}}private String getUserInput() {String answer = null;System.out.print("Would you like milk and sugar with your coffee (y/n)? ");BufferedReader in = new BufferedReader(new InputStreamReader(System.in));try {answer = in.readLine();} catch (IOException ioe) {System.err.println("IO error trying to read your answer");}if (answer == null) {return "no";}return answer;}}
茶的子类挂钩
import java.io.*;public class TeaWithHook extends CaffeineBeverageWithHook {public void brew() {System.out.println("Steeping the tea");} public void addCondiments() {System.out.println("Adding Lemon");}  //对判断条件的实现 如果输入y就加入调料public boolean customerWantsCondiments() {String answer = getUserInput();if (answer.toLowerCase().startsWith("y")) {return true;} else {return false;}}private String getUserInput() {// get the user's responseString answer = null;System.out.print("Would you like milk and sugar with your coffee (y/n)? ");BufferedReader in = new BufferedReader(new InputStreamReader(System.in));try {answer = in.readLine();} catch (IOException ioe) {System.err.println("IO error trying to read your answer");}if (answer == null) {return "no";}return answer;}}
//测试public class BeverageTestDrive {public static void main(String[] args) { Tea tea = new Tea();Coffee coffee = new Coffee(); System.out.println("\nMaking tea...");tea.prepareRecipe(); System.out.println("\nMaking coffee...");coffee.prepareRecipe(); TeaWithHook teaHook = new TeaWithHook();CoffeeWithHook coffeeHook = new CoffeeWithHook(); System.out.println("\nMaking tea...");teaHook.prepareRecipe(); System.out.println("\nMaking coffee...");coffeeHook.prepareRecipe();}

模版方法模式是一个很常见的模式,这是因为对创建框架来说,这个模式很方便可以做到有框架控制如何做事情,而由你指定框架中每个步骤的细节,在实际应用中模版方法有很多实现方法。

下面的例子是用模版方法进行排序

class Student implements Comparable<Student>{    private String name;    private int age;    private float score;        public Student(String name, int age, float score) {        this.name = name;        this.age = age;        this.score = score;    }        public String toString()    {        return name+"\t\t"+age+"\t\t"+score;    }    @Override    public int compareTo(Student o) {             if(this.score>o.score)//score是private的,为什么能够直接调用,这是因为在Student类内部            return -1;//由高到底排序        else if(this.score<o.score)            return 1;        else{            if(this.age>o.age)                return 1;//由底到高排序            else if(this.age<o.age)                return -1;            else                return 0;        }    }}public class ComparableDemo01 {    public static void main(String[] args) {          Student stu[]={new Student("zhangsan",20,90.0f),                new Student("lisi",22,90.0f),                new Student("wangwu",20,99.0f),                new Student("sunliu",22,100.0f)};        Arrays.sort(stu);        for(Student s:stu)        {            System.out.println(s);        }    }}
排序的实现看起来更像是策略模式,因为策略模式使用对象组合,但是在策略模式中,你所组合的类实现了整个算法。数组所实现的排序算法并不完整,它需要一个类填补 compareTo()方法的实现。因此认为这更像模版方法

策略模式

 定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

      这个原则的思考方式是,把会变化的部分取出并封装起来,以便以后可以轻易地改动或扩充此部分,而不影响不需要变化的其他部分

下面就以一个示意性的实现讲解策略模式实例的结构。


这个模式涉及到三个角色:

  ●  环境(Context)角色:持有一个Strategy的引用。

  ●  抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。

  ●  具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。

策略模式网上的例子有很多,也比较简单,与上面一个排序做对比,下面用comparator实现的排序用的就是策略模式

import java.util.Comparator;class Student {    private String name;    private int age;    private float score;        public Student(String name, int age, float score) {        this.name = name;        this.age = age;        this.score = score;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    public float getScore() {        return score;    }    public void setScore(float score) {        this.score = score;    }    public String toString()    {        return name+"\t\t"+age+"\t\t"+score;    }}class StudentComparator implements Comparator<Student>{    public int compare(Student o1, Student o2) {        if(o1.getScore()>o2.getScore())            return -1;        else if(o1.getScore()<o2.getScore())            return 1;        else{            if(o1.getAge()>o2.getAge())                return 1;            else if(o1.getAge()<o2.getAge())                return -1;            else                 return 0;        }    }    }public class comparatorDemo1 {    public static void main(String[] args) {        Student stu[]={new Student("zhangsan",20,90.0f),                new Student("lisi",22,90.0f),                new Student("wangwu",20,99.0f),                new Student("sunliu",22,100.0f)};        java.util.Arrays.sort(stu,new StudentComparator());        for(Student s:stu)        {            System.out.println(s);        }    }}
<span style="font-size:18px;">StudentComparator类完整地实现了整个排序应用的算法,所以它是策略模式</span>

策略模式和模版方法模式对比

1.两者的意图不同。策略模式的意图是定义一个算法家族,把每个算法封装起来并让这些算法可以互换,这样客户可以轻易使用不同的算法。模版方法模式的意图是在抽象类定义一个算法大纲,而由子类定义其中某些步骤的内容,算法的个别步骤可以有不同的实现细节而算法的结果始终维持不变,达到代码的复用效果。


2.实现方法不同。策略模式是通过对象组合的方式实现的,而模版方法模式是通过继承实现的


3.各种的优势不同。模版方法对算法有更多的控制权,它的类的效率会比策略高效,会重复使用到的代码,都被放进超类,好让所有的子类共享,这使得它经常被用于创建框架。策略模式使用对象组合,因此更有弹性,可以方便选择使用不同的算法,加入新的算法也很方便,不需要依赖超类中方法的实现

0 0
原创粉丝点击