剖析过工厂方法、抽象工厂和建造者模式之后,想必都很不屑模板方法模式,So easy,Leader再也不用担心我会出烂代码了!
原谅我例穷(配合词穷理解一下),今天的模板方法模式我们继续来createHuman吧!
昨天吃完饭的时候突然觉得,我这几天都在扯什么白人黑人,会说会笑的废话,能不能编故事变得有深度一点呢?对自己的想象力实在是……只能用“不怎么滴”形容吧!
今天补充一下场景吧!
从前,有一个地主,要雇佣家丁,但是随着人口老龄化严重,又加上计划生育效果太好,雇一个黑人成本都很高,更不用说白人了,怎么样才能才能解决家丁人手不足呢?于是找到了我(开厂的,可以按照各种客户需求定制humanModel生产各种看起来就像是人的木头人,做事效率甚至比人更高效)。但是地主说了,不希望家里就像是个机器工厂,这些家丁能不能有黑白之分,会说会笑,比如守门口的家丁,我希望他是会笑的白人,在马厩喂马的是会说话的黑人就可以了……
客户的需求就这么简单,你说怎么办呢?
看代码吧!
先看HumanModel(抽象类)
package com.freedom.template;
public abstract class HumanModel {
final public void createHuman(){
this.say();
this.smile();
}
protected abstract void say();
protected abstract void smile();
}
然后定义黑人、白人
package com.freedom.template;
public class BlackHuman extends HumanModel{
@Override
protected void say() {
System.out.println("black human can say anything!");
}
@Override
protected void smile() {
System.out.println("black human can smile!");
}
}
package com.freedom.template;
public class WhiteHuman extends HumanModel{
@Override
protected void say() {
System.out.println("white human can say anything!");
}
@Override
protected void smile() {
System.out.println("white human can smile!");
}
}
Test一下
package com.freedom.template;
import org.junit.Test;
public class TestTemplate {
@Test
public void client() {
WhiteHuman wh = new WhiteHuman();
wh.createHuman();
BlackHuman bh = new BlackHuman();
bh.createHuman();
}
}
/*
运行结果:
white human can say anything!
white human can smile!
black human can say anything!
black human can smile!
Black man can not smile!
*/
一开始的需求分析的有点问题,客户要关心模型的黑人、白人会说、会笑的过程吗?只要在createHuman的过程中得到一个符合要求的家丁(输出一个人就可以了),所以我们不需要暴露这么多的方法,故把抽象类上的四个方法设置为protected 访问权限,好了,既然客户不关心这几个方法,而且这四个方法都是由子类来实现的,那就设置成protected 模式。咦~,那还有个缺陷,createHuman方法既然子类都不修改,那是不是可以设置成final 类型呢?(感谢大众给我吹水的机会……嘻嘻)
继续 八一下需求哈,土豪地主说了,这不行呀,还是一个墨模子,都会说会笑,就不能可控点吗?有些我希望它不会说只会笑,有些我希望他只会笑不会说,再改进一下吧!
那我就继续实现smile变得可控,say的留给大家实现。
first,改进一些HumanModel,增加一个方法isSmile(),默认返回true,会笑。
package com.freedom.template;
public abstract class HumanModel {
final public void createHuman(){
this.say();
if(isSmile()){
this.smile();
}
}
protected abstract void say();
protected abstract void smile();
protected boolean isSmile(){
System.out.println("Default value is yes! Smile!");
return true;
}
}
然后黑人喂马的不需要会笑
package com.freedom.template;
public class BlackHuman extends HumanModel{
@Override
protected void say() {
System.out.println("black human can say anything!");
}
@Override
protected void smile() {
System.out.println("black human can smile!");
}
@Override
protected boolean isSmile(){
System.out.println("Black man can not smile!");
//返回false,不会笑
return false;
}
}
//Test
@Test
public void client2() {
BlackHuman bh = new BlackHuman();
bh.createHuman();
}
/*
运行结果:
black human can say anything!
Black man can not smile!
*/
白家丁是看门的,要迎接客人的要笑,在厨房劈柴的不需要,所以给他一个setSmile(boolen isSmile)方法吧,根据需要灵活产出。
package com.freedom.template;
public class WhiteHuman extends HumanModel{
@Override
protected void say() {
System.out.println("white human can say anything!");
}
@Override
protected void smile() {
System.out.println("white human can smile!");
}
private boolean smileFlag = true;
@Override
protected boolean isSmile(){
return this.smileFlag;
}
public void setSmile(boolean isSmile){
this.smileFlag = isSmile;
}
}
//Test
@Test
public void client3() {
WhiteHuman wh = new WhiteHuman();
System.out.println("我是守门的白家丁");
wh.setSmile(true);
wh.createHuman();
WhiteHuman wh2 = new WhiteHuman();
System.out.println("我是厨房劈柴的白家丁");
wh2.setSmile(false);
wh2.createHuman();
}
/*
我是守门的白家丁
white human can say anything!
white human can smile!
我是厨房劈柴的白家丁
white human can say anything!
*/
总结一下模板方法模式,模板方法模式就是在模板方法中按照一个的规则和顺序调用基本方法,具体到我们上面那个例子就是createHuman方法按照规定的顺序(先调用say,然后再调用smile,还是倒过来,并且由isSmile方法的返回值确定createHuman中的执行只能执行哪些方法,模板方法是通过汇总或排序基本方法而产生的结果集。模板方法在一些开源框架中应用很多,它提供了一个抽象类,然后开源框架写了一堆子类,在《Lucene In Action》中就说明了,如果你需要扩展功能,可以继承了这个抽象类,然后修改protected 方法,再然后就是调用一个类似execute 方法,就完成你的扩展开发,确实是一种简单的模式。
在写程序的时候经常有人会问,“父类怎么调用子类的方法”,这个问题很有普遍性。父类是否可以调用子类的方法呢?当然能,但强烈的、极度不建议,怎么做呢?
1. 把子类传递到父类的有参构造中,然后调用;
2.使用反射的方式调用,你使用了反射还有谁不能调用的?!
3.父类调用子类的静态方法。
这三种都是父类直接调用子类的方法,好用不?好用!解决问题了吗?解决了!项目中允许使用不?不允许!我就一直没有搞懂为什么要父类调用子类的方法,如果一定要调用子类,那为什么要继承它呢?搞不懂。其实这个问题可以换个角度去理解,在重写了父类部分方法后,再调用从父类继承的方法,产生不同的结果(这正是模板方法模式),是不是也可以理解为父类调用了子类的方法呢?你修改了子类,影响了父类的结果,模板方法模式要的就是这样的效果,同时也是你要个效果。
今天是Chrismas,所以就这么愉快地结束吧!
Merry Chrismas! Everybody……
源码下载:http://download.youkuaiyun.com/detail/github_22022001/8298159