当模板方法模式遇上工厂模式:一道优雅的烹饪架构设计

当模板方法模式遇上工厂模式:一道优雅的烹饪架构设计

如果在学习 设计模式的过程中,对模板方法模式知识点稍感生疏,记忆有些模糊不清了,不妨参考一下我的上一篇文章:【从厨房到代码------揭秘模板方法模式的烹饪哲学】相信能为你答疑解惑,助你重拾清晰记忆。
庖丁解牛看模式

在软件开发领域,我们经常面临需要标准化流程又保留扩展灵活性的场景。本文通过一个生动的厨房烹饪案例,展示如何模板方法模式工厂模式优雅结合,实现流程标准化与对象创建解耦的完美平衡。

模式交响曲的实现

模板方法模式

搭建烹饪骨架(抽象类)

我们首先定义抽象基类AbstractCooking,它采用三层结构设计
伪代码:

java 复制代码
public abstract class AbstractCooking {
    // 模板方法(final确保流程不可篡改)
    public final void execute() { /* 标准流程 */ }
    
    // 固定步骤(私有方法)
    private void prepareIngredients() { /* ... */ }
    
    // 可选步骤(钩子方法)
    protected boolean needThickening() { return true; }
    
    // 抽象方法(必须实现)
    protected abstract void aromaBlasting();
}

具体代码:

java 复制代码
public abstract class AbstractCooking {
    protected CookEnum cookEnum;

    // 模板方法(final锁定流程)
    public final void execute() {
        prepareIngredients();
        heatOil();
        aromaBlasting();  // 抽象方法:爆香方式
        mainCooking();    // 抽象方法:主料烹制
        if(needThickening()) thicken(); // 钩子控制收汁
    }

    private void prepareIngredients() {
        System.out.println("准备食材以及配料");
    }

    private void heatOil() {
        System.out.println("热锅凉油至180℃");
    }

    private void thicken() {
        System.out.println("收汁");
    }

    // 钩子方法:默认需要收汁
    protected boolean needThickening() {
        return true;
    }

    protected abstract void aromaBlasting();
    protected abstract void mainCooking();


    public CookEnum getCookEnum() {
        return cookEnum;
    }
}

这种设计实现了:

  • 流程固化:通过final方法锁定烹饪顺序
  • 灵活扩展:抽象方法强制子类实现关键步骤
  • 可选扩展:钩子方法提供流程微调能力

具体菜品(子类)

宫保鸡丁

java 复制代码
/**
 * 宫保鸡丁
 */
@Service
public class KungPaoChicken extends AbstractCooking {
    public KungPaoChicken() {
        this.cookEnum = CookEnum.KUNG_PAO_CHICKEN;
    }

    @Override
    protected void aromaBlasting() {
        System.out.println("葱姜蒜爆香");
    }

    @Override
    protected void mainCooking() {
        System.out.println("胡萝卜、鸡肉、花生切丁爆炒");
    }

    @Override
    protected boolean needThickening() {    // 不需要收汁
        return false;
    }
}

麻婆豆腐

java 复制代码
/**
 * 麻婆豆腐
 */
@Service
public class MapoTofu  extends AbstractCooking {
    public MapoTofu() {
        this.cookEnum = CookEnum.MAPO_TO_FU;
    }

    @Override
    protected void aromaBlasting() {
        System.out.println("煸炒郫县豆瓣酱+花椒粒");
    }

    @Override
    protected void mainCooking() {
        System.out.println("嫩豆腐切块入红汤慢炖");
    }
}

工厂模式

CookFactory通过Spring容器自动装载所有菜品实现

java 复制代码
@Service
public class CookFactory implements InitializingBean {

    @Autowired
    private List<AbstractCooking> cookings;

    private Map<CookEnum, AbstractCooking> cookingMap = new HashMap<>();

    public AbstractCooking getCookingByCode(String code) {
        CookEnum cookEnum = CookEnum.getByCode(code);
        return cookingMap.get(cookEnum);
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        for (AbstractCooking cooking: cookings) {
            cookingMap.put(cooking.getCookEnum(), cooking);
        }
    }
}
java 复制代码
/**
 * 菜品枚举类
 */
public enum CookEnum {
    KUNG_PAO_CHICKEN("kungPaoChicken", "宫保鸡丁"),
    MAPO_TO_FU("mapoTofu", "麻婆豆腐");

    private final String code;
    private final String name;

    CookEnum(String code, String name) {
        this.code = code;
        this.name = name;
    }

    public String getCode() {
        return code;
    }

    public String getName() {
        return name;
    }

    public static CookEnum getByCode(String code) {
        for (CookEnum cookEnum : CookEnum.values()) {
            if (cookEnum.code.equals(code)) {
                return cookEnum;
            }
        }
        return null;
    }
}

这种实现方式具备:

  • 自动发现:利用Spring的依赖注入特性
  • 集中管理:统一维护菜品实例映射关系
  • 解耦调用:客户端无需关心具体实现类

模式协作的优势呈现

扩展性演示

java 复制代码
@Service
public class BraisedPork extends AbstractCooking {
    // 实现抽象方法
    @Override
    protected void aromaBlasting() {
        System.out.println("葱姜蒜大料爆香");
    }
    @Override
    protected void mainCooking() {
        System.out.println("三层肉文火慢炖40分钟");
    }
    // 扩展枚举
    CookEnum.BRAISED_PORK
}

无需修改已有代码即可完成功能扩展,充分体现开闭原则

运行时流程控制

控制器通过简单调用实现完整烹饪流程

java 复制代码
@GetMapping("/order")
public void cookDish(String dishCode) {
    cookFactory.getCooking(dishCode).execute();
}

完整代码

抽象类:

java 复制代码
public abstract class AbstractCooking {
    protected CookEnum cookEnum;

    // 模板方法(final锁定流程)
    public final void execute() {
        prepareIngredients();
        heatOil();
        aromaBlasting();  // 抽象方法:爆香方式
        mainCooking();    // 抽象方法:主料烹制
        if(needThickening()) thicken(); // 钩子控制收汁
    }

    private void prepareIngredients() {
        System.out.println("准备食材以及配料");
    }

    private void heatOil() {
        System.out.println("热锅凉油至180℃");
    }

    private void thicken() {
        System.out.println("收汁");
    }

    // 钩子方法:默认需要收汁
    protected boolean needThickening() {
        return true;
    }

    protected abstract void aromaBlasting();
    protected abstract void mainCooking();


    public CookEnum getCookEnum() {
        return cookEnum;
    }
}

子类 - 宫保鸡丁:

java 复制代码
/**
 * 宫保鸡丁
 */
@Service
public class KungPaoChicken extends AbstractCooking {
    public KungPaoChicken() {
        this.cookEnum = CookEnum.KUNG_PAO_CHICKEN;
    }

    @Override
    protected void aromaBlasting() {
        System.out.println("葱姜蒜爆香");
    }

    @Override
    protected void mainCooking() {
        System.out.println("胡萝卜、鸡肉、花生切丁爆炒");
    }

    @Override
    protected boolean needThickening() {    // 不需要收汁
        return false;
    }
}

子类 - 麻婆豆腐:

java 复制代码
/**
 * 麻婆豆腐
 */
@Service
public class MapoTofu  extends AbstractCooking {
    public MapoTofu() {
        this.cookEnum = CookEnum.MAPO_TO_FU;
    }

    @Override
    protected void aromaBlasting() {
        System.out.println("煸炒郫县豆瓣酱+花椒粒");
    }

    @Override
    protected void mainCooking() {
        System.out.println("嫩豆腐切块入红汤慢炖");
    }
}

工厂类:

java 复制代码
@Service
public class CookFactory implements InitializingBean {

    @Autowired
    private List<AbstractCooking> cookings;

    private Map<CookEnum, AbstractCooking> cookingMap = new HashMap<>();

    public AbstractCooking getCookingByCode(String code) {
        CookEnum cookEnum = CookEnum.getByCode(code);
        return cookingMap.get(cookEnum);
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        for (AbstractCooking cooking: cookings) {
            cookingMap.put(cooking.getCookEnum(), cooking);
        }
    }
}

枚举:

java 复制代码
/**
 * 菜品枚举类
 */
public enum CookEnum {
    KUNG_PAO_CHICKEN("kungPaoChicken", "宫保鸡丁"),
    MAPO_TO_FU("mapoTofu", "麻婆豆腐");

    private final String code;
    private final String name;

    CookEnum(String code, String name) {
        this.code = code;
        this.name = name;
    }

    public String getCode() {
        return code;
    }

    public String getName() {
        return name;
    }

    public static CookEnum getByCode(String code) {
        for (CookEnum cookEnum : CookEnum.values()) {
            if (cookEnum.code.equals(code)) {
                return cookEnum;
            }
        }
        return null;
    }
}

接口:

java 复制代码
@RestController
@RequestMapping("/test")
public class Testcontroller {

    @Autowired
    CookFactory cookFactory;

    @GetMapping("/orderDishes")
    public void orderDishes(String dishCode) {
        cookFactory.getCookingByCode(dishCode).execute();
    }
}
相关推荐
李少兄20 分钟前
Unirest:优雅的Java HTTP客户端库
java·开发语言·http
此木|西贝26 分钟前
【设计模式】原型模式
java·设计模式·原型模式
可乐加.糖43 分钟前
一篇关于Netty相关的梳理总结
java·后端·网络协议·netty·信息与通信
s9123601011 小时前
rust 同时处理多个异步任务
java·数据库·rust
9号达人1 小时前
java9新特性详解与实践
java·后端·面试
cg50171 小时前
Spring Boot 的配置文件
java·linux·spring boot
啊喜拔牙1 小时前
1. hadoop 集群的常用命令
java·大数据·开发语言·python·scala
anlogic2 小时前
Java基础 4.3
java·开发语言
非ban必选2 小时前
spring-ai-alibaba第七章阿里dashscope集成RedisChatMemory实现对话记忆
java·后端·spring
A旧城以西2 小时前
数据结构(JAVA)单向,双向链表
java·开发语言·数据结构·学习·链表·intellij-idea·idea