博主介绍: ✌博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家✌
Java知识图谱点击链接:体系化学习Java(Java面试专题)
💕💕 感兴趣的同学可以收藏关注下 ,不然下次找不到哟💕💕
文章目录
- 1、什么是模板方法模式
- 2、模板方法模式的优缺点
- 3、模板方法模式的应用场景
- 4、模板方法模式的结构
- 5、模板方法模式的代码案例
1、什么是模板方法模式
模板方法模式(Template Method Pattern)是一种行为设计模式,它定义了一个算法的框架,将一些步骤的具体实现延迟到子类中,使得子类可以改变算法的某些特定步骤,而不改变算法的结构。
模板方法模式的核心思想是:定义一个抽象类,其中包含一个模板方法,该方法中定义了算法的骨架,然后将一些步骤的实现交给子类去完成。子类可以重写这些步骤,从而改变算法的具体实现,但是算法的结构不会改变。
2、模板方法模式的优缺点
模板方法模式的优点包括:
-
将算法的骨架和具体实现分离,提高了代码的复用性和可维护性。
-
子类可以灵活地改变算法的某些步骤,从而实现不同的功能。
-
父类可以控制子类的执行顺序,保证算法的正确性。
模板方法模式的缺点包括:
-
父类和子类之间的耦合度较高,一旦父类的代码发生改变,可能会影响到子类的实现。
-
可能会导致类的数量增加,增加代码的复杂度。
3、模板方法模式的应用场景
模板方法模式适用于以下场景:
-
算法的整体步骤固定,但某些步骤的具体实现可以在子类中改变。
-
避免代码重复,将相同的代码抽象到父类中,子类只需要实现特定的代码即可。
-
父类需要控制子类的执行顺序,从而保证算法的正确性。
具体的应用场景有:
-
框架设计:框架中通常都会定义一些模板方法,子类通过实现特定的方法来完成框架的功能。
-
数据库访问:在访问数据库时,通常都需要进行连接、查询、关闭等操作,这些操作的顺序是固定的,但是具体的实现可以有所不同。
-
网络编程:在网络编程中,通常需要先建立连接、发送数据、接收数据等操作,这些操作的顺序是固定的,但是具体的实现可以有所不同。
-
面向对象设计:在面向对象设计中,通常会使用模板方法模式来实现一些通用的算法,如排序算法、搜索算法等。
-
游戏开发:在游戏开发中,通常需要实现一些通用的功能,如角色移动、攻击、防御等,这些功能的实现可以使用模板方法模式。
4、模板方法模式的结构
模板方法模式是一种行为设计模式,它定义了一个算法的骨架,并允许子类为一个或多个步骤提供实现。这种模式属于行为型模式。
模板方法模式的结构包括以下几个部分:
-
抽象类(AbstractClass):定义了算法的骨架,包含了若干个抽象方法,这些方法由子类实现。
-
具体类(ConcreteClass):实现了抽象类中定义的抽象方法,完成算法中的具体步骤。
-
钩子方法(Hook Method):在抽象类中定义的方法,子类可以选择性地覆盖它们,以改变算法的行为。
-
模板方法(Template Method):定义了算法的骨架,包含了一系列调用抽象方法和钩子方法的步骤,子类不能修改它的行为。
模板方法模式的核心思想是将算法的具体实现交给子类来完成,从而实现代码的复用和扩展。
5、模板方法模式的代码案例
package com.pany.camp.design.principle.template;
/**
*
* @description: 抽象类
* @copyright: @Copyright (c) 2022
* @company: Aiocloud
* @author: pany
* @version: 1.0.0
* @createTime: 2023-06-27 22:42
*/
public abstract class CaffeineBeverage {
final void prepareRecipe() {
boilWater();
brew();
pourInCup();
if (customerWantsCondiments()) {
addCondiments();
}
}
void boilWater() {
System.out.println("Boiling water");
}
void pourInCup() {
System.out.println("Pouring into cup");
}
abstract void brew();
abstract void addCondiments();
boolean customerWantsCondiments() {
return true;
}
}
package com.pany.camp.design.principle.template;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* @description: 咖啡
* @copyright: @Copyright (c) 2022
* @company: Aiocloud
* @author: pany
* @version: 1.0.0
* @createTime: 2023-06-27 22:42
*/
class Coffee extends CaffeineBeverage {
void brew() {
System.out.println("Dripping coffee through filter");
}
void addCondiments() {
System.out.println("Adding sugar and milk");
}
boolean customerWantsCondiments() {
String answer = getUserInput();
return answer.toLowerCase().startsWith("y");
}
private String getUserInput() {
String answer = null;
System.out.print("Would you like sugar and milk with your coffee? (y/n) ");
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
try {
answer = in.readLine();
} catch (IOException e) {
System.err.println("IO error trying to read your answer");
}
if (answer == null) {
return "no";
}
return answer;
}
}
package com.pany.camp.design.principle.template;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* @description: 茶
* @copyright: @Copyright (c) 2022
* @company: Aiocloud
* @author: pany
* @version: 1.0.0
* @createTime: 2023-06-27 22:43
*/
class Tea extends CaffeineBeverage {
void brew() {
System.out.println("Steeping the tea");
}
void addCondiments() {
System.out.println("Adding lemon");
}
boolean customerWantsCondiments() {
String answer = getUserInput();
return answer.toLowerCase().startsWith("y");
}
private String getUserInput() {
String answer = null;
System.out.print("Would you like lemon with your tea? (y/n) ");
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
try {
answer = in.readLine();
} catch (IOException e) {
System.err.println("IO error trying to read your answer");
}
if (answer == null) {
return "no";
}
return answer;
}
}
package com.pany.camp.design.principle.template;
/**
*
* @description: 客户端
* @copyright: @Copyright (c) 2022
* @company: Aiocloud
* @author: pany
* @version: 1.0.0
* @createTime: 2023-06-27 22:43
*/
public class Client {
public static void main(String[] args) {
CaffeineBeverage coffee = new Coffee();
CaffeineBeverage tea = new Tea();
System.out.println("Making coffee...");
coffee.prepareRecipe();
System.out.println("\nMaking tea...");
tea.prepareRecipe();
}
}
CaffeineBeverage 是抽象类,定义了制作咖啡因饮料的模板方法 prepareRecipe() ,以及一些基本方法 boilWater() 和 pourInCup() 。 CaffeineBeverage 还定义了两个抽象方法 brew() 和 addCondiments() ,由子类实现。
Coffee 和 Tea 是具体类,实现了 brew() 和 addCondiments() 方法,以及 customerWantsCondiments() 钩子方法,可以根据客户的需求选择是否添加调料。
在 main 函数中,我们创建了 Coffee 和 Tea 对象,并调用它们的 prepareRecipe() 方法,输出了制作咖啡和茶的过程。
输出结果如下:
Making coffee...
Boiling water
Dripping coffee through filter
Pouring into cup
Would you like sugar and milk with your coffee? (y/n) y
Adding sugar and milk
Making tea...
Boiling water
Steeping the tea
Pouring into cup
Would you like lemon with your tea? (y/n) y
Adding lemon
Process finished with exit code 0
💕💕 本文由激流原创,首发于CSDN博客,博客主页 https://blog.csdn.net/qq_37967783?spm=1010.2135.3001.5421
💕💕喜欢的话记得点赞收藏啊