一、介绍
模板模式,顾名思义,定义一个模板,将部分逻辑以具体方法或者具体构造函数的形式实现,在抽象类中声明一些抽象方法来迫使子类实现剩余的逻辑。
不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现,这就是模板方法模式的用意。
模板模式涉及到三个角色:
- 抽象类(AbstractClass):实现了模板方法,定义了算法的骨架;
- 具体类(ConcreteClass):实现抽象类中的抽象方法,已完成完整的算法;
- 客户角色:客户类提出使用具体类的请求;
二、示例
举个例子,以早上起床到上班所需要的操作为例,大致流程可以分为以下几步:穿衣服、刷牙、洗脸、吃早餐等。男生和女生的操作可能有些区别。
我们创建一个抽象的类,定义好大致的操作流程,如下:
/** * 抽象类 */ public abstract class AbstractPerson { /** * 定义操作流程 */ public void prepareGoWorking(){ dressing();//穿衣服 brushTeeth();//刷牙 washFace();//洗脸 eatBreakFast();//吃早餐 } /**穿衣服*/ protected abstract void dressing(); /**刷牙*/ protected void brushTeeth(){ System.out.println("刷牙"); } /**洗脸*/ protected void washFace(){ System.out.println("洗脸"); } /**吃早餐*/ protected abstract void eatBreakFast(); }
因为男生和女生的行为不一样,我们分别创建两个具体类,如下:
/** * 男生 * 具体实现类 */ public class ManPerson extends AbstractPerson{ @Override protected void dressing() { System.out.println("穿西装"); } @Override protected void eatBreakFast() { System.out.println("直接在公司吃早餐"); } }
/** * 女生 * 具体实现类 */ public class WomanPerson extends AbstractPerson{ @Override protected void dressing() { System.out.println("穿休闲衣服"); } @Override protected void eatBreakFast() { System.out.println("在家弄点吃的,或者在外面买一点小吃"); } }
创建一个客户端,实现如下:
public class TemplateClient { public static void main(String[] args) { //男生起床步骤 ManPerson manPerson = new ManPerson(); System.out.println("-----男生起床步骤----"); manPerson.prepareGoWorking(); System.out.println("-----女生起床步骤----"); //女生起床步骤 WomanPerson womanPerson = new WomanPerson(); womanPerson.prepareGoWorking(); } }
输出结果:
-----男生起床步骤---- 穿西装 刷牙 洗脸 直接在公司吃早餐 -----女生起床步骤---- 穿休闲衣服 刷牙 洗脸 在家弄点吃的,或者在外面买一点小吃
当然,模版模式的玩法,还不仅仅只有这些,还可以在模版模式中使用挂钩(hook)。
什么是hook
呢?存在一个空实现的方法,我们称这种方法为hook
。子类可以视情况来决定是否要覆盖它。
还是以上面为例子,比如吃完早餐就要出门上班,选择什么交通工具呢?
抽象类新增方法hook()
,内容如下:
/** * 抽象类 */ public abstract class AbstractPerson { /** * 定义操作流程 */ public void prepareGoWorking(){ dressing();//穿衣服 brushTeeth();//刷牙 washFace();//洗脸 eatBreakFast();//吃早餐 hook();//挂钩 } /**穿衣服*/ protected abstract void dressing(); /**刷牙*/ protected void brushTeeth(){ System.out.println("刷牙"); } /**洗脸*/ protected void washFace(){ System.out.println("洗脸"); } /**吃早餐*/ protected abstract void eatBreakFast(); /**挂钩*/ protected void hook(){}; }
男生具体实现类,重写hook()
方法,内容如下:
/** * 男生 * 具体实现类 */ public class ManPerson extends AbstractPerson{ @Override protected void dressing() { System.out.println("穿西装"); } @Override protected void eatBreakFast() { System.out.println("直接在公司吃早餐"); } @Override protected void hook() { System.out.println("乘地铁上班"); } }
运行测试类,男生具体实现类,输出结果:
-----男生起床步骤---- 穿西装 刷牙 洗脸 直接在公司吃早餐 乘地铁上班
当然,还有其他的玩法,比如女生洗完脸之后,可能需要化妆,我们再次将抽象类进行处理,内容如下:
/** * 抽象类 */ public abstract class AbstractPerson { /** * 定义操作流程 */ public void prepareGoWorking(){ dressing();//穿衣服 brushTeeth();//刷牙 washFace();//洗脸 //是否需要化妆,默认不化妆 if(isMakeUp()){ System.out.println("进行化妆"); } eatBreakFast();//吃早餐 hook();//挂钩 } /**是否需要化妆方法*/ protected boolean isMakeUp(){ return false; } /**穿衣服*/ protected abstract void dressing(); /**刷牙*/ protected void brushTeeth(){ System.out.println("刷牙"); } /**洗脸*/ protected void washFace(){ System.out.println("洗脸"); } /**吃早餐*/ protected abstract void eatBreakFast(); /**挂钩*/ protected void hook(){}; }
女生具体实现类,重写isMakeUp()
方法,内容如下:
/** * 女生 * 具体实现类 */ public class WomanPerson extends AbstractPerson{ @Override protected void dressing() { System.out.println("穿休闲衣服"); } @Override protected void eatBreakFast() { System.out.println("在家弄点吃的,或者在外面买一点小吃"); } @Override protected boolean isMakeUp() { return true; } }
运行测试类,女生具体实现类,输出结果:
-----女生起床步骤---- 穿休闲衣服 刷牙 洗脸 进行化妆 在家弄点吃的,或者在外面买一点小吃