模式定义

模板方法模式是一种行为型设计模式,它定义一个操作中的算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些特定步骤。模板方法模式通过把不变行为搬移到父类,去除子类中的重复代码来体现其优势。

模式结构

graph TD A[AbstractClass] --> B[ConcreteClass] A --> C[ConcreteClass]

实现方式

基础实现

定义抽象类,实现具体子类。

// 抽象类
public abstract class Beverage {
    // 模板方法,定义算法骨架
    final void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }
    
    // 共同方法
    void boilWater() {
        System.out.println("煮沸水");
    }
    
    // 抽象方法,由子类实现
    abstract void brew();
    
    void pourInCup() {
        System.out.println("倒入杯中");
    }
    
    // 抽象方法,由子类实现
    abstract void addCondiments();
}

// 具体子类 - 咖啡
class Coffee extends Beverage {
    @Override
    void brew() {
        System.out.println("用沸水冲泡咖啡粉");
    }
    
    @Override
    void addCondiments() {
        System.out.println("加糖和牛奶");
    }
}

// 具体子类 - 茶
class Tea extends Beverage {
    @Override
    void brew() {
        System.out.println("用沸水浸泡茶叶");
    }
    
    @Override
    void addCondiments() {
        System.out.println("加柠檬");
    }
}

使用示例

public class TemplateMethodPatternDemo {
    public static void main(String[] args) {
        System.out.println("制作咖啡:");
        Beverage coffee = new Coffee();
        coffee.prepareRecipe();
        
        System.out.println("\n制作茶:");
        Beverage tea = new Tea();
        tea.prepareRecipe();
    }
}

经典案例

1. Java Servlet API

Java Servlet中的doGet和 doPost方法是模板方法模式的经典应用:

public class MyServlet extends HttpServlet {
    // 模板方法模式:service方法定义了处理请求的算法骨架
    // doGet和doPost是具体步骤的实现
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 处理GET请求的具体实现
        response.getWriter().println("处理GET请求");
    }
    
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 处理POST请求的具体实现
        response.getWriter().println("处理POST请求");
    }
    
    // 父类HttpServlet中的service方法(模板方法)类似于:
    // protected void service(HttpServletRequest req, HttpServletResponse res) {
    //     String method = req.getMethod();
    //     if ("GET".equals(method)) {
    //         doGet(req, res);
    //     } else if ("POST".equals(method)) {
    //         doPost(req, res);
    //     }
    // }
}

2. Android Activity生命周期

Android开发中Activity的生命周期方法也是模板方法模式的应用:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // onCreate是模板方法中的一部分
    }
    
    @Override
    protected void onStart() {
        super.onStart();
        // onStart是模板方法中的一部分
    }
    
    @Override
    protected void onResume() {
        super.onResume();
        // onResume是模板方法中的一部分
    }
    
    // Android框架定义了Activity的生命周期算法骨架
    // 开发者只需重写相应的生命周期方法
}

3. Spring框架中的JdbcTemplate

Spring框架中的JdbcTemplate使用模板方法模式简化数据库操作:

public class UserService {
    private JdbcTemplate jdbcTemplate;
    
    public User getUserById(int id) {
        String sql = "SELECT * FROM users WHERE id = ?";
        // query方法是模板方法,定义了数据库查询的算法骨架
        // RowMapper是回调接口,由用户实现具体的映射逻辑
        return jdbcTemplate.queryForObject(sql, new Object[]{id}, 
            new RowMapper() {
                @Override
                public User mapRow(ResultSet rs, int rowNum) throws SQLException {
                    User user = new User();
                    user.setId(rs.getInt("id"));
                    user.setName(rs.getString("name"));
                    // 具体的映射逻辑由用户实现
                    return user;
                }
            });
    }
}

应用场景

优缺点

优点

  • 封装不变部分,扩展可变部分:将不变的行为封装在父类中,可变部分由子类实现
  • 提取公共代码,便于维护:避免代码重复,提高代码复用性
  • 行为由父类控制,子类实现:通过父类调用子类实现,反向控制结构
  • 符合开闭原则:增加新的具体实现无需修改现有代码

缺点

  • 算法骨架固定:模板方法定义了算法骨架,不易修改
  • 可能违反里氏替换原则:子类可能无法完全替换父类
  • 增加了代码理解难度:需要在父类和子类之间跳转理解代码