目录
一、行为型模式
一句话概括行为型模式
行为型模式:类或对象间如何交互、如何划分职责,从而更好的完成任务.
1.1、模板方法模式
1.1.1、概念
在一个算法骨架中,将某些算法的步骤延迟倒子类中,使得这些算法的可以根据具体的环境实现.
这就像是,我们在设计一个程序的时候经常可能会遇到这种情况:“设计了一个算法步骤,确定了这些步骤的执行顺序,但其中某些步骤还是未知,需要根据具体的业务情况而定”,此时就可以使用模板方法模式,使其放到子类实现.
例如,炒菜的步骤时固定的,分为倒油、热油、倒入要炒食物、倒调料、翻炒这几个步骤,其中 倒油、热油、翻炒这几个步骤是固定的,而炒什么食物 和 倒调料 都是要根据情况而定的.
模板方法模式包含角色:
- 抽象类:给出一套算法的具体实现和执行顺序,其中包含一些在子类中实现的抽象方法.
- 具体子类:实现抽象类中定义的抽象方法,他们也是算法执行逻辑的组成步骤.
1.1.2、案例实现
例如上述炒菜案例.
/**
* 抽象类: 做菜类
*/
public abstract class DoCooking {
public void doCooking() {
//1.倒油
pourOil();
//2.热油
hotOil();
//3.倒食物
pourFood();
//4.添加调料
addSeasoning();
//5.翻炒
fry();
}
private void pourOil() {
System.out.println("倒油");
}
private void hotOil() {
System.out.println("热油");
}
/**
* 添加食物
*/
protected abstract void pourFood();
/**
* 添加调料
*/
protected abstract void addSeasoning();
private void fry() {
System.out.println("翻炒");
}
}
/**
* 具体子类: 处理鸡蛋
*/
public class HandlerEgg extends DoCooking {
@Override
protected void pourFood() {
System.out.println("将鸡蛋下锅");
}
@Override
protected void addSeasoning() {
System.out.println("添加酱油");
}
}
/**
* 具体子类: 处理米饭
*/
public class HandlerRice extends DoCooking {
@Override
protected void pourFood() {
System.out.println("将米饭下锅");
}
@Override
protected void addSeasoning() {
System.out.println("添加葱花");
}
}
public class Client {
public static void main(String[] args) {
//1.炒鸡蛋
HandlerEgg egg = new HandlerEgg();
egg.doCooking();
System.out.println("===================");
//2.炒米饭
HandlerRice rice = new HandlerRice();
rice.doCooking();
}
}
执行结果如下:
1.1.3、案例实现(项目实战)
以专辑信息处理流程为例,我们可以使用模板方法模式来定义一个通用的专辑处理流程.
- 公共的逻辑:验证、记录日志等.
- 抽象逻辑:专辑的相关操作,如新增专辑、修改专辑.
data class Album (
var title: String,
var content: String,
)
abstract class AlbumProcessor {
//模板方法,定义了专辑处理的算法骨架
fun processAlbum(album: Album) {
valid(album) //验证专辑有效性
logStart(album) //记录开始处理日志
doProcess(album) //执行具体的专辑处理逻辑
logEnd(album) //记录结束处理日志
}
private fun valid(album: Album) {
// 校验专辑标题、内容、图片是否合法
println("Valid album ......")
}
private fun logStart(album: Album) {
//记录专辑处理开始的日志
println("[album title: ${album.title}] log start....")
}
private fun logEnd(album: Album) {
//记录专辑处理结束的日志
println("[album title: ${album.title}] log end")
}
//抽象方法,由子类实现专辑的具体处理逻辑
protected abstract fun doProcess(album: Album)
}
//专辑创建处理器
class AlbumCreateProcessor: AlbumProcessor() {
override fun doProcess(album: Album) {
//保存专辑到数据库
println("save to db")
}
}
//专辑修改处理器
class AlbumEditProcessor: AlbumProcessor() {
override fun doProcess(album: Album) {
//更新专辑到数据库
println("update to db")
}
}
使用实例如下
fun main() {
val album = Album(
title = "Home|Gradle",
content = "Build better software, faster. The leading software platform for improving developer productivity. Now supporting Maven, Bazel, sbt, and Gradle build systems."
)
//创建专辑
val createProcessor = AlbumCreateProcessor()
createProcessor.processAlbum(album)
println("=========================================")
//修改专辑
album.title = "Maven Good"
val editProcessor = AlbumEditProcessor()
editProcessor.processAlbum(album)
}
运行结果如下:
1.1.4、优缺点
优点:
提高代码复用性:将相同代码放到抽象的父类中,不同实现放到不同子类中.
符合开闭原则:将来如果增加一个相关业务吗,只需要扩展实现一个子类,无需修改原有代码.
缺点:
增加系统复杂度:每一个不同实现都需要定义一个子类,会导致类的数量增加,系统更加庞大.
1.1.5、使用场景
- 算法的整体步骤固定,只有个别容易改变.
- 需要通过子类来决定父类算法中的某步骤的具体实现.