福田网站建设方案服务,百度推广一个点击多少钱,app手机网站,遵义网站制作小程序学习难度#xff1a;⭐ #xff0c;比较常用 模板方法模式
在面向对象程序设计过程中#xff0c;程序员常常会遇到这种情况#xff1a;设计一个系统时知道了算法所需的关键步骤#xff0c;而且确定了这些步骤的执行顺序#xff0c;但某些步骤的具体实现还未知#xff0… 学习难度⭐ 比较常用 模板方法模式
在面向对象程序设计过程中程序员常常会遇到这种情况设计一个系统时知道了算法所需的关键步骤而且确定了这些步骤的执行顺序但某些步骤的具体实现还未知或者说某些步骤的实现与具体的环境相关。例如拿泡茶这件事来说可以分为4个步骤第一步洗茶具第二步烧开水第三步放入茶叶并根据不同的茶叶泡不同的时间第四步品茶。以上的一二四步都是一样的只有第三步不一样因此可以将一二四步具体实现好即模板方法。第三步则是用户自己需要实现的方法即抽象方法。模板方法的定义 定义一个操作中的算法骨架而将算法的一些步骤延迟到子类中使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。
模板方法Template Method模式包含以下主要角色 抽象类Abstract Class负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。 模板方法定义了算法的骨架按某种顺序调用其包含的基本方法。 基本方法是实现算法各个步骤的方法是模板方法的组成部分。基本方法又可以分为三种 抽象方法(Abstract Method) 一个抽象方法由抽象类声明、由其具体子类实现。 具体方法(Concrete Method) 一个具体方法由一个抽象类或具体类声明并实现其子类可以进行覆盖也可以直接继承。 钩子方法(Hook Method) 在抽象类中已经实现包括用于判断的逻辑方法和需要子类重写的空方法两种。 一般钩子方法是用于判断的逻辑方法这类方法名一般为isXxx返回值类型为boolean类型。 具体子类Concrete Class实现抽象类中所定义的抽象方法和钩子方法它们是一个顶级逻辑的组成步骤。
案例
【例】炒菜
炒菜的某些步骤是固定的分为开启灶台、倒油、炒菜、倒调料品、起锅共五个步骤。假设炒菜和倒调料品两个步骤不一样其他都一样现通过模板方法模式来用代码模拟。类图如下 代码
编写抽象模板类其中开炉灶、倒油、起锅都是固定的方法而炒菜和放调味品则是根据不同的菜品而不同的而cook()方法则是一个将上述步骤组合调用的一个方法使用final修饰不可被重写如下
// 烹饪抽象类
public abstract class AbstractCook {// 做菜很多步骤都一样的只是关键步骤不一样// 因此相同步骤作为模板实现好不同的自己实现private String food;public AbstractCook(String food){this.food food;}public void openStove(){//1. 开启灶台是相同步骤System.out.println(打开灶台将锅烧热);}public void pourOil(){//2. 倒油是相同步骤System.out.println(油倒入锅中并烧热);}//3. 翻炒时间和手法不一样public abstract void fry();//4. 不同菜的调味品不一样public abstract void pourSauce();//5. 出锅是一样的public void takeFood(){System.out.println(将炒好的food盛入餐盘中);}// final 修饰不被继承public final void cook(){openStove();pourOil();fry();pourSauce();takeFood();}
}
然后具体的菜品的制作继承上述模板类其中共同的步骤就不用重新写了只需要重写自己的炒菜和放调味品的具体方法
// 炒贵州黄牛肉类
public class CookBeef extends AbstractCook{public CookBeef() {super(贵州黄牛肉);}Overridepublic void fry() {System.out.println(牛肉下锅总共炒10分钟每个30秒翻一下);}Overridepublic void pourSauce() {System.out.println(放盐和味精其他放酱油、蒜末、辣椒、葱花去腥提鲜);}
}// 炒青菜类
public class CookVegetable extends AbstractCook{public CookVegetable() {super(青菜);}Overridepublic void fry() {System.out.println(蔬菜下锅总共炒2分钟每个5秒翻一下);}Overridepublic void pourSauce() {System.out.println(放盐和味精其他放耗油即可);}
}
客户端测试类
public class Main {public static void main(String[] args) {// 炒牛肉CookBeef cookBeef new CookBeef();cookBeef.cook();System.out.println(-----------------);// 炒青菜CookVegetable cookVegetable new CookVegetable();cookVegetable.cook();}
}输出结果 打开灶台将锅烧热 油倒入锅中并烧热 牛肉下锅总共炒10分钟每个30秒翻一下 放盐和味精其他放酱油、蒜末、辣椒、葱花去腥提鲜 将炒好的贵州黄牛肉盛入餐盘中 ----------------- 打开灶台将锅烧热 油倒入锅中并烧热 蔬菜下锅总共炒2分钟每个5秒翻一下 放盐和味精其他放耗油即可 将炒好的青菜盛入餐盘中 优点 提高代码复用性 将相同部分的代码放在抽象的父类中而将不同的代码放入不同的子类中。 实现了反向控制 通过一个父类调用其子类的操作通过对子类的具体实现扩展不同的行为实现了反向控制 并符合“开闭原则”。
缺点
对每个不同的实现都需要定义一个子类这会导致类的个数增加系统更加庞大设计也更加抽象。父类中的抽象方法由子类实现子类执行的结果会影响父类的结果这导致一种反向的控制结构它提高了代码阅读的难度。
适用场景
算法的整体步骤很固定但其中个别部分易变时这时候可以使用模板方法模式将容易变的部分抽象出来供子类实现。需要通过子类来决定父类算法中某个步骤是否执行实现子类对父类的反向控制。