🎭 程序员的一天: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种模式可以这样归类:
🏭 创建型模式(小王的一天中遇到的)
- 单例模式 - 早餐的唯一性
- 工厂模式 - 创建不同的工具
- 建造者模式 - 构建睡眠环境
🏗️ 结构型模式(小王的一天中遇到的)
- 适配器模式 - 地铁换乘
- 装饰器模式 - 给面加料
- 代理模式 - 代购服务
🎭 行为型模式(小王的一天中遇到的)
- 策略模式 - 选择出行方式
- 观察者模式 - APP通知
- 模板方法模式 - 工作流程
- 命令模式 - 执行任务
- 责任链模式 - 问题处理
- 状态模式 - 手机状态
💡 设计模式的核心思想
看完小王的一天,你会发现设计模式其实就几个核心思想:
- 解耦 - 让代码更灵活,就像策略模式,想换出行方式就换,不用改其他代码
- 复用 - 避免重复代码,就像工厂模式,统一创建对象,不用到处写new
- 扩展 - 容易添加新功能,就像装饰器模式,想加什么功能就加什么
- 封装 - 隐藏复杂性,就像代理模式,把复杂的购物过程隐藏起来,你只需要下单就行
🎓 如何学习设计模式?
其实学习设计模式没那么难:
- 从生活出发 - 就像小王的一天,设计模式无处不在,多观察生活
- 理解场景 - 知道什么情况下用什么模式,不要为了用而用
- 动手实践 - 在项目中应用设计模式,光看不练没用
- 不断反思 - 思考是否有更好的设计,不要过度设计
🌟 结语
看完小王的一天,你会发现:设计模式不是什么高深的理论,就是解决实际问题的经验总结。它们悄无声息地融入我们的生活,让代码更优雅,让系统更健壮。
记住一句话:设计模式不是目的,而是手段。 我们的目标是写出更好的代码,解决实际的问题。不要为了用设计模式而用设计模式,合适的时候用,不合适的时候别硬用。
当你理解了设计模式背后的思想,你会发现,它们其实很简单,很实用,也很有趣!
📚 延伸阅读
如果你想深入学习设计模式,可以看看这些文章:
- Java设计模式详解:让代码优雅如诗的秘密武器 - 设计模式基础入门,了解设计模式的核心概念
- 创建型设计模式:对象诞生的艺术与智慧 - 单例、工厂、建造者等创建型模式详解
- 结构型设计模式:代码架构的魔法师 - 适配器、装饰器、代理等结构型模式详解
- 行为型设计模式:对象协作的舞蹈家(上) - 观察者、策略、命令等模式详解
- 行为型设计模式:对象协作的舞蹈家(中) - 状态、模板方法、迭代器等模式详解
- 行为型设计模式:对象协作的舞蹈家(下) - 责任链、中介者、访问者等模式详解