行为型模式
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。
今天开始我们讲的是行为型模式中的模板方法模式。老规矩,讲解之前再次熟悉下行为型模式包含:模板方法模式、策略模式、命令模式、职责链模式、状态模式、观察者模式、中介者模式、迭代器模式、访问者模式、备忘录模式、解释器模式。共11种设计模式。
模板方法模式(Template Method)
定义
定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。
解决问题
对某些已确定通用规范进行统一管理,不确定部分交由子类具体实现,但整体行为规范不变。
实现
定义通用规范方法,对于不确定部分设计为抽象方法,由子类进行完成。
结构
主要角色:
抽象类(Abstract Class):提供一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。这些方法的定义如下:
(1)模板方法:定义了算法的骨架,按某种规范调用其包含的基本方法。
(2)基本方法:是整个算法中的部分逻辑。由以下几种类型:
抽象方法:在抽象类中申明,由具体子类实现。
具体方法:在抽象类中已经实现,在具体子类中可以继承或重写它。
钩子方法:在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。
具体子类(Concrete Class):实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的一个组成步骤。
应用场景:
算法的整体步骤很固定,但其中个别部分易变时,这时候可以使用模板方法模式,将容易变的部分抽象出来,供子类实现。
当多个子类存在公共的行为时,可以将其提取出来并集中到一个公共父类中以避免代码重复。首先,要识别现有代码中的不同之处,并且将不同之处分离为新的操作。最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。
当需要控制子类的扩展时,模板方法只在特定点调用钩子操作,这样就只允许在这些点进行扩展。
注意:
模板方法一般用final修饰,不许子类修改其行为逻辑。
具体方法一般用private修饰,不许子类重写,但不是必须。
钩子方法可以没有,具体依据设计实现。
优点:
它封装了不变部分,扩展可变部分。它把认为是不变部分的算法封装到父类中实现,而把可变部分算法由子类继承实现,便于子类继续扩展。
它在父类中提取了公共的部分代码,便于代码复用。
部分方法是由子类实现的,因此子类可以通过扩展方式增加相应的功能,符合开闭原则。
缺点:
对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象。
父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度。
代码实现:披萨接单,制作。
//抽象类 MakeTemplate
public abstract class MakeTemplate {
protected PizzaOrder order;
//具体方法:打印订单
private void orderPrint() {
System.out.println("-------------订单信息-----------------");
System.out.println("name: " + order.getName());
System.out.println("name: " + order.getSize());
System.out.println("name: " + order.isPepper());
System.out.println("");
}
//具体方法:制作开始打印
private void startMake() {
System.out.println("-------------开始制作-----------------");
}
//具体方法:送入烤箱
private void putOven() {
System.out.println("放入烤箱....... ");
}
//具体方法:结束打印
private void endMake() {
System.out.println("-------------制作完成-----------------");
System.out.println("");
}
//抽象方法:具体制作
protected abstract void doMake();
//具体方法:控制时间(子类可重写)
protected void selectTime() {
System.out.println("默认 烘烤 20分钟......");
}
//模板方法:主方法
public final void make() {
orderPrint();
startMake();
doMake();
if (isPepperMake()) {
System.out.println("放辣椒......");
}
putOven();
selectTime();
endMake();
}
//钩子方法:
protected boolean isPepperMake() {
return true;
}
}
//具体子类:PizzaMaker
@Data
public class PizzaMaker extends MakeTemplate {
PizzaMaker() {
}
PizzaMaker(PizzaOrder order) {
this.order = order;
}
@Override
protected void doMake() {
System.out.println("选择面点......");
System.out.println("放入规定尺寸模具......");
System.out.println("加入辅料......");
System.out.println("进行修饰......");
}
@Override
protected void selectTime() {
System.out.println("自定义 35分钟 ......");
}
@Override
protected boolean isPepperMake() {
return order.isPepper();
}
}
//订单信息
@Data
public class PizzaOrder {
private double size;
private String name;
private boolean isPepper;
public void setPepper(boolean pepper) {
isPepper = pepper;
}
}
//模拟客户端
public class ClientDemo {
public static void main(String[] args) {
PizzaOrder order = new PizzaOrder();
order.setName("甜甜圈披萨");
order.setSize(9.0);
order.setPepper(false);
MakeTemplate maker = new PizzaMaker(order);
maker.make();
System.out.println("---------------订单2------------------");
PizzaOrder order2 = new PizzaOrder();
order2.setName("青椒圈披萨");
order2.setSize(11.0);
order2.setPepper(true);
MakeTemplate maker2 = new PizzaMaker(order2);
maker2.make();
}
}
扩展
在模板方法模式中,基本方法包含:抽象方法、具体方法和钩子方法,正确使用“钩子方法”可以使得子类控制父类的行为。
好了,关于模板方法模式的说明,馆长就先讲到这里。谢谢各位看官!
23 种设计模式不是孤立存在的,很多模式之间存在一定的关联关系,在大的系统开发中常常同时使用多种设计模式,或者模式与模式之间的组合进行生成更加强大的程序功能。