JAVA 设计模式

张开发
2026/4/21 21:17:12 15 分钟阅读

分享文章

JAVA 设计模式
设计模式的作用我能用它做什么那设计模式具体能帮我们做什么呢换句话说学了设计模式到底有什么好处如果你只是写一个简单的“Hello World”程序当然完全不需要设计模式。但是当我们去构建一个大型、复杂的项目时设计模式就能帮我们解决下面这些实实在在的痛点可维护性项目做大后需求总是在变。如果没有良好的设计改一个功能可能会牵扯出一堆“连锁反应”甚至需要重构整个项目。设计模式教会我们如何解耦、如何分层让修改变得像搭积木一样——抽掉一块不影响其他模块。代码复用性很多场景其实都有相似的解决方案。比如你需要保证一个类在整个系统里只有一个实例比如配置文件管理器这时候单例模式就是现成的“轮子”你直接拿来用就好不用自己再去琢磨怎么实现。这就避免了重复造轮子提高了开发效率。沟通效率开发是团队协作的事如果你跟同事说“我在这个地方用了一个观察者模式”对方脑海中立刻就会浮现出“一对多依赖、事件通知、松耦合”这些结构而不用再一行行去读你的代码。设计模式成为了程序员之间的“行话”让沟通变得简洁高效。设计模式都有哪些是如何分类前面我们聊了设计模式的基本概念知道了它就像前辈们留下的“锦囊妙计”。那么这些锦囊妙计到底有哪些呢按照经典的 GoFGang of Four四人组 分类设计模式分为三大类创建型模式、结构型模式和行为型模式。创建型模式Creational Patterns核心目的解决“如何创建对象”的问题让对象的创建和使用分离从而让系统更独立、更灵活。创建型模式说白了就是帮你把对象“生”出来而且生得巧妙不让你直接new一个完事。它们关注的是怎样创建对象使得创建过程不会耦合到具体的类上。1. 单例模式Singleton核心定义保证一个类只有一个实例并提供一个全局访问点。实战场景配置管理器、数据库连接池、线程池。这些对象我们通常只需要一个实例避免重复创建造成资源浪费或数据不一致。讲法想象一下整个公司只有一台咖啡机所有人要用都得去那儿接咖啡——这就是单例。你不能自己随便买一台放工位上否则管理混乱咖啡因超标。在代码里单例模式就保证了类似“咖啡机”这样的全局唯一对象。2. 工厂方法模式Factory Method核心定义定义一个用于创建对象的接口让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。实战场景日志记录器。假设我们有一个日志系统可能需要输出到文件FileLogger、数据库DatabaseLogger或控制台ConsoleLogger。客户端不想知道具体用哪个类只想要一个日志记录器。这时我们可以定义一个LoggerFactory接口里面有一个createLogger()方法然后让FileLoggerFactory、DatabaseLoggerFactory分别实现这个接口各自负责创建对应的日志对象。客户端只需要根据配置选择不同的工厂就能得到想要的日志记录器。生活中工厂方法模式就像是一家总店接口规定每家分店子类都要有自己的招牌菜创建产品的方法。你走进不同的分店就能吃到该店的特色菜。这样总店不用关心每家店具体怎么做菜只约定“有这道菜”就行。在代码里父类定义创建对象的接口子类负责具体实现这样新增产品时只需增加新的工厂子类符合“开闭原则”。3. 抽象工厂模式Abstract Factory核心定义提供一个创建一系列相关或相互依赖对象的接口而无需指定它们具体的类。实战场景跨平台的 UI 组件库。假设我们要开发一个支持 Windows 和 Mac 风格的界面每个风格下都有按钮Button、文本框TextField等组件。这些组件是相关的属于同一产品族。我们不能让 Windows 下出现 Mac 风格的按钮。抽象工厂模式就可以定义一个UIFactory包含createButton()和createTextField()等方法然后提供WindowsUIFactory和MacUIFactory两个具体工厂分别创建 Windows 风格的按钮和文本框以及 Mac 风格的按钮和文本框。客户端只需要选择对应的工厂就能得到一整套风格一致的 UI 组件。生活中抽象工厂就像是一个家具品牌它承诺提供一套风格统一的家具比如现代风格的沙发、茶几、电视柜。如果你选择“宜家现代系列”工厂你得到的沙发、茶几、电视柜都是现代风格的如果你选择“北欧复古系列”工厂得到的全是复古风格。你不能把不同风格的家具混搭因为它们是成套的。抽象工厂就是为了创建一整组相关对象而设计的确保它们属于同一产品族。3. 建造者模式Builder核心定义将一个复杂对象的构建与它的表示分离使得同样的构建过程可以创建不同的表示。实战场景构造一个包含很多可选参数的复杂对象比如一个 Computer 对象有 CPU、内存、硬盘、显卡……你可以一步步地指定要什么配置最后 build 出来。生活中就像去 KFC 点套餐你可以自由组合汉堡、薯条、可乐最后收银员给你配齐。建造者模式就是让你一步步“定制”一个复杂对象而不是写一个巨长的构造方法把所有参数都塞进去。4. 原型模式Prototype核心定义通过复制克隆现有的实例来创建新的实例。实战场景游戏里要生成大量相同类型的小怪如果用 new 然后一个个赋值性能很差。不如先造一个原型小怪然后克隆它又快又方便。Java 里的Cloneable接口就是原型模式的应用。生活中孙悟空拔根毫毛一吹变出一堆猴子——这就是原型模式。原型模式让我们通过复制现有对象来创建新对象特别适合那些创建成本高、但又需要大量相似对象的场景。结构型模式Structural Patterns核心目的类和对象的组合关注如何将类或对象组合成更大的结构就像搭积木一样把功能灵活地组织起来。1. 适配器模式Adapter核心定义将一个类的接口转换成客户希望的另一个接口让原本接口不兼容的类可以协同工作。实战场景读卡器——你把 SD 卡插进读卡器读卡器插进 USB 口电脑就能读取 SD 卡里的照片了。在代码里比如老系统的日志接口是log(String msg)新系统需要info(String msg)你可以写一个适配器把老接口包装一下适配到新接口上。生活中去国外旅游插座孔型不一样你就需要一个转换插头。适配器模式就是这个转换插头让原本不兼容的接口能配合使用。2. 桥接模式Bridge核心定义将抽象部分与实现部分分离使它们可以独立变化。实战场景JDBC 驱动——你写的 SQL 是抽象部分而具体连接的是 MySQL 还是 Oracle 是实现部分。JDBC 桥接了这两者让你换数据库时不用改上层代码。生活中遥控器抽象和电视实现是分开的你可以用同一个遥控器控制不同品牌的电视。桥接模式就是把抽象和实现解耦让两者可以独立扩展。3. 装饰模式Decorator核心定义动态地给一个对象添加额外的职责比继承更灵活。实战场景Java IO 流——new BufferedInputStream(new FileInputStream(test.txt))。FileInputStream 负责读文件BufferedInputStream 给它加上缓冲功能一层套一层功能随意组合。生活中就像买了一杯咖啡你可以加糖、加奶、加巧克力每加一种配料咖啡的功能口味就增强一点。装饰模式就是让你能动态地给对象“加料”而且可以叠加。4. 组合模式Composite核心定义将对象组合成树形结构以表示“部分-整体”的层次让客户端可以统一对待单个对象和组合对象。实战场景文件系统——文件夹里可以包含文件或子文件夹。无论是文件还是文件夹都有“删除”“重命名”等操作。组合模式让客户端可以把文件夹和文件同等对待。生活中公司的组织架构——部门里有员工部门下还有子部门。无论是对员工还是对部门老板都可以发出“工作”指令这就是组合模式的体现。5. 外观模式Facade核心定义为子系统中的一组接口提供一个一致的界面定义一个高层接口让子系统更容易使用。实战场景电脑开机——你只要按一下开机键背后 CPU、内存、硬盘、风扇等等一系列复杂操作就自动完成了。外观模式把复杂的子系统封装起来给客户端一个简单的接口。生活中你只需要按开机键不需要知道硬件是怎么自检的、怎么加载系统的。外观模式就是给你一个“一键启动”的按钮。6. 享元模式Flyweight核心定义运用共享技术有效地支持大量细粒度的对象。实战场景Java 中的 String 常量池、Integer 缓存池。如果你创建多个内容相同的字符串它们会共享同一个内存地址避免重复创建。生活中就像共享单车——大家共用同一批单车而不是每人买一辆。享元模式通过共享对象来减少内存消耗特别适合大量相似对象的场景。7. 代理模式Proxy核心定义为其他对象提供一种代理以控制对这个对象的访问。实战场景Spring AOP——在方法执行前后添加日志、权限检查远程调用RPC——客户端调用代理对象就像调用本地方法一样代理负责网络通信。生活中明星的经纪人——要找明星演出得先跟经纪人谈经纪人帮你处理合同、档期最后才让明星上场。代理模式就是那个经纪人控制着对真实对象的访问。行为型模式Behavioral Patterns核心目的对象之间的通信和责任分配关注对象之间如何交互、如何划分职责。1. 模板方法模式Template Method核心定义定义一个操作中的算法骨架而将一些步骤延迟到子类中使得子类可以不改变算法结构即可重定义某些特定步骤。实战场景Servlet 中的doGet()/doPost()—— 整体流程由容器控制接收请求、响应你只需要重写特定的方法JDBC 模板类把获取连接、关闭连接等固定步骤封装好你只需写 SQL。生活中就像做菜流程是固定的备菜、热锅、下锅、出锅。但具体做什么菜备什么菜、怎么炒由你自己决定。模板方法模式把固定流程定好把可变的部分留给子类实现。2. 命令模式Command核心定义将一个请求封装为一个对象从而使你可用不同的请求对客户进行参数化对请求排队或记录日志以及支持可撤销的操作。实战场景遥控器按钮——每个按钮对应一个命令对象按下按钮就执行命令事务回滚——把操作封装成命令可以 undo。生活中去餐厅吃饭你拿着菜单点菜服务员把菜单传给厨师。菜单就是命令对象它封装了你的需求厨师只管做菜。命令模式把请求发送者和执行者解耦。3. 迭代器模式Iterator核心定义提供一种方法顺序访问一个聚合对象中的各个元素而又不暴露其内部的表示。实战场景Java Collection 框架中的iterator()方法。不管底层是数组、链表还是其他数据结构你都可以用统一的迭代器遍历元素。生活中就像翻一本书你不需要知道书页是怎么装订的你只需要一页一页翻下去就行。迭代器模式给你一个统一的方式遍历集合不用关心集合内部结构。4. 观察者模式Observer核心定义定义对象间的一种一对多的依赖关系当一个对象的状态发生改变时所有依赖于它的对象都得到通知并被自动更新。实战场景事件监听机制——按钮被点击所有注册的监听器都会收到通知消息队列MQ——发布者发布消息订阅者都能收到。生活中就像微信公众号你关注了某个号当它发文章时你就能收到推送。观察者模式实现了一对多的通知机制让被观察者公众号和观察者读者解耦。5. 中介者模式Mediator核心定义用一个中介对象来封装一系列的对象交互使各对象不需要显式地相互引用从而使其耦合松散而且可以独立地改变它们之间的交互。实战场景MVC 中的 Controller —— 它作为中介处理用户请求协调 Model 和 View聊天室——用户通过聊天室发送消息而不是直接私聊每个人。生活中就像飞机塔台飞机之间不直接沟通都跟塔台联系塔台统一调度。中介者模式把多对多的关系简化为一对多减少对象间的耦合。6. 备忘录模式Memento核心定义在不破坏封装性的前提下捕获一个对象的内部状态并在该对象之外保存这个状态以便以后恢复。实战场景编辑器的 Undo撤销功能——每操作一步就保存一个快照撤销时恢复到上一个快照。生活中就像游戏存档你打 BOSS 前存个档万一挂了可以读档重来。备忘录模式就是为了实现这种“后悔药”功能。7. 解释器模式Interpreter核心定义给定一个语言定义它的文法的一种表示并定义一个解释器这个解释器使用该表示来解释语言中的句子。实战场景正则表达式解析、数学表达式计算比如计算12*3。生活中相当于我们定义了一套简单的规则然后写个程序来解释符合这套规则的语句。实际开发中用得较少但在编译器、规则引擎中很有用。8. 状态模式State核心定义允许一个对象在其内部状态改变时改变它的行为让对象看起来似乎修改了它的类。实战场景订单状态流转——待支付、已支付、已发货、已完成不同状态下订单的行为不同比如待支付才能取消已支付不能取消。状态模式把每个状态的行为封装到独立的类中。生活中就像红绿灯不同颜色灯亮车辆行为不同。状态模式把状态和对应的行为封装在一起状态变了行为也跟着变。9. 策略模式Strategy核心定义定义一系列算法把它们一个个封装起来并且使它们可以相互替换让算法的变化独立于使用算法的客户。实战场景聚合支付——根据用户选择调用微信支付、支付宝或银联支付的算法排序算法切换——你可以根据需要选择冒泡排序、快速排序。讲法去旅游你可以选择坐飞机、坐火车或自驾。每一种出行方式就是一种策略。策略模式让你可以灵活切换算法而不影响客户端。10. 责任链模式Chain of Responsibility核心定义使多个对象都有机会处理请求从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链并沿着这条链传递请求直到有一个对象处理它为止。实战场景Filter 过滤器——请求经过一系列过滤器每个过滤器决定是否继续传递OA 系统多级审批——请假单从组长传到经理传到总监直到有人批准。生活中就像公司里的报销审批你先提交给组长组长批不了就转给经理经理批不了再转给总监……责任链模式让请求沿着链传递直到被处理。11. 访问者模式Visitor核心定义表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。实战场景编译器的语法树分析——对抽象语法树中的不同节点做类型检查、代码生成等操作这些操作可以封装成访问者数据报表统计——对不同类型的数据进行统计。生活中就像一个体检中心不同科室的医生访问者对同一个体检者元素进行检查体检者本身不用改变。访问者模式让你在不修改元素类的情况下为它们添加新的操作。总结

更多文章