【Java学习】【Java基础】--第3篇:初学模板方法模式和策略模式
一、模板方法模式 (Template Method Pattern)
1. 核心思想:骨架不变,细节可变
2. 模板方法模式的关键特点
- 控制流程:父类控制算法骨架,子类实现具体步骤
- 代码复用:公共代码在抽象类中实现
- 扩展性:通过钩子方法提供灵活性
- 好莱坞原则:"不要调用我们,我们会调用你" - 子类不直接调用父类,而是父类调用子类(父类决定了流程,子类决定了细节)
假设要开一家饮品店,制作饮料有固定的流程,但具体步骤可以调整。
3. 模式结构
// 抽象类 - 定义饮料制作模板
abstract class BeverageTemplate {
// 模板方法 - final防止子类改变算法骨架
public final void prepareBeverage() {
boilWater();
brew();
pourInCup();
if (customerWantsCondiments()) {
addCondiments();
}
serve();
}
// 固定步骤,子类共享
private void boilWater() {
System.out.println("烧开水");
}
private void pourInCup() {
System.out.println("倒入杯中");
}
private void serve() {
System.out.println("端给顾客");
}
// 抽象方法 - 由子类实现具体细节
protected abstract void brew();
protected abstract void addCondiments();
// 钩子方法,子类可以选择重写
protected boolean customerWantsCondiments() {
return true; // 默认加调料
}
}
4. 具体实现
// 咖啡具体实现
class Coffee extends BeverageTemplate {
@Override
protected void brew() {
System.out.println("冲泡咖啡");
}
@Override
protected void addCondiments() {
System.out.println("添加糖和牛奶");
}
@Override
protected boolean customerWantsCondiments() {
// 模拟部分顾客需要添加调料
return Math.random() > 0.5;
}
}
// 茶具体实现
class Tea extends BeverageTemplate {
@Override
protected void brew() {
System.out.println("浸泡茶叶");
}
@Override
protected void addCondiments() {
System.out.println("添加柠檬");
}
}
public class Main {
public static void main(String[] args) {
System.out.println("制作咖啡");
Coffee coffee = new Coffee();
coffee.prepareBeverage();
// 制作咖啡
// 烧开水
// 冲泡咖啡
// 倒入杯中
// 添加糖和牛奶
// 端给顾客
System.out.println();
System.out.println("制作茶饮");
Tea tea = new Tea();
tea.prepareBeverage();
// 制作茶饮
// 烧开水
// 浸泡茶叶
// 倒入杯中
// 添加柠檬
//端给顾客
}
}
二、策略模式 (Strategy Pattern)
1. 核心思想:定义算法家族,让它们可以互相替换
2. 策略模式的关键特点
- 开闭原则:无需修改上下文即可引入新策略
- 消除条件语句:用多态代替复杂的条件判断
- 代码复用:可以在不同上下文中复用一个策略
- 灵活性:运行时动态切换算法
- 单一职责:每个算法都有自己的类
假设要实现一个支付系统,支持多种支付方式,每种支付方式的算法不同。
3. 模式结构
// 策略接口 - 定义所有支付方式的共同行为
interface PaymentStrategy {
void pay(double amount);
boolean validate();
}
// 具体实现 - 信用卡支付
class CreditCardPayment implements PaymentStrategy {
// 信用卡号
private String cardNumber;
public CreditCardPayment(String cardNumber) {
this.cardNumber = cardNumber;
}
@Override
public void pay(double amount) {
System.out.println("使用信用卡支付" + amount + "元");
System.out.println("卡号: ****-****-****-" + maskCardNumber());
}
@Override
public boolean validate() {
return cardNumber != null && cardNumber.length() == 16;
}
private String maskCardNumber() {
return cardNumber.substring(12);
}
}
// 具体实现 - 支付宝支付
class AlipayPayment implements PaymentStrategy {
private String account;
public AlipayPayment(String account) {
this.account = account;
}
@Override
public void pay(double amount) {
System.out.println("使用支付宝支付" + amount + "元");
System.out.println("账户: " + account);
}
@Override
public boolean validate() {
return account != null && account.contains("@");
}
}
4. 上下文类 - 使用策略:
// 支付上下文 - 负责使用策略
class PaymentContext {
private PaymentStrategy paymentStrategy;
private String orderId;
public PaymentContext(String orderId) {
this.orderId = orderId;
}
// 设置策略
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
// 执行支付
public boolean executePayment(double amount) {
if (paymentStrategy == null) {
System.out.println("请设置支付模式!");
return false;
}
if (!paymentStrategy.validate()) {
System.out.println("验证失败!");
return false;
}
System.out.println("开始处理订单" + orderId);
paymentStrategy.pay(amount);
System.out.println("支付成功");
return true;
}
}
public class Main {
public static void main(String[] args) {
String orderId = "ABC_12345";
PaymentContext paymentContext = new PaymentContext(orderId);
// 使用信用卡策略
System.out.println("===使用信用卡支付===");
paymentContext.setPaymentStrategy(new CreditCardPayment("1234567891011121"));
paymentContext.executePayment(100.0);
// ===使用信用卡支付===
// 开始处理订单ABC_12345
// 使用信用卡支付100.0元
// 卡号: ****-****-****-1121
// 支付成功
// 使用支付宝策略
System.out.println("\n===使用支付宝支付===");
paymentContext.setPaymentStrategy(new AlipayPayment("user@alipay.com"));
paymentContext.executePayment(25.0);
// ===使用支付宝支付===
// 开始处理订单ABC_12345
// 使用支付宝支付25.0元
// 账户: user@alipay.com
// 支付成功
}
}
三、深入对比分析
1. 设计目标不同
| 方面 | 模板方法模式 | 策略模式 |
|---|---|---|
| 关注点 | 算法步骤的固定与变化 | 算法实现的互换性 |
| 关系 | 父子类继承关系 | 接口与实现关系 |
| 控制权 | 父类控制流程 | 客户端控制选择 |
2. 代码结构对比
模板方法模式:
abstract class Processor {
public final void process() { // 固定流程
step1();
step2(); // 抽象方法
step3();
}
private void step1() { /* 实现 */ }
protected abstract void step2();
private void step3() { /* 实现 */ }
}
策略模式:
interface Strategy {
void execute();
}
class Context {
private Strategy strategy;
public void setStrategy(Strategy s) {
this.strategy = s;
}
public void execute() {
strategy.execute(); // 委托给策略
}
}
四、两者结合
模板方法模式定义数据处理框架
abstract class DataProcessor {
// 父类决定流程
public final void process(String input) {
if (!validateInput(input)) {
System.out.println("输入不得为空!");
return;
}
String data = transformData(input);
outResult(data);
}
// 抽象方法 - 子类具体实现数据转换
protected abstract String transformData(String input);
private boolean validateInput(String input) {
return input != null && !input.trim().isEmpty();
}
private void outResult(String data) {
System.out.println("输出:" + data);
}
}
策略模式提供不同的转换实现
interface TransformStrategy {
String transform(String input);
}
class UppercaseStrategy implements TransformStrategy {
@Override
public String transform(String input) {
return input.toUpperCase();
}
}
class ReverseStrategy implements TransformStrategy {
@Override
public String transform(String input) {
return new StringBuilder(input).reverse().toString();
}
}
结合两种方法
class StrategyProcessor extends DataProcessor {
private TransformStrategy strategy;
// 可以在运行时改变策略
public void setStrategy(TransformStrategy strategy) {
this.strategy = strategy;
}
@Override
protected String transformData(String input) {
return strategy.transform(input);
}
}
public class Main {
public static void main(String[] args) {
StrategyProcessor strategyProcessor = new StrategyProcessor();
String input = "hello world";
// 策略1
strategyProcessor.setStrategy(new UppercaseStrategy());
strategyProcessor.process(input); // 输出:HELLO WORLD
// 策略2
strategyProcessor.setStrategy(new ReverseStrategy());
strategyProcessor.process(input); // 输出:dlrow olleh
}
}
五、总结对比表
| 维度 | 模板方法模式 | 策略模式 |
|---|---|---|
| 核心思想 | 固定流程,可变步骤 | 算法互换,独立封装 |
| 关系类型 | 继承关系 | 组合关系 |
| 控制方向 | 父类控制子类 | 客户端控制算法 |
| 代码复用 | 通过继承复用模板代码 | 通过组合复用策略 |
| 灵活性 | 编译时确定算法结构 | 运行时切换算法 |
| 适用场景 | 算法骨架固定,步骤可变 | 多种算法需要动态选择 |
| 典型应用 | 框架、工作流、测试生命周期 | 支付方式、排序算法、压缩算法 |
选择指南:
- 用模板方法当:你有固定的工作流程,但某些步骤需要定制化
- 用策略模式当:你有多种算法,需要在运行时灵活切换
- 结合使用当:既有固定流程,又需要在某些步骤使用不同策略

浙公网安备 33010602011771号