美文网首页技术文架构设计与重构程序员
设计模式系列之九模板方法模式

设计模式系列之九模板方法模式

作者: 梦中人在梦中 | 来源:发表于2016-12-17 23:56 被阅读59次

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

    有一个泡茶和冲咖啡的业务,他们都有差不多相似的流程。

    一、不使用设计模式

    public class Tea {
        //泡茶流程
        void process() {
            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 Coffee {
        //冲咖啡流程
        void process() {
            boilWater();
            brewCoffeeGrinds();
            pourInCup();
            addSugarAndMilk();
        }
    
        public void boilWater() {
            System.out.println("烧水");
        }
    
        public void brewCoffeeGrinds() {
            System.out.println("冲咖啡");
        }
    
        public void pourInCup() {
            System.out.println("倒进杯子");
        }
    
        public void addSugarAndMilk() {
            System.out.println("加牛奶和糖");
        }
    }
    

    二、模板方法模式的使用

    下面以一个代码样例来说明模板方法模式的使用。

    //定义模板方法
    public abstract class TemplateMethod {
        //冲咖啡和泡茶的模板,注意这里的final,意味着该方法不可修改,即模板中方法的先后顺序被固定
        final void template() {
            //烧水
            boilWater();
            //冲泡:用沸水"浸泡"茶叶/用沸水"冲泡"咖啡
            brew();
            //把泡好的饮料倒进杯子
            pourInCup();
            //加调料
            addCondiments();
        }
        /**这两个方法交给子类去实现**/
        //茶应该"浸泡",咖啡应该"冲泡"
        abstract void brew();
        //茶加柠檬,咖啡加牛奶和糖
        abstract void addCondiments();
    
        /**这两个方法属于公用方法**/
        void boilWater() {
            System.out.println("烧水");
        }
        void pourInCup() {
            System.out.println("倒进杯子");
        }
    }
    
    public class Tea extends TemplateMethod {
        public void brew() {
            System.out.println("浸泡");
        }
        public void addCondiments() {
            System.out.println("加柠檬");
        }
    }
    
    public class Coffee extends TemplateMethod {
        public void brew() {
            System.out.println("冲泡");
        }
        public void addCondiments() {
            System.out.println("加糖和牛奶");
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            Tea tea = new Tea();
            Coffee coffee = new Coffee();
            //泡茶
            tea.template();
            //冲咖啡
            coffee.template();
        }
    }
    

    三、使用钩子(hook)来做一些其它操作

    //定义模板方法
    public abstract class TemplateMethodWithHook {
        //冲咖啡和泡茶的模板,注意这里的final,意味着该方法不可修改,即模板中方法的先后顺序被固定
        final void template() {
            //烧水
            boilWater();
            //冲泡:用沸水"浸泡"茶叶/用沸水"冲泡"咖啡
            brew();
            //把泡好的饮料倒进杯子
            pourInCup();
            //加调料
            if (customerWantsCondiments()) {
                addCondiments();
            }
        }
        /**这两个方法交给子类去实现**/
        //茶应该"浸泡",咖啡应该"冲泡"
        abstract void brew();
        //茶加柠檬,咖啡加牛奶和糖
        abstract void addCondiments();
    
        /**这两个方法属于公用方法**/
        void boilWater() {
            System.out.println("烧水");
        }
        void pourInCup() {
            System.out.println("倒进杯子");
        }
    
        //这里是个钩子,子类可决定是否需要加调料。也就是说子类可通过这个hook控制模板定义的逻辑
        boolean customerWantsCondiments() {
            return true;
        }
    }
    
    public class TeaWithHook extends TemplateMethod {
    
        public void brew() {
            System.out.println("浸泡");
        }
        public void addCondiments() {
            System.out.println("加柠檬");
        }
    
        public boolean customerWantsCondiments() {
            //不需要加柠檬
            return false;
        }
    }
    
    public class CoffeeWithHook extends TemplateMethod {
    
        public void brew() {
            System.out.println("冲泡");
        }
        public void addCondiments() {
            System.out.println("加糖和牛奶");
        }
    
        public boolean customerWantsCondiments() {
            //需要加糖和牛奶
            return true;
        }
    }
    
    public class TestHook {
        public static void main(String[] args) {
            TeaWithHook teaHook = new TeaWithHook();
            CoffeeWithHook coffeeHook = new CoffeeWithHook();
            //泡茶,不加柠檬
            teaHook.template();
            //冲咖啡,加糖和牛奶
            coffeeHook.template();
        }
    }
    

    四、比较

    不使用设计模式 使用模板方法模式
    Coffee和Tea主导一切;它们控制了算法 TemplateMethod控制了一切,它拥有算法,并且保护这个算法
    Coffee和Tea之间存在着重复的代码 通过TemplateMethod类实现了代码的复用
    如果算法变了,需要修改Coffee和Tea类 新增算法或调整顺序只需要修改TemplateMethod类
    由于类的组织不具有弹性,新加入第三种类型时需要完全重写一份 由于有模板存在,只需要实现差异化的逻辑即可
    算法的知识和它的实现会分散在许多类中 TemplateMethod类专注在算法本身,而由子类提供完整的实现

    上一篇:<a href="http://muchstudy.com/2016/12/17/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E7%B3%BB%E5%88%97%E4%B9%8B%E5%85%AB%E5%A4%96%E8%A7%82%E6%A8%A1%E5%BC%8F/">设计模式系列之八外观模式</a>
    下一篇:<a href="http://muchstudy.com/2016/12/20/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E7%B3%BB%E5%88%97%E4%B9%8B%E5%8D%81%E8%BF%AD%E4%BB%A3%E5%99%A8%E6%A8%A1%E5%BC%8F/">设计模式系列之十迭代器模式</a>

    相关文章

      网友评论

        本文标题:设计模式系列之九模板方法模式

        本文链接:https://www.haomeiwen.com/subject/kveamttx.html