定义
模板方法模式(Template Method Pattern)是一种行为型设计模式,它定义了一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
以下是模板方法模式的主要特点和定义:
主要角色
-
AbstractClass(抽象类) :
- 定义了抽象的原语操作(primitive operations),这些操作由具体子类实现。
- 实现了一个模板方法,该方法定义了算法的骨架,调用了抽象原语操作。
-
ConcreteClass(具体类) :
- 实现了抽象类中的抽象原语操作。
业务
假设我们要实现不同类型的饮料制作过程,每种饮料的制作都有一些共同的步骤,如烧水、冲泡、添加调料等,但具体的冲泡和添加调料的方式可能不同。
classDiagram
class Beverage {
+prepareBeverage() : void
+boilWater() : void
+pourInCup() : void
+brew() : void
+addCondiments() : void
}
class Coffee {
+brew() : void
+addCondiments() : void
}
class Tea {
+brew() : void
+addCondiments() : void
}
Beverage <|-- Coffee
Beverage <|-- Tea
一、定义抽象类(AbstractClass)
abstract class Beverage {
// 模板方法,定义了饮料制作的流程
final void prepareBeverage() {
boilWater();
brew();
pourInCup();
addCondiments();
}
void boilWater() {
System.out.println("Boiling water.");
}
abstract void brew();
void pourInCup() {
System.out.println("Pouring into cup.");
}
abstract void addCondiments();
}
二、定义具体类(ConcreteClass)
- 咖啡的制作:
class Coffee extends Beverage {
@Override
void brew() {
System.out.println("Brewing coffee.");
}
@Override
void addCondiments() {
System.out.println("Adding sugar and milk.");
}
}
- 茶的制作:
class Tea extends Beverage {
@Override
void brew() {
System.out.println("Steeping tea.");
}
@Override
void addCondiments() {
System.out.println("Adding lemon.");
}
}
三、使用模板方法模式
public class TemplateMethodPatternExample {
public static void main(String[] args) {
Beverage coffee = new Coffee();
coffee.prepareBeverage();
System.out.println();
Beverage tea = new Tea();
tea.prepareBeverage();
}
}
在这个例子中,Beverage是抽象类,定义了制作饮料的模板方法prepareBeverage,该方法包含了制作饮料的一系列步骤。Coffee和Tea是具体类,它们实现了抽象类中的抽象方法brew和addCondiments,从而实现了不同类型饮料的制作过程。通过这种方式,我们可以在不改变模板方法的情况下,通过扩展具体类来实现不同的饮料制作过程,体现了模板方法模式的优点。
框架中的使用
spring
一、JdbcTemplate
Spring 的JdbcTemplate是模板方法模式的一个典型应用。JdbcTemplate封装了数据库操作的基本流程,如获取数据库连接、创建语句对象、执行 SQL 语句、处理结果集等。而具体的数据库操作逻辑,如 SQL 语句的编写和结果集的处理,则由开发者在回调方法中实现。
例如:
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import javax.sql.DataSource;
import java.util.List;
public class UserDao {
private JdbcTemplate jdbcTemplate;
public UserDao(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public List<User> findAllUsers() {
return jdbcTemplate.query("SELECT * FROM users", new RowMapper<User>() {
@Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setId(rs.getLong("id"));
user.setName(rs.getString("name"));
user.setAge(rs.getInt("age"));
return user;
}
});
}
}
在这个例子中,JdbcTemplate的query方法是一个模板方法,它定义了执行数据库查询的基本流程,而具体的结果集处理逻辑在RowMapper的实现中提供。
二、TransactionTemplate
TransactionTemplate用于处理数据库事务,它也是模板方法模式的应用。它封装了事务管理的基本流程,如开启事务、执行事务中的业务逻辑、提交或回滚事务等。而具体的业务逻辑则由开发者在回调方法中实现。
例如:
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
public class UserService {
private TransactionTemplate transactionTemplate;
public UserService(PlatformTransactionManager transactionManager) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
}
public void saveUser(User user) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
// 具体的数据库保存操作
userDao.saveUser(user);
}
});
}
}
在这个例子中,TransactionTemplate的execute方法是一个模板方法,它定义了事务管理的基本流程,而具体的业务逻辑在TransactionCallbackWithoutResult的实现中提供。
综上所述,Spring 框架广泛使用了模板方法模式,通过封装通用的流程,将具体的逻辑延迟到子类或回调方法中实现,提高了代码的可复用性和可维护性。
总结
使用场景
-
当多个算法具有相似的结构,但某些具体步骤不同时。
- 例如,在一个文档生成系统中,不同类型的文档(如报告、论文、简历等)的生成过程可能有相似的结构,但具体的内容生成方式不同。可以使用模板方法模式定义一个文档生成的模板方法,将具体的内容生成步骤延迟到具体的文档类中实现。
-
当需要将算法的结构和具体实现分离时。
- 模板方法模式将算法的结构定义在抽象类中,而将具体的实现留给具体子类。这样可以提高代码的可维护性和可扩展性,因为可以在不改变算法结构的情况下,通过添加新的具体子类来实现新的算法变体。
优点
-
提高代码的复用性。
- 模板方法模式将算法的结构封装在抽象类中,可以在多个具体子类中复用。
-
实现了代码的可维护性和可扩展性。
- 通过将算法的结构和具体实现分离,可以在不改变算法结构的情况下,通过添加新的具体子类来实现新的算法变体。
-
符合开闭原则。
- 可以在不修改现有代码的情况下,通过添加新的具体子类来扩展系统的功能。
缺点
-
可能会导致代码的复杂性增加。
- 模板方法模式需要定义抽象类和具体子类,这可能会增加代码的复杂性。
-
可能会限制具体子类的灵活性。
- 具体子类必须实现抽象类中定义的抽象原语操作,这可能会限制具体子类的灵活性。