05_模板方法模式
【模板方法】
定义一个操作中的算法框架,将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
【模板方法的抽象类中主要包含两部分】
[ 基本方法 ]
也称为基本操作,是由子类来实现的方法,并在模板方法中被调用。
[ 模板方法 ]
可以有一个或几个,一般是一个具体的方法,也就是一个框架,实现了对基本方法的调度,完成固定的逻辑。
【注意】
抽象模板中的基本方法尽量设计为protected类型,符合迪米特法则,不需要暴露的属性或方法尽量不要设置为protected类型,实现类若非必要,尽量不要扩大父类中的访问权限。
【模板方法例子】
package com.Higgin.TemplateMethod; abstract class Person{ //1.拿水果 protected abstract void getFruit(); //2.拿饭菜 protected abstract void getMeal(); //3.拿汤 protected abstract void getSoup(); //4.全部吃了 protected abstract void eatAll(); //5.把餐盘放到清洗间 protected abstract void putForClean(); //整个吃中饭的流程 public void havingDinner(){ this.getFruit(); this.getMeal(); this.getSoup(); this.eatAll(); this.putForClean(); } } class Employee extends Person{ @Override protected void getFruit() { System.out.println("员工拿水果..."); } @Override protected void getMeal() { System.out.println("员工拿饭菜..."); } @Override protected void getSoup() { System.out.println("员工拿汤..."); } @Override protected void eatAll() { System.out.println("员工将所有食物吃干净..."); } @Override protected void putForClean() { System.out.println("员工将餐具放置于清洗间..."); } } /** * 客户端 */ public class TestTemplateMethod { public static void main(String[] args) { Person employee=new Employee(); employee.havingDinner(); } }
【运行结果】
【模板方法的优点】
1.封装不变部分,扩展可变部分。
把认为不变部分的算法封装到父类实现,而可变部分的则可以通过继承来继续扩展。
2.提取了公共部分的代码,便于维护。
在抽象类中将整个流程所需的方法封装到一个方法中,方便维护。
3.行为由父类控制,子类实现
基本方法由子类实现,因此子类可以通过扩展的方式增加相应的功能,符合开闭原则。
【模板方法的缺点】
我们一般会在抽象类中负责最抽象、最一般的事物属性或方法,实现类完成具体的事物属性或方法。但是模板方法却颠倒了,抽象类定义了部分抽象方法,由子类实现,子类执行的结果影响了父类的执行结果,即对父类产生了影响,在复杂项目会增加代码的阅读难度。
【模板方法的使用场景】
* 多个子类有共有的方法,并且逻辑相同。
* 重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现。
* 重构的时候,模板方法模式是经常使用的一个模式,把相同的代码抽取到父类中,然后通过钩子方法约束其行为。
【钩子方法案例】
package com.Higgin.TemplateMethod; abstract class Person{ //1.拿水果 protected abstract void getFruit(); //2.拿饭菜 protected abstract void getMeal(); //3.拿汤 protected abstract void getSoup(); //4.全部吃了 protected abstract void eatAll(); //5.把餐盘放到清洗间 protected abstract void putForClean(); //钩子方法:是否拿汤(默认要拿) protected boolean isGetSoup(){ return true; } //整个吃中饭的流程 public void havingDinner(){ this.getFruit(); this.getMeal(); if(isGetSoup()){ //使用钩子方法进行判断 this.getSoup(); } this.eatAll(); this.putForClean(); } } class Employee extends Person{ @Override protected void getFruit() { System.out.println("员工拿水果..."); } @Override protected void getMeal() { System.out.println("员工拿饭菜..."); } @Override protected void getSoup() { System.out.println("员工拿汤..."); } @Override protected void eatAll() { System.out.println("员工将所有食物吃干净..."); } @Override protected void putForClean() { System.out.println("员工将餐具放置于清洗间..."); } private boolean soupFlag=true; //是否要汤的标志 //通过该方法设置钩子方法的返回值 protected void setSoupFlag(boolean soupFlag){ this.soupFlag=soupFlag; } //覆写父类的isGetSoup()钩子方法 protected boolean isGetSoup(){ return this.soupFlag; } } /** * 客户端 */ public class TestTemplateMethod { public static void main(String[] args) { Person employee=new Employee(); employee.havingDinner(); System.out.println("==================================================="); Employee employee2=new Employee(); employee2.setSoupFlag(false); employee2.havingDinner(); } }
【运行结果】