《Head First 设计模式》学习笔记——模板方法模式

模板方法模式

eg:
要写一段程序实现泡茶和泡咖啡,方法如下:

泡茶的方法:

1.把水煮沸
2.用沸水浸泡茶叶
3.把茶倒进杯子
4.加柠檬

泡咖啡的方法:

1.把水煮沸
2.用沸水冲泡咖啡
3.把咖啡倒进杯子
4.加糖和牛奶

通过观察,我们可以发现这两种饮料的冲泡都采用了相同的算法:

1.把水煮沸
2.用热水泡咖啡或茶
3.把饮料倒进杯子里
4.在饮料内加入适当的调料

所以我们很自然的就会想到通过将公共的地方抽取出来,放在父类,子类继承父类,在方法中实现各自的操作,就像这样:

public abstract class CaffeineBeverage{
    void final 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");
    }
}

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

现在,当我们要冲泡咖啡或茶就很简单了,只要让子类Tea和Coffee继承CaffeineBeverage然后实现各自特有的步骤:

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");
    }
}

然后我们再直接调用子类的模板方法就可以了:

Tea myTea = new Tea();
myTea.prepareRecipe();

以上的实现就是模板方法模式,现在我们再来看下定义:

模板方法:

  • 是一个方法
  • 用作一个算法的模板
  • 算法内的每一个步骤都被一个方法代表
  • 某些方法是由父类处理的,某些方法是由子类处理的(声明为抽象)

定义

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

除了上述外,模板方法中可能还有“hook”(钩子)方法,这是一个默认不做事的方法,即在父类中有空实现或默认的实现,钩子的存在可以让子类有能力对算法的不同点进行挂钩,子类可以根据情况决定要不要覆盖它们如:

public abstract class CaffeineBeverage{
    void final prepareRecipe(){
        boilWater();
        brew();
        pourInCup();
        if(customerWantsCondiments){//顾客想要加饮料才执行addCondiments()方法
            addCondiments();
        }
    }

    abstract void brew();
    abstract void addCondiments();

    void boilWater(){
        //实现
        System.out.println("Boiling water");
    }

    void pourInCup(){
        //实现
        System.out.println("Pouring into cup");
    }

    boolean customerWantsCondiments(){//默认返回true,子类可以覆盖此方法(顾客不想加饮料时)
        return true;
    }
}

上述操作可以通过钩子作为条件控制,影响抽象类中的算法流程

钩子的作用:

1.让子类实现算法中可选的部分,或者在钩子对于子类的实现并不重要的时候,子类可以此钩子置之不理
2.让子类能够有机会对模板方法中某些即将发生的(或刚刚发生的)步骤作出反应

模板方法与策略模式比较

策略模式:

1.定义了一个算法家族,并让这些算法可以互换,正因为每一个算法都被封装起来了,所以客户可以轻易地使用不同的算法
2.通过对象组合的方式,让客户选择算法实现
3.使用对象组合,更有弹性,客户可以在运行时改变算法,主要改用不同的策略对象
4.不依赖任何人,整个算法都是自己搞定

模板方法

1.定义了一个算法的大纲,由子类定义其中某些步骤的内容,个别步骤可以有不同的实现细节,但是算法的结构依然维持不变
2.用继承进行算法的实现
3.对算法有更多的控制权,不会重复代码
4.依赖超类中的方法的实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值