1.这个模式比较简单,我们举⼀个银行贷款申请流程程序的例子(这个并非是书中的例子):
申请贷款,银行要检查这个客户的⼀些事宜,譬如客户收支状况记录、从三个地方拿到他的信
用记录、得到其他已有相关债务信息、得到借债人股票市值、得到借债人未来收入预期分析等
等。我们可以设计如下⼀个模板方法:
abstract class CheckBackground {
public abstract void checkBank();
public abstract void checkCredit();
public abstract void checkLoan();
public abstract void checkStock();
public abstract void checkIncome();
public void check() {//模板方法为非抽象的,可以设置为final,这样子类就不会修改这个流程了。
checkBank();
checkCredit();
checkLoan();
checkStock();
checkIncome();
}
}
我们的贷款类就可以如下这么设计了,实现了模板方法中的抽象方法:
class LoanApp extends CheckBackground {
private String name;
public LoanApp(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void checkBank() {
//ck acct, balance
System.out.println("check bank...");
}
public void checkCredit() {
//ck score from 3 companies
System.out.println("check credit...");
}
public void checkLoan() {
//ck other loan info
System.out.println("check other loan...");
}
public void checkStock() {
//ck how many stock values
System.out.println("check stock values...");
}
public void checkIncome() {
//ck how much a family make
System.out.println("check family income...");
}
//other methods
}
2.这个模式的核心思想是“抽象”。首先作为模板方法,它必须是⼀个方法(废话……),它可以
作为⼀个算法的例子,在模板方法中,每⼀个步骤都要由另⼀个方法来完成,某些方法是由这
个类完成,某些则是由这个类的子类完成(需要由子类提供的方法必须在超类中声明为抽象)
——模板方法定义了⼀个算法的步骤,并允许子类为⼀个或多个步骤提供实现,实质上模板方
法提供了⼀个算法的框架(Framework),步骤定死,而实现又子类进行。这个模式的优势在
于最大限度的发挥抽象能力,保证程序需求变更或者优化升级时必须进行的变更最小。注意、
包含模板方法的类本身要是抽象的。
3.我们能不能比较智能的控制算法呢,比如某些时候这个客户是⼀个VI P客户,我们不需要对其I
n come去进行检查,此时可以使用Hook(挂钩),在需要的时候把⼀些方法“挂上”。我们这样设
计这个模板方法类:
abst ract   cl ass Ch eckBackgrou n d  {
pu bl i c abst ract   v oi d  ch eckBan k();
pu bl i c abst ract   v oi d  ch eckCredi t ();
pu bl i c abst ract   v oi d  ch eckLoan ();
pu bl i c abst ract   v oi d  ch eckStock();
pu bl i c abst ract   v oi d  ch eckI n come();
publ ic void check()  {/ /模板方法为非抽象的
ch eckBan k();
ch eckCredi t ();
ch eckLoan ();     
i f(! ischeckVIP){/ /使用钩子,子类可以根据需要进行覆盖
ch eckStock();
}
ch eckI n come();
}
publ ic boolean  ischeckVIP(){/ /钩子函数
return  false;
}
}
挂钩函数除了可以让子类控制⼀些算法的流程以外,另⼀个功能是让子类有机会对模板方法中
某些即将发生的步骤做出反应。
注意,由于子类必须实现抽象类中的所有抽象方法,所以应该保持抽象方法的数目越少越好,
这就需要你在设计的时候对算法内的数据不要切割太细,同时粒度太大程序的弹性又受到限制
,这就需要你去权衡了,程序设计中太多的地方是平衡和妥协了。
4.我们此时引出⼀个新的OO原则——好莱坞原则:别电话给我们,我们会打电话给你——别调
用我们,我们会去调用你。
在这个原则之下,我们允许低层组件将自己挂钩到系统上,而高层组件会决定什么时候和如何
使用这些低层组件,我们把决策权放到高层模块中。也就是说,高层组件对待低层组件的方式
就是上边那句黑体字的原则。书中举了⼀个咖啡与茶的例子(有趣的是,《咖啡与茶》是丁薇
早年间的⼀张唱片的名字,我高⼀的时候买到了正版卡带)来解释模板方法模式与这个原则关
系,见原书(英文版)P297。这个原则和依赖倒置原则的关系是,后者交给我们如何尽量避免
使用具体类,而多使用抽象,注重体现如何避免依赖。前者则是通过创建框架和组件的⼀种技
巧,注重创建⼀个有弹性的设计,同时又防止其他类太过依赖它们,避免类的环状依赖。值得
注意的是,工厂方法是模板方法的⼀种特殊版本。
5.接着,我们看看Jav a中有什么是使用了这个模式的:数组排序方法sort (  )
sort ()的设计者希望这个方法能适用于所有的数组,所以将其设置为静态方法。而同时你必须实
现compartT o方法后才能使用sort方法,为了达到这⼀点,设计者利用了Comparabl e接口,提供
这个接口所声明的方法,也就是compartT o。
我们现在利用这个接口去设计⼀个鸭子的类,试图根据体重去对鸭子进行比较。
pu bl i c  cl ass Du ck  i mpl emen t s Comparabl e  {
St ri n g n ame;
i n t  wei gh t ;
pu bl i c Du ck(St ri n g n ame,   i n t  wei gh t )  {
th i s.n ame = n ame;
th i s.wei gh t  = wei gh t ;
}
pu bl i c St ri n g  toSt ri n g()  {
retu rn  n ame +  " wei gh s  " + wei gh t ;
}
pu bl i c  i n t   compareT o(Obj ect  obj ect )  {
Du ck oth erDu ck =  (Du ck)obj ect ;
i f   (th i s.wei gh t  < oth erDu ck.wei gh t )  {
retu rn   -1;
} el se  i f   (th i s.wei gh t  == oth erDu ck.wei gh t )  {
retu rn  0;
} el se  {  / /   th i s.wei gh t  > oth erDu ck.wei gh t
retu rn  1;
}
}
}
这样,我们就能直接使用数组中的sort方法了:
i mport   j av a.u t i l .Array Li st ;
i mport   j av a.u t i l .Array s;
pu bl i c  cl ass Du ckSortT estDri v e  {
pu bl i c  stat i c  v oi d mai n (St ri n g[ ]  args)  {
Du ck[ ]  du cks =  {
n ew Du ck("Daf f y ",  8),
n ew Du ck("Dewey ",  2),
n ew Du ck("Howard",  7),
n ew Du ck("Lou i e",  2),
n ew Du ck("Don al d",  10), 
n ew Du ck("Hu ey ",  2)
};
Sy stem.ou t .pri n t l n ("Before  sort i n g: ");
di spl ay (du cks);
Array s. sort (du cks);
Sy stem.ou t .pri n t l n ("/n Af ter  sort i n g: ");
di spl ay (du cks);
}
pu bl i c  stat i c  v oi d di spl ay (Du ck[ ]  du cks)  {
for  (i n t   i  = 0;   i  < du cks. l en gth ;   i ++)  {
Sy stem.ou t .pri n t l n (du cks[ i ] );
}
}
}
这和模板方法又有什么关系呢?
完成Comparabl e接口的compareT o方法使得元素自行提供比较大小的算法部分。这就有点像前
边我们的贷款程序中自己定义如何检查客户收入的函数⼀样。
我们再举两个例子:Swi n g:
i mport   j av a.awt . *;
i mport   j av ax . swi n g. *;
pu bl i c  cl ass My Frame ex ten ds  JFrame  {
pu bl i c My Frame(St ri n g  t i t l e)  {
su per(t i t l e);
th i s. setDefau l tCl oseOperat i on (JFrame.EXI T_ON_CLOSE);
th i s. setSi z e(300,300);
th i s. setVi si bl e(t ru e);
}
pu bl i c  v oi d pai n t (Graph i cs graph i cs)  {/ /默认情况下,它什么都不做,是⼀个挂钩,通过覆盖该
方法,你可以将自己的代码插入JFrame中,
su per .pai n t (graph i cs);
St ri n g msg =  "I   ru l e! ! ";
graph i cs.drawSt ri n g(msg,  100,  100);
}
pu bl i c  stat i c  v oi d mai n (St ri n g[ ]  args)  {
My Frame my Frame = n ew My Frame("Head Fi rst  Desi gn  Pat tern s");
}
}
Appl et:具体的appl et大量使用挂钩函数提供行为。
i mport   j av a.appl et .Appl et ;
i mport   j av a.awt .Graph i cs;
pu bl i c  cl ass My Appl et  ex ten ds  Appl et   {
St ri n g message;
pu bl i c  v oi d  i n i t ()  {
message =  "Hel l o Worl d,   I 'm al i v e! ";
repai n t ();
}
pu bl i c  v oi d  start ()  {
message =  "Now  I 'm  start i n g u p. . . ";
repai n t ();
}
pu bl i c  v oi d  stop()  {
message =  "Oh ,  n ow  I 'm bei n g  stopped. . . ";
repai n t ();
}
pu bl i c  v oi d dest roy ()  {
message =  "Goodby e,   cru el  worl d";
repai n t ();
}
pu bl i c  v oi d pai n t (Graph i cs g)  {
g.drawSt ri n g(message,  5,  15);
}
}
6.最后,我们比较⼀下模板方法模式和策略模式的异同。
前者定义⼀个算法的大纲,由子类(注意这里是继承)定义其中的某些步骤的内容,这样算法
的细节可有不同,但是算法的结构和流程保持不变,它对算法有更多的控制权。而后者定义了
⼀个算法的家族,并让这些算法互换,正因为每⼀个算法都被封装了起来,所以客户可以轻易
地使用不同的算法(不是通过继承而是接口的组合),它则更有弹性。
在线视频:h t tp: / / v . y ou ku . com/ v _sh ow/ i d_XMj U2Nz A0OTI 4.h tml

HeadFir st 设计模式学习笔记8--模板方法模式相关推荐

  1. HeadFir st 设计模式学习笔记21-- 解释者(Inter pr eter)模式拾零

    HeadFir st 设计模式学习笔记21-- 解释者(Inter pr eter)模式拾零 1.概述 这个模式是在不能叫做模式,它的作用是实现⼀种语言规范的解释器,比如罗马数字解释器. 2.实例 我 ...

  2. 设计模式学习笔记——模板(Template)模式

    设计模式学习笔记--模板(Template)模式 @(设计模式)[设计模式, 模板模式, template, 模板方法] 设计模式学习笔记模板Template模式 基本介绍 模板案例 类图 实现代码 ...

  3. 设计模式学习笔记——解释器(Interpreter)模式

    设计模式学习笔记--解释器(Interpreter)模式 @(设计模式)[设计模式, 解释器模式, Interpreter] 设计模式学习笔记解释器Interpreter模式 基本介绍 解释器案例 类 ...

  4. 设计模式学习笔记——命令(Command)模式

    设计模式学习笔记--命令(Command)模式 @(设计模式)[设计模式, 命令模式, command] 设计模式学习笔记命令Command模式 基本介绍 命令案例 类图 实现代码 Command接口 ...

  5. 设计模式学习笔记——代理(Proxy)模式

    设计模式学习笔记--代理(Proxy)模式 @(设计模式)[设计模式, 代理模式, proxy] 设计模式学习笔记代理Proxy模式 基本介绍 代理案例 类图 实现代码 Printable接口 Pri ...

  6. 设计模式学习笔记——状态(State)模式框架

    设计模式学习笔记--状态(State)模式框架 @(设计模式)[设计模式, 状态模式, State] 设计模式学习笔记状态State模式框架 基本介绍 状态案例 类图 实现代码 State接口 Day ...

  7. 设计模式学习笔记——备忘录(Memento)模式

    设计模式学习笔记--备忘录(Memento)模式 @(设计模式)[设计模式, 备忘录模式, memento] 设计模式学习笔记备忘录Memento模式 基本介绍 备忘录案例 类图 实现代码 Memen ...

  8. 设计模式学习笔记——观察者(Observer)模式

    设计模式学习笔记--观察者(Observer)模式 @(设计模式)[设计模式, 观察者模式, Observer] 设计模式学习笔记观察者Observer模式 基本介绍 观察者案例 类图 实现代码 Ob ...

  9. 设计模式学习笔记——外观(Facade)模式

    设计模式学习笔记--外观(Facade)模式 @(设计模式)[设计模式, 外观模式, facade] 设计模式学习笔记外观Facade模式 基本介绍 外观案例 类图 实现代码 Database类 ma ...

最新文章

  1. NSMutableParagraphStyle /NSParagraphStyle
  2. 前后端分离开发,日志应该如何进行记录,在出现问题的时候,方便定位问题
  3. Mybatis Plus——以XML方式使用 Wrapper 自定义SQL时IDEA错误[**expected, got ‘${‘]解决方案
  4. eclipse 面包屑开关 / 查看class再哪个jar中
  5. Spring 自动装配模式之byType
  6. 的主机名_如何在Mac 上更改电脑的名称或本地局域网主机名?
  7. 2020中国奢侈品消费者数字行为洞察报告
  8. 删除链表的倒数第n个节点 python_LeetCode 19.删除链表的倒数第N个节点(Python)
  9. mysql手工注入imformation_mysql 简单手工注入
  10. Oracle插入时间
  11. C++ 构造函数与析构函数
  12. 8 月社群专属福利活动开启!进群免费领取开发视频课程!
  13. 海康威视:工程项目不是我们的目标,对创新业务发展充满信心...
  14. springboot-day01-引入基础
  15. 读君山-七年阿里老人谈新人程序员的成长
  16. 每日算法系列【LeetCode 684】冗余连接
  17. Codeforces Round #381 (Div. 2) D. Alyona and a tree 树上二分+前缀和思想
  18. mysql修改有外键约束的表结构
  19. eclipse中出现代码覆盖的颜色信息,如何去掉
  20. PWA 应用列表及常用工具

热门文章

  1. AKH-0.66 MP-60×50 系列电流互感器(安科瑞-卓宋兰)
  2. flash player在 unbuntu linux 下,百度MP3音乐盒歌词显示乱码
  3. IAAS 云平台 Apache CloudStack 2016 年展望
  4. 如何做好技术演讲-口才提升篇章
  5. 佰马科技亮相中国通信展,参加智慧杆最受欢迎企业联展
  6. nn.BCELoss总结
  7. React cannot set property props of undefined
  8. 对豆瓣进行爬虫来获取相关数据(分别保存到Excel表格和sqlite中)
  9. MATLAB GUI制作快速入门
  10. 广结善缘,中国是人情社会。