江湖中流传无招胜有招,飞花摘叶可伤人,那是高手的化境。但要成为高手,必须从基础开始。所谓招式,或势大力沉,或快速机巧,或出人意料,都是有迹可寻。
对于软件,对于JAVA自也有前辈高手,或归纳,或原创,或借鉴,汇成了一些套路,程序员称之为模式。
就先学习下模板方法吧
引子
中国人好饮茶,老外爱coffee.
要泡茶,一般经过以下4个步骤
1.烧水
2.开水倒进茶杯
3.放茶叶,开始泡茶
4.茶水里加柠檬(年轻人喜欢这么干)
看看Tea类
/**
* @copyright remark holdings
*/
package com.proxy.proxya.design.template;
/**
* @author kobe_t
* @date 2018/2/15 22:22
*/
public class Tea {
/**
* 烧水
*/
public void boilWater() {
System.out.println("Boiling water");
}
/**
* 将开水倒进杯子
*/
public void pourInCup() {
System.out.println("pour water into a Cup");
}
/**
* 将茶叶浸泡
*/
public void SteepingToBag() {
System.out.println("Steeping the tea");
}
/**
* 加柠檬
*/
public void addLemon() {
System.out.println("Adding lemon");
}
}
原料有了,怎么泡呢,恩,应该有个方法来控制泡茶流程
/**
* 泡茶
*/
void prepareRecipe() {
boilWater();
pourInCup();
SteepingToBag();
addLemon();
}
要喝咖啡,一般经过以下4个步骤
1.烧水
2.开水倒进茶杯
3.把咖啡倒进杯子
4.咖啡里加糖或牛奶(老外都喜欢?)
再看看Coffee
/**
* @copyright remark holdings
*/
package com.proxy.proxya.design.template;
/**
* @author kobe_t
* @date 2018/2/15 22:12
*/
public class Coffee {
/**
* 烧水
*/
public void boilWater() {
System.out.println("Boiling water");
}
/**
* 将开水倒进杯子
*/
public void pourInCup() {
System.out.println("pour water into a Cup");
}
/**
* 把咖啡倒进杯子
*/
public void brewCofferGrinds() {
System.out.println("Dripping Coffee through filter");
}
/**
* 加糖和牛奶
*/
public void addSugarAndMilk() {
System.out.println("Adding sugar and milk");
}
}
现在加个控制冲咖啡的方法
void prepareRecipe() {
boilWater();
pourInCup();
brewCofferGrinds();
addSugarAndMilk();
}
恩,有发现了,上面有一样的步骤
1.烧水
2.开水倒进茶杯
那说明产生了重复代码,我们一般会这么干,提取公用方法,生成基类,类似如下
/**
* @copyright remark holdings
*/
package com.proxy.proxya.design.template;
/**
* @author kobe_t
* @date 2018/2/15 22:33
*/
public class AbstractCoffineBeverage {
/**
* 烧水
*/
void boilWater() {
System.out.println("Boiling water");
}
/**
* 将开水倒进杯子
*/
void pourInCup() {
System.out.println("pour water into a Cup");
}
}
Tea和Coffee继续这个基类,恩。这样好像还不错,还能进一步吗,能吗?
泡茶和冲咖啡都是4步,看下不一样的2步
泡茶:是把茶叶放进杯子里泡,咖啡:把咖啡放进杯子冲
泡茶:加柠檬;咖啡:加糖加牛奶。闻到了什么,对,其实他们步骤也是一样的,所以控制的流程方法应该是一样的
prepareRecipe
那么,我们的基类可以这样
/**
* @copyright remark holdings
*/
package com.proxy.proxya.design.template;
/**
* @author kobe_t
* @date 2018/2/15 22:33
*/
public abstract class AbstractCoffineBeverage2 {
/**
* 烧水
*/
void boilWater() {
System.out.println("Boiling water");
}
/**
* 将开水倒进杯子
*/
void pourInCup() {
System.out.println("pour water into a Cup");
}
public abstract void brew();
public abstract void addCondiments();
}
基类做为抽象类,并且重新命名一个brew,addCondiments方法,分别表示冲泡与添加调料,那么控制的泡茶,冲咖啡的方法就是一个公用的了,子类不能改变它的流程
final void prepareRecipe() {
boilWater();
brew();
pourInCup();
addCondiments();
}
而此时对应的Tea和Coffee变成如下
/**
* @copyright remark holdings
*/
package com.proxy.proxya.design.template;
/**
* @author kobe_t
* @date 2018/2/15 22:12
*/
public class Coffee extends AbstractCoffineBeverage {
@Override
public void brew() {
System.out.println("Dripping Coffee through filter");
}
@Override
public void addCondiments() {
System.out.println("Adding sugar and milk");
}
}
/**
* @copyright remark holdings
*/
package com.proxy.proxya.design.template;
/**
* @author kobe_t
* @date 2018/2/15 22:22
*/
public class Tea extends AbstractCoffineBeverage {
@Override
public void brew() {
System.out.println("Steeping the tea");
}
@Override
public void addCondiments() {
System.out.println("Adding lemon");
}
}
那么我们泡茶和冲咖啡的流程就统一了,
要泡茶
Tea tea = new Tea();
tea.prepareRecipe();
System.out.println();
输出
Boiling water
Steeping the tea
pour water into a Cup
Adding lemon
冲咖啡
Coffee coffee = new Coffee();
coffee.prepareRecipe();
输出
Boiling water
Dripping Coffee through filter
pour water into a Cup
Adding sugar and milk
Ok,这就是模板方法:
在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤,多体会,多揣摩,多实践,三多