🎭 程序员的一天:12种设计模式藏在你身边

🎭 程序员的一天:12种设计模式藏在你身边

Scroll Down

🎭 程序员的一天:12种设计模式藏在你身边

前几天和同事聊天,他说设计模式太抽象,学了也用不上。我当时就想,其实设计模式就在我们身边,只是你没注意到而已。

正好,我梳理了程序员小王的一天,发现他这一天里居然用到了12种设计模式!而且都是生活中很常见的场景。今天就把这些分享给大家,看看设计模式是怎么悄无声息地融入我们生活的。

🌅 清晨:单例模式 - 唯一的那份早餐

早上7:00,小王被闹钟吵醒,迷迷糊糊地走到厨房。打开冰箱一看,里面只有一个鸡蛋、一盒牛奶、一袋面包。

"唉,又得吃这个了。"小王一边嘀咕,一边开始做早餐。

等等,你有没有想过,为什么冰箱里每种食物只有一份?不是两份,也不是三份?这就是单例模式的体现——确保一个类只有一个实例。

在代码里,我们经常需要确保某些资源只有一个实例,比如数据库连接池、配置管理器。如果创建多个实例,不仅浪费资源,还可能导致状态混乱。

生活中的单例模式

其实单例模式在生活中随处可见:

  • 冰箱里的鸡蛋:只有一个,不能同时有两个(除非你买新的)
  • 家里的钥匙:只有一把,丢了就麻烦了(别问我怎么知道的)
  • 音乐播放器:同一时间只能播放一首歌,总不能同时放两首吧

代码中的单例模式

// 懒汉式单例 - 就像小王需要时才去冰箱拿食物
public class BreakfastManager {
    private static BreakfastManager instance;
    
    private BreakfastManager() {
        // 私有构造,防止外部创建
    }
    
    public static BreakfastManager getInstance() {
        if (instance == null) {
            instance = new BreakfastManager();
        }
        return instance;
    }
    
    public void makeBreakfast() {
        System.out.println("制作早餐:鸡蛋 + 牛奶 + 面包");
    }
}

为什么需要单例? 就像你不会同时打开两个冰箱门(虽然理论上可以,但没必要),某些资源在系统中只需要一个实例就够了。多了反而麻烦,还浪费资源。


🚴 通勤路上:策略模式 - 选择最佳路线

早上7:30,小王洗漱完毕,准备出门。站在门口,他开始纠结:今天骑电车还是打车?

看看窗外,天气不错,但时间有点紧。小王想了想:“算了,还是骑电车吧,省钱又环保。”

这就是策略模式——根据不同的情况,选择不同的策略。天气好就骑电车,下雨就打车,时间紧就打车,心情好就骑电车…不同的条件,不同的选择。

在代码里,策略模式就是把不同的算法封装起来,可以随时切换。比如支付方式:支付宝、微信、银行卡,想用哪个用哪个。

生活中的策略模式

策略模式在生活中太常见了:

  • 出行方式:天气好骑电车,下雨就打车,心情好就走路
  • 音乐播放:想听什么模式就切什么模式,随机、单曲、顺序随便选
  • 点餐策略:工作日随便吃点,周末必须吃好的(这是原则)

代码中的策略模式

// 出行策略接口
interface TransportationStrategy {
    void goToSubway();
}

// 骑电车策略
class BikeStrategy implements TransportationStrategy {
    @Override
    public void goToSubway() {
        System.out.println("骑电车去地铁站,环保又省钱");
    }
}

// 打车策略
class TaxiStrategy implements TransportationStrategy {
    @Override
    public void goToSubway() {
        System.out.println("打车去地铁站,舒适又快速");
    }
}

// 策略上下文
class TransportationContext {
    private TransportationStrategy strategy;
    
    public void setStrategy(TransportationStrategy strategy) {
        this.strategy = strategy;
    }
    
    public void execute() {
        strategy.goToSubway();
    }
}

// 使用示例
public class MorningRoutine {
    public static void main(String[] args) {
        TransportationContext context = new TransportationContext();
        
        // 根据天气选择策略
        if (isSunny()) {
            context.setStrategy(new BikeStrategy());
        } else {
            context.setStrategy(new TaxiStrategy());
        }
        
        context.execute();
    }
}

策略模式的优势:小王不需要改自己的出行逻辑,想换出行方式?直接切换策略就行。想加个共享单车?新增一个策略类就完事了,完全不影响现有代码。


🚇 地铁换乘:适配器模式 - 无缝连接

早上8:00,小王到了地铁站。今天要换乘,从1号线换到2号线。

虽然两条线路的站台不一样,但换乘通道把它们连起来了。小王走几步就到了2号线,无缝衔接。

这就是适配器模式——让两个不兼容的东西能够协同工作。1号线和2号线本来不兼容,但换乘通道(适配器)让它们无缝连接。

在代码里,我们经常遇到这种情况:新系统要用老接口,或者两个系统的接口不匹配。这时候就需要适配器来"翻译"一下。

生活中的适配器模式

  • 电源适配器:220V转110V,让不同电压的设备都能工作
  • 转接头:Type-C转3.5mm,让新手机用旧耳机
  • 地铁换乘:不同线路通过换乘通道连接

代码中的适配器模式

// 1号线接口
interface Line1 {
    void arriveAtStation(String station);
}

// 2号线接口(不兼容)
interface Line2 {
    void reachStation(String station);
}

// 适配器:让1号线和2号线能够换乘
class SubwayAdapter implements Line2 {
    private Line1 line1;
    
    public SubwayAdapter(Line1 line1) {
        this.line1 = line1;
    }
    
    @Override
    public void reachStation(String station) {
        // 适配:将2号线的接口转换为1号线的接口
        line1.arriveAtStation(station);
        System.out.println("通过换乘通道,成功换乘到2号线");
    }
}

// 使用示例
public class SubwayTransfer {
    public static void main(String[] args) {
        Line1 line1 = new Line1Impl();
        Line2 line2 = new SubwayAdapter(line1);
        
        // 现在可以用2号线的接口操作1号线了
        line2.reachStation("换乘站");
    }
}

适配器模式的价值:让不兼容的接口能够协同工作,提高了代码的复用性。就像地铁换乘通道,虽然简单,但解决了大问题。


📱 地铁上看电影:观察者模式 - 通知系统

早上8:15,地铁上人不多,小王找了个座位,打开视频APP准备看个电影放松一下。

刚打开APP,就收到一堆通知:“您关注的剧集更新了”、“好友给你点赞了”、“系统消息:今日签到”…

小王一边看通知,一边想:为什么我一打开APP,这些通知就都来了?这就是观察者模式——一个对象(视频APP)状态改变了,所有关注它的对象(各种通知)都会收到通知。

简单说,就是"一对多"的关系。一个被观察者,多个观察者。被观察者一有变化,所有观察者都能收到通知。

生活中的观察者模式

观察者模式在生活中太常见了:

  • APP推送:新消息来了,所有订阅的用户都能收到(虽然有时候很烦)
  • 电视台节目:节目一开始,所有观众都能看到(虽然现在看电视的人少了)
  • 微信群消息:有人发消息,所有群成员都能收到(这个最烦,特别是工作群)

代码中的观察者模式

// 被观察者(主题)
interface Subject {
    void attach(Observer observer);
    void detach(Observer observer);
    void notifyObservers(String message);
}

// 观察者接口
interface Observer {
    void update(String message);
}

// 视频APP(被观察者)
class VideoApp implements Subject {
    private List<Observer> observers = new ArrayList<>();
    
    @Override
    public void attach(Observer observer) {
        observers.add(observer);
    }
    
    @Override
    public void detach(Observer observer) {
        observers.remove(observer);
    }
    
    @Override
    public void notifyObservers(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
    
    public void newVideoReleased(String videoName) {
        System.out.println("新视频发布:" + videoName);
        notifyObservers("新视频《" + videoName + "》已发布,快来观看!");
    }
}

// 用户(观察者)
class User implements Observer {
    private String name;
    
    public User(String name) {
        this.name = name;
    }
    
    @Override
    public void update(String message) {
        System.out.println(name + "收到通知:" + message);
    }
}

// 使用示例
public class VideoNotification {
    public static void main(String[] args) {
        VideoApp app = new VideoApp();
        
        // 小王订阅了APP
        User xiaowang = new User("小王");
        app.attach(xiaowang);
        
        // 新视频发布,小王自动收到通知
        app.newVideoReleased("设计模式实战");
    }
}

观察者模式的优势:发布者和订阅者完全解耦,想订阅就订阅,想取消就取消,非常灵活。就像你可以随时取消APP的通知,APP也可以随时推送新内容,互不影响。


🏢 到达公司:工厂模式 - 创建不同的对象

早上9:00,小王到了公司,打开电脑。今天要做什么呢?先打开飞书看看有没有消息,再打开IDE准备写代码,还要打开浏览器查资料。

等等,这些工具是怎么创建的?不是直接new出来的,而是通过系统"工厂"创建的。这就是工厂模式——不直接创建对象,而是通过工厂来创建。

为什么要这样?因为创建对象的过程可能很复杂,或者需要根据条件创建不同的对象。交给工厂统一管理,代码更清晰,也更容易维护。

生活中的工厂模式

工厂模式在生活中到处都是:

  • 汽车工厂:要什么车就生产什么车,轿车、SUV、卡车随便选
  • 披萨店:要什么口味就做什么口味,芝士、海鲜、蔬菜都有
  • 工具创建:需要什么工具就创建什么工具,编辑器、浏览器、聊天软件,想用哪个用哪个

代码中的工厂模式

// 工具接口
interface Tool {
    void open();
}

// 具体工具
class IDE implements Tool {
    @Override
    public void open() {
        System.out.println("打开IDE,准备写代码");
    }
}

class Browser implements Tool {
    @Override
    public void open() {
        System.out.println("打开浏览器,查找资料");
    }
}

class ChatApp implements Tool {
    @Override
    public void open() {
        System.out.println("打开飞书,查看消息");
    }
}

// 工具工厂
class ToolFactory {
    public static Tool createTool(String type) {
        switch (type) {
            case "IDE":
                return new IDE();
            case "Browser":
                return new Browser();
            case "ChatApp":
                return new ChatApp();
            default:
                throw new IllegalArgumentException("未知的工具类型");
        }
    }
}

// 使用示例
public class MorningWork {
    public static void main(String[] args) {
        // 通过工厂创建工具,而不是直接new
        Tool chatApp = ToolFactory.createTool("ChatApp");
        chatApp.open();
        
        Tool ide = ToolFactory.createTool("IDE");
        ide.open();
    }
}

工厂模式的优势:对象的创建和使用完全分离。想加个新工具?改工厂就行,使用代码完全不用动。这就是开闭原则的体现。


📋 制定工作计划:模板方法模式 - 固定的流程

早上9:15,小王打开笔记本,开始制定今天的工作计划。

他的工作流程基本固定:先看需求文档,然后分析需求,接着设计方案,再编码实现,最后测试验证。这个流程就像模板一样,每次都是这个套路。

这就是模板方法模式——定义一个算法的骨架,具体步骤可以变化,但整体流程不变。就像做菜,流程是固定的(准备食材 → 烹饪 → 装盘),但每道菜的具体做法不一样。

生活中的模板方法模式

模板方法模式在生活中很常见:

  • 写论文:摘要 → 引言 → 正文 → 结论,流程固定,但内容不同
  • 做菜:准备食材 → 烹饪 → 装盘,流程固定,但每道菜做法不同
  • 工作流程:需求分析 → 设计 → 开发 → 测试,流程固定,但每个项目内容不同

代码中的模板方法模式

// 抽象工作流程(模板)
abstract class WorkTemplate {
    // 模板方法:定义固定的工作流程
    public final void dailyWork() {
        checkMessages();
        analyzeRequirements();
        designSolution();
        implementCode();
        testCode();
    }
    
    // 具体步骤,子类可以重写
    protected void checkMessages() {
        System.out.println("查看飞书消息");
    }
    
    protected abstract void analyzeRequirements();
    protected abstract void designSolution();
    protected abstract void implementCode();
    
    protected void testCode() {
        System.out.println("运行测试用例");
    }
}

// 具体实现:新功能开发
class NewFeatureWork extends WorkTemplate {
    @Override
    protected void analyzeRequirements() {
        System.out.println("分析新功能需求文档");
    }
    
    @Override
    protected void designSolution() {
        System.out.println("设计新功能的技术方案");
    }
    
    @Override
    protected void implementCode() {
        System.out.println("编写新功能代码");
    }
}

// 具体实现:Bug修复
class BugFixWork extends WorkTemplate {
    @Override
    protected void analyzeRequirements() {
        System.out.println("分析Bug报告");
    }
    
    @Override
    protected void designSolution() {
        System.out.println("设计Bug修复方案");
    }
    
    @Override
    protected void implementCode() {
        System.out.println("修复Bug代码");
    }
}

// 使用示例
public class WorkPlan {
    public static void main(String[] args) {
        WorkTemplate work = new NewFeatureWork();
        work.dailyWork();
    }
}

模板方法模式的优势:保证流程一致性,同时允许每个步骤有不同的实现。就像小王每天的工作流程是固定的,但具体内容可以根据任务类型调整。这样既规范,又灵活。


🍽️ 中午吃饭:装饰器模式 - 给菜品加料

中午12:00,小王和同事去楼下吃饭。他点了一份牛肉面,然后对老板说:“加个鸡蛋,再加份牛肉,再来一勺辣椒。”

老板一边加料,小王一边想:这碗面还是那碗面,但加了料之后变得更丰富了。这就是装饰器模式——在不改变原有对象的基础上,动态地添加功能。

就像给照片加滤镜,照片还是那张照片,但加了滤镜之后效果不一样了。或者给房子装修,房子还是那个房子,但装修之后更漂亮了。

生活中的装饰器模式

装饰器模式在生活中随处可见:

  • 给面加料:牛肉面 + 鸡蛋 + 牛肉 + 辣椒,想加什么加什么
  • 给照片加滤镜:原图 + 滤镜1 + 滤镜2,可以叠加多个滤镜
  • 装修房子:毛坯房 + 刷墙 + 铺地板 + 装家具,一步步装饰

代码中的装饰器模式

// 基础组件:面条
interface Noodle {
    String getDescription();
    double getPrice();
}

// 具体组件:牛肉面
class BeefNoodle implements Noodle {
    @Override
    public String getDescription() {
        return "牛肉面";
    }
    
    @Override
    public double getPrice() {
        return 15.0;
    }
}

// 装饰器抽象类
abstract class NoodleDecorator implements Noodle {
    protected Noodle noodle;
    
    public NoodleDecorator(Noodle noodle) {
        this.noodle = noodle;
    }
    
    @Override
    public String getDescription() {
        return noodle.getDescription();
    }
    
    @Override
    public double getPrice() {
        return noodle.getPrice();
    }
}

// 具体装饰器:加鸡蛋
class EggDecorator extends NoodleDecorator {
    public EggDecorator(Noodle noodle) {
        super(noodle);
    }
    
    @Override
    public String getDescription() {
        return noodle.getDescription() + " + 鸡蛋";
    }
    
    @Override
    public double getPrice() {
        return noodle.getPrice() + 2.0;
    }
}

// 具体装饰器:加牛肉
class ExtraBeefDecorator extends NoodleDecorator {
    public ExtraBeefDecorator(Noodle noodle) {
        super(noodle);
    }
    
    @Override
    public String getDescription() {
        return noodle.getDescription() + " + 加牛肉";
    }
    
    @Override
    public double getPrice() {
        return noodle.getPrice() + 5.0;
    }
}

// 使用示例
public class LunchOrder {
    public static void main(String[] args) {
        // 基础牛肉面
        Noodle noodle = new BeefNoodle();
        System.out.println(noodle.getDescription() + " - ¥" + noodle.getPrice());
        
        // 加鸡蛋
        noodle = new EggDecorator(noodle);
        System.out.println(noodle.getDescription() + " - ¥" + noodle.getPrice());
        
        // 再加牛肉
        noodle = new ExtraBeefDecorator(noodle);
        System.out.println(noodle.getDescription() + " - ¥" + noodle.getPrice());
        
        // 再加辣椒(可以继续装饰)
        // noodle = new SpicyDecorator(noodle);
    }
}

装饰器模式的优势:可以动态地组合功能,想加什么功能就加什么功能,非常灵活。比继承好多了,不会出现类爆炸的问题。


💼 下午开会:命令模式 - 执行任务

下午2:00,小王参加需求评审会。产品经理在台上讲需求,小王在下面记笔记。

"用户登录功能、商品搜索功能、购物车功能…"小王一边记,一边想:这些需求先记下来,等会再统一执行。这就是命令模式——把请求封装成对象,可以记录、可以执行、可以撤销。

就像游戏里的操作记录,你可以执行操作,也可以撤销操作。或者智能家居的语音命令,说一句话就能执行一个操作。

生活中的命令模式

命令模式在生活中很常见:

  • 会议记录:把需求记下来,稍后统一执行(虽然有时候会忘记)
  • 游戏操作:记录操作,可以撤销/重做(这个最实用)
  • 智能家居:说句话就能执行操作,非常方便

代码中的命令模式

// 命令接口
interface Command {
    void execute();
    void undo();
}

// 接收者:开发团队
class DevelopmentTeam {
    public void implementFeature(String feature) {
        System.out.println("开发功能:" + feature);
    }
    
    public void cancelFeature(String feature) {
        System.out.println("取消功能:" + feature);
    }
}

// 具体命令:开发需求
class ImplementFeatureCommand implements Command {
    private DevelopmentTeam team;
    private String feature;
    
    public ImplementFeatureCommand(DevelopmentTeam team, String feature) {
        this.team = team;
        this.feature = feature;
    }
    
    @Override
    public void execute() {
        team.implementFeature(feature);
    }
    
    @Override
    public void undo() {
        team.cancelFeature(feature);
    }
}

// 调用者:产品经理
class ProductManager {
    private List<Command> commands = new ArrayList<>();
    
    public void addCommand(Command command) {
        commands.add(command);
    }
    
    public void executeAll() {
        for (Command command : commands) {
            command.execute();
        }
    }
    
    public void undoLast() {
        if (!commands.isEmpty()) {
            Command lastCommand = commands.get(commands.size() - 1);
            lastCommand.undo();
            commands.remove(lastCommand);
        }
    }
}

// 使用示例
public class RequirementMeeting {
    public static void main(String[] args) {
        DevelopmentTeam team = new DevelopmentTeam();
        ProductManager pm = new ProductManager();
        
        // 记录需求
        pm.addCommand(new ImplementFeatureCommand(team, "用户登录功能"));
        pm.addCommand(new ImplementFeatureCommand(team, "商品搜索功能"));
        
        // 统一执行
        pm.executeAll();
        
        // 可以撤销
        pm.undoLast();
    }
}

命令模式的优势:请求和执行完全解耦,想执行就执行,想撤销就撤销,还可以记录日志。就像会议记录,可以随时查看和执行,非常灵活。


🔧 处理系统问题:责任链模式 - 逐级处理

下午3:00,小王遇到了一个系统问题,自己搞了半天也没解决。

"算了,找组长吧。"小王心想。结果组长看了半天,也解决不了。“那就找技术总监吧。”

这就是责任链模式——问题一级一级往上传递,每一级都有机会处理。如果这一级处理不了,就传给下一级。

就像公司里的审批流程,员工 → 组长 → 经理 → 总监,一级一级往上走,谁有权限谁处理。

生活中的责任链模式

责任链模式在生活中很常见:

  • 医院就诊:普通医生看不了,找主任医师,还不行就找专家
  • 公司审批:员工申请,组长批不了就找经理,经理批不了就找总监
  • 安全防护:防火墙挡不住,杀毒软件上,还不行就入侵检测

代码中的责任链模式

// 处理器抽象类
abstract class ProblemHandler {
    protected ProblemHandler nextHandler;
    
    public void setNextHandler(ProblemHandler handler) {
        this.nextHandler = handler;
    }
    
    public abstract void handleProblem(String problem);
    
    protected void passToNext(String problem) {
        if (nextHandler != null) {
            nextHandler.handleProblem(problem);
        } else {
            System.out.println("问题无法解决,需要更高层级处理");
        }
    }
}

// 具体处理器:小王
class DeveloperHandler extends ProblemHandler {
    @Override
    public void handleProblem(String problem) {
        if (problem.contains("简单bug")) {
            System.out.println("小王:这个问题我来解决");
        } else {
            System.out.println("小王:这个问题我解决不了,上报给组长");
            passToNext(problem);
        }
    }
}

// 具体处理器:组长
class TeamLeaderHandler extends ProblemHandler {
    @Override
    public void handleProblem(String problem) {
        if (problem.contains("架构问题")) {
            System.out.println("组长:这个问题我来解决");
        } else {
            System.out.println("组长:这个问题我解决不了,上报给技术总监");
            passToNext(problem);
        }
    }
}

// 具体处理器:技术总监
class CTOHandler extends ProblemHandler {
    @Override
    public void handleProblem(String problem) {
        System.out.println("技术总监:这个问题我来解决");
    }
}

// 使用示例
public class ProblemSolving {
    public static void main(String[] args) {
        // 构建责任链
        ProblemHandler developer = new DeveloperHandler();
        ProblemHandler teamLeader = new TeamLeaderHandler();
        ProblemHandler cto = new CTOHandler();
        
        developer.setNextHandler(teamLeader);
        teamLeader.setNextHandler(cto);
        
        // 处理问题
        developer.handleProblem("复杂的架构问题");
    }
}

责任链模式的优势:可以动态组织处理流程,想加一级就加一级,想减一级就减一级,非常灵活。就像公司的问题处理流程,可以根据实际情况调整。


🏠 下班回家:代理模式 - 代购服务

晚上6:00,小王下班了。今天不想去超市,就在APP上下单,让外卖员帮忙买。

"牛奶、面包、水果…"小王一边下单,一边想:外卖员就是我的代理,他替我去超市,我不用亲自去。这就是代理模式——用一个对象代理另一个对象,可以控制访问,也可以增加额外功能。

就像房产中介代理你找房子,票务网站代理你买票,都是代理模式的应用。

生活中的代理模式

代理模式在生活中很常见:

  • 代购服务:外卖员代理你去超市,你只需要下单就行
  • 票务代理:票务网站代理你买票,不用去现场排队
  • 房产中介:中介代理你找房子,省时省力(虽然要付中介费)

代码中的代理模式

// 主题接口:购物
interface Shopping {
    void buy(String item);
}

// 真实主题:小王自己去购物
class RealShopping implements Shopping {
    @Override
    public void buy(String item) {
        System.out.println("小王亲自去超市购买:" + item);
    }
}

// 代理:外卖员代购
class ShoppingProxy implements Shopping {
    private RealShopping realShopping;
    
    public ShoppingProxy() {
        this.realShopping = new RealShopping();
    }
    
    @Override
    public void buy(String item) {
        // 代理的额外功能:下单、支付、配送
        System.out.println("通过APP下单:" + item);
        System.out.println("支付订单");
        System.out.println("外卖员代购:" + item);
        // 实际还是调用真实对象的购买方法
        realShopping.buy(item);
        System.out.println("配送到家");
    }
}

// 使用示例
public class AfterWork {
    public static void main(String[] args) {
        // 使用代理,不需要亲自去超市
        Shopping shopping = new ShoppingProxy();
        shopping.buy("牛奶、面包、水果");
    }
}

代理模式的优势:可以在不改变原有对象的基础上,增加额外功能(如下单、支付、配送)。就像代购服务,让购物变得更方便,虽然要多花点钱。


📱 刷手机:状态模式 - 不同的状态

晚上10:00,小王洗漱完躺在床上刷手机。他按了一下电源键,手机解锁了。打开微信,刷了会朋友圈,然后锁屏充电。

小王一边充电,一边想:手机有不同的状态——锁屏、解锁、使用中、充电。不同状态下,操作行为也不一样。锁屏时打不开APP,解锁后才能用。这就是状态模式——对象的状态变了,行为也跟着变。

就像红绿灯,红灯停、绿灯行、黄灯等,不同状态下的行为完全不同。

生活中的状态模式

状态模式在生活中很常见:

  • 手机状态:锁屏、解锁、使用中、充电,不同状态行为不同
  • 红绿灯:红灯停、绿灯行、黄灯等,状态决定行为
  • 游戏角色:站立、跑步、跳跃、攻击,不同状态动作不同

代码中的状态模式

// 状态接口
interface PhoneState {
    void unlock();
    void lock();
    void openApp(String app);
    void charge();
}

// 具体状态:锁屏状态
class LockedState implements PhoneState {
    private Phone phone;
    
    public LockedState(Phone phone) {
        this.phone = phone;
    }
    
    @Override
    public void unlock() {
        System.out.println("解锁手机");
        phone.setState(phone.getUnlockedState());
    }
    
    @Override
    public void lock() {
        System.out.println("手机已经锁屏");
    }
    
    @Override
    public void openApp(String app) {
        System.out.println("请先解锁手机");
    }
    
    @Override
    public void charge() {
        System.out.println("手机锁屏充电中...");
    }
}

// 具体状态:解锁状态
class UnlockedState implements PhoneState {
    private Phone phone;
    
    public UnlockedState(Phone phone) {
        this.phone = phone;
    }
    
    @Override
    public void unlock() {
        System.out.println("手机已经解锁");
    }
    
    @Override
    public void lock() {
        System.out.println("锁定手机");
        phone.setState(phone.getLockedState());
    }
    
    @Override
    public void openApp(String app) {
        System.out.println("打开APP:" + app);
    }
    
    @Override
    public void charge() {
        System.out.println("手机使用中充电...");
    }
}

// 上下文:手机
class Phone {
    private PhoneState lockedState;
    private PhoneState unlockedState;
    private PhoneState currentState;
    
    public Phone() {
        lockedState = new LockedState(this);
        unlockedState = new UnlockedState(this);
        currentState = lockedState; // 初始状态为锁屏
    }
    
    public void setState(PhoneState state) {
        this.currentState = state;
    }
    
    public PhoneState getLockedState() {
        return lockedState;
    }
    
    public PhoneState getUnlockedState() {
        return unlockedState;
    }
    
    public void unlock() {
        currentState.unlock();
    }
    
    public void lock() {
        currentState.lock();
    }
    
    public void openApp(String app) {
        currentState.openApp(app);
    }
    
    public void charge() {
        currentState.charge();
    }
}

// 使用示例
public class NightRoutine {
    public static void main(String[] args) {
        Phone phone = new Phone();
        
        // 尝试打开APP(锁屏状态)
        phone.openApp("微信");
        
        // 解锁
        phone.unlock();
        
        // 现在可以打开APP了
        phone.openApp("微信");
        phone.openApp("抖音");
        
        // 锁屏
        phone.lock();
        
        // 充电
        phone.charge();
    }
}

状态模式的优势:把状态转换逻辑封装在状态类里,不用写一大堆if-else。就像手机的状态管理,清晰明了,想加个新状态也很容易。


💤 睡觉:建造者模式 - 构建完美的睡眠环境

晚上11:00,小王准备睡觉了。他先关灯,然后拉窗帘,调空调温度到26度,设置明天7点的闹钟,最后把手机放好。

"完美!"小王一边躺下,一边想:这些步骤可以按不同顺序执行,但最终都是为了构建一个完美的睡眠环境。这就是建造者模式——用多个简单的步骤,一步步构建一个复杂的对象。

就像建房子,打地基、建框架、装修、入住,步骤可以调整,但最终都是为了建好房子。

生活中的建造者模式

建造者模式在生活中很常见:

  • 建造房子:打地基 → 建框架 → 装修 → 入住,一步步来
  • 制作汉堡:面包 → 肉饼 → 蔬菜 → 酱料,想加什么加什么
  • 准备睡觉:关灯 → 拉窗帘 → 调温度 → 设置闹钟,按自己的习惯来

代码中的建造者模式

// 产品:睡眠环境
class SleepEnvironment {
    private boolean lightOff;
    private boolean curtainClosed;
    private int temperature;
    private String alarmTime;
    private boolean phonePlaced;
    
    // Getters and Setters
    public void setLightOff(boolean lightOff) {
        this.lightOff = lightOff;
    }
    
    public void setCurtainClosed(boolean curtainClosed) {
        this.curtainClosed = curtainClosed;
    }
    
    public void setTemperature(int temperature) {
        this.temperature = temperature;
    }
    
    public void setAlarmTime(String alarmTime) {
        this.alarmTime = alarmTime;
    }
    
    public void setPhonePlaced(boolean phonePlaced) {
        this.phonePlaced = phonePlaced;
    }
    
    @Override
    public String toString() {
        return "睡眠环境{" +
                "关灯=" + lightOff +
                ", 拉窗帘=" + curtainClosed +
                ", 温度=" + temperature + "°C" +
                ", 闹钟=" + alarmTime +
                ", 手机已放好=" + phonePlaced +
                '}';
    }
}

// 建造者接口
interface SleepEnvironmentBuilder {
    SleepEnvironmentBuilder turnOffLight();
    SleepEnvironmentBuilder closeCurtain();
    SleepEnvironmentBuilder setTemperature(int temp);
    SleepEnvironmentBuilder setAlarm(String time);
    SleepEnvironmentBuilder placePhone();
    SleepEnvironment build();
}

// 具体建造者
class BedtimeBuilder implements SleepEnvironmentBuilder {
    private SleepEnvironment environment = new SleepEnvironment();
    
    @Override
    public SleepEnvironmentBuilder turnOffLight() {
        System.out.println("关灯");
        environment.setLightOff(true);
        return this;
    }
    
    @Override
    public SleepEnvironmentBuilder closeCurtain() {
        System.out.println("拉窗帘");
        environment.setCurtainClosed(true);
        return this;
    }
    
    @Override
    public SleepEnvironmentBuilder setTemperature(int temp) {
        System.out.println("设置空调温度:" + temp + "°C");
        environment.setTemperature(temp);
        return this;
    }
    
    @Override
    public SleepEnvironmentBuilder setAlarm(String time) {
        System.out.println("设置闹钟:" + time);
        environment.setAlarmTime(time);
        return this;
    }
    
    @Override
    public SleepEnvironmentBuilder placePhone() {
        System.out.println("放好手机");
        environment.setPhonePlaced(true);
        return this;
    }
    
    @Override
    public SleepEnvironment build() {
        return environment;
    }
}

// 使用示例
public class Bedtime {
    public static void main(String[] args) {
        // 使用建造者模式,链式调用,灵活组合
        SleepEnvironment environment = new BedtimeBuilder()
                .turnOffLight()
                .closeCurtain()
                .setTemperature(26)
                .setAlarm("7:00")
                .placePhone()
                .build();
        
        System.out.println("\n" + environment);
        System.out.println("完美!可以睡觉了😴");
    }
}

建造者模式的优势:可以灵活组合构建步骤,代码可读性强,链式调用写起来很舒服。就像准备睡觉,可以按照自己的习惯安排步骤顺序,想先关灯就先关灯,想先拉窗帘就先拉窗帘。


📊 设计模式全景图:小王的一天

看完了小王的一天,我画了张图,把12种设计模式都标出来了:

小王的一天早上单例模式通勤策略模式地铁适配器模式看视频观察者模式工作工厂模式计划模板方法模式午餐装饰器模式开会命令模式问题责任链模式回家代理模式刷手机状态模式睡觉建造者模式

🎯 设计模式分类总结

看完小王的一天,是不是觉得设计模式其实就在身边?按照GoF的分类,这12种模式可以这样归类:

🏭 创建型模式(小王的一天中遇到的)

  1. 单例模式 - 早餐的唯一性
  2. 工厂模式 - 创建不同的工具
  3. 建造者模式 - 构建睡眠环境

🏗️ 结构型模式(小王的一天中遇到的)

  1. 适配器模式 - 地铁换乘
  2. 装饰器模式 - 给面加料
  3. 代理模式 - 代购服务

🎭 行为型模式(小王的一天中遇到的)

  1. 策略模式 - 选择出行方式
  2. 观察者模式 - APP通知
  3. 模板方法模式 - 工作流程
  4. 命令模式 - 执行任务
  5. 责任链模式 - 问题处理
  6. 状态模式 - 手机状态

💡 设计模式的核心思想

看完小王的一天,你会发现设计模式其实就几个核心思想:

  1. 解耦 - 让代码更灵活,就像策略模式,想换出行方式就换,不用改其他代码
  2. 复用 - 避免重复代码,就像工厂模式,统一创建对象,不用到处写new
  3. 扩展 - 容易添加新功能,就像装饰器模式,想加什么功能就加什么
  4. 封装 - 隐藏复杂性,就像代理模式,把复杂的购物过程隐藏起来,你只需要下单就行

🎓 如何学习设计模式?

其实学习设计模式没那么难:

  1. 从生活出发 - 就像小王的一天,设计模式无处不在,多观察生活
  2. 理解场景 - 知道什么情况下用什么模式,不要为了用而用
  3. 动手实践 - 在项目中应用设计模式,光看不练没用
  4. 不断反思 - 思考是否有更好的设计,不要过度设计

🌟 结语

看完小王的一天,你会发现:设计模式不是什么高深的理论,就是解决实际问题的经验总结。它们悄无声息地融入我们的生活,让代码更优雅,让系统更健壮。

记住一句话:设计模式不是目的,而是手段。 我们的目标是写出更好的代码,解决实际的问题。不要为了用设计模式而用设计模式,合适的时候用,不合适的时候别硬用。

当你理解了设计模式背后的思想,你会发现,它们其实很简单,很实用,也很有趣!


📚 延伸阅读

如果你想深入学习设计模式,可以看看这些文章: