设计模式-外观模式

写在前面

Hello,我是易元,这篇文章是我学习设计模式时的笔记和心得体会。如果其中有错误,欢迎大家留言指正!

初版注册功能

那时的UserService还是个清爽少年,只需两步走天下。然而,命运的齿轮开始转动......

java 复制代码
// 初版代码:简单却纯粹的协作  
public class UserService {  
    private UserDao userDao = new UserDao();  
    private EmailService emailService = new EmailService();  

    public void register(String username) {  
        userDao.save(username);          // 数据库:用户已入库!  
        emailService.sendWelcomeEmail(username); // 邮件:叮!您的专属拉花已送达~  
    }  
}  
EmailService
typescript 复制代码
public class EmailService {

    public void sendWelcomeEmail(String username) {
        System.out.println("发送欢迎邮件给: " + username);
    }
}
UserDao
typescript 复制代码
public class UserDao {

    public void save(String userName) {
        System.out.println("用户: " + userName + "已保存到数据库");
    }

}

需求风暴的暴击

产品经理带着新需求闪现:客户超爱邮件功能!但还要加短信通知、送200积分!明天上线!

小易的屏幕疯狂闪烁,手指在键盘上舞成残影:

PointsService
typescript 复制代码
public class PointsService {

    public void addWelcomePoints(String username) {
        System.out.println("增加新人积分(200): " + username);
    }
}
SmsService
typescript 复制代码
public class SmsService {
    public void sendRegisterSms(String username) {
        System.out.println("向: " + username + "发送注册短信");
    }
}
UserService被迫"身兼数职"
java 复制代码
public class UserService {  
    private UserDao userDao = new UserDao();  
    private EmailService emailService = new EmailService();  
    private SmsService smsService = new SmsService();  
    private PointsService pointsService = new PointsService();  

    public void register(String username) {  
        userDao.save(username);          // 存用户  
        emailService.sendWelcomeEmail(username); // 发邮件  
        smsService.sendRegisterSms(username);    // 发短信  
        pointsService.addWelcomePoints(username); // 送积分  
        // UserService:我裂开了.jpg  
    }  
}  

凌晨的办公室回荡着键盘的悲鸣,突然传来窸窸窣窣的对话
UserService :我明明是注册服务,为啥还要当快递员+会计?!这是哪个杀千刀的给我安排这么重的活儿!!
SmsService :老板说必须发短信验证!
PointsService:200积分!少一分都不行!

外观模式的重构

小易盯着屏幕上臃肿的UserService,眉头拧成了死结。他翻开《设计模式之美》,指尖停在了外观模式的章节

设计精髓

  • 核心思想:为子系统提供统一的高层接口

  • 核心角色

    • FacadeUserRegistrationFacade(指挥全局的指挥官)
    • SubSystemUserDao/EmailService等(各司其职的士兵)

重构后的注册服务

子系统保持纯粹职责
typescript 复制代码
public class EmailService {  
    public void sendWelcomeEmail(String username) {  
        System.out.println("发送欢迎邮件给: " + username);  
    }  
}  

public class PointsService {  
    public void addWelcomePoints(String username) {  
        System.out.println("为增加新人积分" + username);  
    }  
}  
UserRegistrationFacade(指挥官)
java 复制代码
public class UserRegistrationFacade {  
    private UserDao userDao = new UserDao();  
    private EmailService emailService = new EmailService();  
    private SmsService smsService = new SmsService();  
    private PointsService pointsService = new PointsService();  

    public void completeRegistration(String username) {  
        userDao.save(username);  
        emailService.sendWelcomeEmail(username);  
        smsService.sendRegisterSms(username);  
        pointsService.addWelcomePoints(username);  
    }  
}  
UserService重归清爽
typescript 复制代码
public class UserService {  
    private UserRegistrationFacade facade = new UserRegistrationFacade();  

    public void register(String username) {  
        System.out.println("业务逻辑处理");  
        facade.completeRegistration(username);  
    }  
}  

晨光透过百叶窗洒在屏幕上,UserService 轻轻哼唱:「我还是从前那个少年,没有一丝丝改变~」

长话短说

核心价值
  • 将多步操作封装为单一接口
  • 业务逻辑与子系统交互解耦
  • 统一管理调用顺序与异常
适用场景
  1. 系统存在多个交互复杂的子系统
  2. 需要降低客户端与子系统的耦合度
  3. 涉及多层调用或复杂初始化流程
  4. 要求统一权限管控或流程监控
实现四步曲
  1. 划定需要封装的子系统边界
  2. 创建外观类定义高层接口
  3. 编排执行顺序
  4. 客户端统一通过外观类交互
特别提示
  • 避免打造"上帝外观",保持单一职责
  • 可搭配工厂模式动态创建子系统
  • 平衡封装力度,预留扩展入口
相关推荐
野犬寒鸦37 分钟前
Linux常用命令详解(下):打包压缩、文本编辑与查找命令
linux·运维·服务器·数据库·后端·github
huohuopro1 小时前
thinkphp模板文件缺失没有报错/thinkphp无法正常访问控制器
后端·thinkphp
cainiao0806054 小时前
《Spring Boot 4.0新特性深度解析》
java·spring boot·后端
-曾牛4 小时前
Spring AI 与 Hugging Face 深度集成:打造高效文本生成应用
java·人工智能·后端·spring·搜索引擎·springai·deepseek
南玖yy4 小时前
C/C++ 内存管理深度解析:从内存分布到实践应用(malloc和new,free和delete的对比与使用,定位 new )
c语言·开发语言·c++·笔记·后端·游戏引擎·课程设计
计算机学姐5 小时前
基于SpringBoot的小区停车位管理系统
java·vue.js·spring boot·后端·mysql·spring·maven
BUG制造机.5 小时前
Go 语言 slice(切片) 的使用
开发语言·后端·golang
小鸡脚来咯5 小时前
请求参数:Header 参数,Body 参数,Path 参数,Query 参数分别是什么意思,什么样的,分别通过哪个注解获取其中的信息
java·spring boot·后端
天上掉下来个程小白6 小时前
添加购物车-02.代码开发
java·服务器·前端·后端·spring·微信小程序·苍穹外卖
幽络源小助理8 小时前
懒人美食帮SpringBoot订餐系统开发实现
java·spring boot·后端·美食