模板方法模式
用意:准备一个抽象类,将部分逻辑以具体方法以及具体子类的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。
模板方法模式的定义:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
模板方法模式是基于继承的代码复用的基本技术,模板方法模式的结构和用法也是面向对象设计的核心
抽象模版(AbstractClass)
- 定义了一个或多个抽象操作,以便让子类实现。这些抽象操作叫做基本操作,它们是一个顶级逻辑的组成步骤。
- 定义并实现了一个模版方法。这个模版方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。顶级逻辑也有可能调用一些具体方法。
具体模版(ConcreteClass)
- 实现父类所定义的一个或多个抽象方法,它们是一个顶级逻辑的组成步骤。
- 每一个抽象模版角色都可以有任意多个具体模版角色与之对应,而每一个具体模版角色都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各不相同。
应用场景
当我们要完成在某一细节层次一致的一个过程或一系列步骤,但其个别步骤在更详细的层次上的实现可能不同的时候,我们通常要考虑用模板方法模式解决。
实例——数据库访问
package TemplateMethod;
public abstract class DataObject {
abstract public void Connect()throws Exception;
abstract public void Select() throws Exception;
abstract public void Process() throws Exception;
abstract public void Disconnect();
public void Run() throws Exception {
Connect();
Select();
Process();
Disconnect();
}
}
package TemplateMethod;
import java.sql.*;
public class CustomerDataObject extends DataObject {
final String Driver = "com.mysql.cj.jdbc.Driver";
final String URL = "jdbc:mysql://localhost/web?serverTimezone=UTC";
final String User = "root";
final String Password = "root";
String url;
PreparedStatement pstmt;
ResultSet rs;
Connection conn;
@Override
public void Connect() throws Exception {
Class.forName(Driver);
}
@Override
public void Select() throws SQLException {
conn = DriverManager.getConnection(URL, User, Password);
String sql = "select sgrade from student";
pstmt = conn.prepareStatement(sql);
}
@Override
public void Process() throws Exception {
rs = pstmt.executeQuery();
String rr = "";
if (!rs.next()) {
System.out.println("欢迎您第一次使用!");
} else {
rs.previous();
while (rs.next()) {
rr = rs.getString(1);
}
}
System.out.println(rr);
}
@Override
public void Disconnect() {
if (rs != null)
try {
rs.close();
} catch (SQLException e1) {
e1.printStackTrace();
throw new RuntimeException(e1);
}
if (pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
}
package TemplateMethod;
public class Main {
public static void main(String[] args) throws Exception {
DataObject d=new CustomerDataObject();
d.Run();
}
}
优缺点
优点
- 实现代码复用
缺点
- 算法骨架不容易升级(模板和子类是非常耦合的,如要对模板中的算法骨架进行变更,会影响子类变化)