软件设计模式(Java)复习
目录
一、设计模式的定义
目的:
二、设计模式的基本要素
三、设计模式的分类(复习题纲里面没有,但我的建议是狠狠的背)
四、设计模式的优点
五、面向对象设计的七大原则
六、模式分类及详解
(一)创建型模式(Creational Patterns)
1. 简单工厂模式(Simple Factory)
2. 工厂方法模式(Factory Method)
3. 单例模式(Singleton)
4. 原型模式(Prototype)
(二)结构型模式(Structural Patterns)
1.桥接模式(Bridge)
2. 适配器模式(Adapter)
3. 装饰器模式(Decorator)
4. 代理模式(Proxy)
(三)行为型模式(Behavioral Patterns)
1. 观察者模式(Observer)
2. 命令模式(Command)
七、模式对比与总结
一、设计模式的定义
是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结;是一种用于对软件系统中不断重现的设计问题的解决方案进行文档化的技术;是一种共享专家设计经验的技术。
目的:
为了可重用代码、让代码更容易被他人理解、提高代码可靠性
二、设计模式的基本要素
设计模式一般包含模式名称、问题、目的、解决方案、效果、实例代码和相关设计模式等基本要素,4个关键要素如下:
模式名称 (Pattern Name) :根据或结构命名
问题 (Problem) :原始存在的问题及问题原因
解决方案 (Solution) :解决问题的职责及相互关系
效果 (Consequences) :效果评价及选择
三、设计模式的分类(复习题纲里面没有,但我的建议是狠狠的背)
根据目的(模式是用来做什么的)可分为创建型(Creational),结构型(Structural)和行为型(Behavioral)三类:
创建型模式主要用于创建对象,5种
结构型模式主要用于处理类或对象的组合,7种
行为型模式主要用于描述类或对象如何交互和怎样分配职责,11种
根据范围,即模式主要是处理类之间的关系还是处理对象之间的关系,可分为类模式和对象模式两种:
类模式处理类和子类之间的关系,这些关系通过继承建立,在编译时刻就被确定下来,是一种静态关系
对象模式处理对象间的关系,这些关系在运行时变化,更具动态性
四、设计模式的优点
融合了众多专家的经验,并以一种标准的形式供广大开发人员所用;
提供了一套通用的设计词汇和一种通用的语言,以方便开发人员之间进行沟通和交流,使得设计方案更加通俗易懂;
让人们可以更加简单方便地复用成功的设计和体系结构;
使得设计方案更加灵活,且易于修改;
将提高软件系统的开发效率和软件质量,且在一定程度上节约设计成本;
有助于初学者更深入地理解面向对象思想,方便阅读和学习现有类库与其他系统中的源代码,还可以提高软件的设计水平和代码质量;
五、面向对象设计的七大原则
原则名称 | 核心思想 |
单一职责原则 | 一个类只负责一项职责,避免功能冗余。 |
开闭原则 | 软件实体对扩展开放,对修改关闭(通过接口扩展而非修改源码)。 |
里氏替换原则 | 子类可替换父类且不破坏程序原有逻辑(子类需遵循父类契约)。 |
接口隔离原则 | 客户端不依赖不需要的接口,使用多个特定接口替代单一复杂接口。 |
依赖倒置原则 | 高层模块不依赖低层模块,两者均依赖抽象(接口 / 抽象类)。 |
迪米特法则(最少知识原则) | 一个对象应尽可能少地了解其他对象,降低耦合度。 |
合成复用原则 | 优先使用组合 / 聚合而非继承来复用代码,保持类的独立性。 |
六、模式分类及详解
(一)创建型模式(Creational Patterns)
1. 简单工厂模式(Simple Factory)
- 定义:通过一个工厂类根据参数创建不同类型的产品对象,隐藏对象创建细节。
- 角色:
- 工厂(Factory):创建产品的核心类。
- 产品接口(Product):定义产品公共接口。
- 具体产品(ConcreteProduct):接口实现类。
- 优点:封装对象创建,客户端无需关心细节;便于扩展新产品。
- 缺点:工厂类职责过重,违反单一职责原则;扩展新产品需修改工厂类,违反开闭原则。
- 适用环境:产品类型较少,且不常扩展的场景(如日志记录器简单创建)。
2. 工厂方法模式(Factory Method)
- 定义:将对象创建延迟到子类,每个子类创建不同的产品对象。
- 角色:
- 抽象工厂(AbstractFactory):定义创建产品的接口。
- 具体工厂(ConcreteFactory):实现接口,创建具体产品。
- 产品接口(Product)、具体产品(ConcreteProduct):同简单工厂。
- 优点:符合开闭原则,扩展新产品只需新增工厂和产品类;遵循单一职责原则。
- 缺点:类数量增加,复杂度提升。
- 适用环境:产品族需要扩展,或创建逻辑需要灵活变化的场景(如数据库连接工厂)。
某系统运行日志记录器(Logger)可以通过多种途径保存系统的运行日志,例如通过文件记录或数据库记录,用户可以通过修改配置文件灵活地更换日志记录方式。在设计各类日志记录器时,开发人员发现需要对日志记录器进行一些初始化工作,初始化参数的设置过程较为复杂,而且某些参数的设置有严格的先后次序,否则可能会发生记录失败。为了更好地封装记录器的初始化过程并保证多种记录器切换的灵活性,现使用工厂方法模式设计该系统。
3. 单例模式(Singleton)
- 定义:确保类只有一个实例,并提供全局访问点。
- 角色:
- 单例类(Singleton):包含私有构造函数、静态实例和获取实例的方法。
- 优点:节省资源(如数据库连接池),确保全局状态统一。
- 缺点:破坏面向对象封装性,难以测试;可能导致内存泄漏。
- 适用环境:需要全局唯一实例的场景(如日志管理器、配置管理器)。
某软件公司承接了一个服务器负载均衡(Load Balance)软件的开发工作,该软件运行在一台负载均衡服务器上,可以将并发访问和数据流量分发到服务器集群中的多台设备上进行并发处理,提高了系统的整体处理能力,缩短了响应时间。由于集群中的服务器需要动态删减,且客户端请求需要统一分发,因此需要确保负载均衡器的唯一性,只能有一个负载均衡器来负责服务器的管理和请求的分发,否则将会带来服务器状态的不一致以及请求分配冲突等问题。如何确保负载均衡器的唯一性是该软件成功的关键,试使用单例模式设计服务器负载均衡器。
4. 原型模式(Prototype)
- 定义:通过复制已有对象(原型)来创建新对象,避免重复初始化过程,提高对象创建效率。
- 角色:
- 原型接口(Prototype):声明克隆方法clone()。
- 具体原型类(ConcretePrototype):实现克隆方法,创建自身副本。
- 优点:简化对象创建过程,提高性能;便于动态添加或删除对象类型。
- 缺点:每个类都需实现克隆方法,较复杂的对象克隆(如包含引用对象)需处理深拷贝问题。
- 适用环境:创建对象成本较高,且新对象与已有对象差异较小时(如游戏中创建大量相似角色);对象种类较少且可复用已有实例时。
在使用某OA系统时,有些岗位的员工发现他们每周的工作都大同小异,因此在填写工作周报时很多内容都是重复的,为了提高工作周报的创建效率,大家迫切地希望有一种机制能够快速创建相同或者相似的周报,包括创建周报的附件。试使用原型模式对该OA系统中的工作周报创建模块进行改进。且需要能查询比较最近几周的周报的变化情况。
(二)结构型模式(Structural Patterns)
1.桥接模式(Bridge)
- 定义:将抽象部分与实现部分分离,使它们可以独立地变化,通过组合而非继承的方式建立两者联系,避免因多维度变化导致的类爆炸问题。
- 角色:
- 抽象化(Abstraction):定义抽象接口,持有实现化角色的引用,作为抽象层的基础。
- 扩展抽象化(RefinedAbstraction):继承抽象化角色,实现具体的业务逻辑,对抽象功能进行扩展。
- 实现化(Implementor):定义实现接口,声明具体实现的方法,是实现部分的抽象。
- 具体实现化(ConcreteImplementor):实现 Implementor 接口,提供具体的功能实现。
- 优点:
- 实现抽象和实现的解耦,两者可以独立扩展,符合开闭原则。
- 提高系统的可维护性和可扩展性,通过组合替代继承,避免子类数量膨胀。
- 更好地应对多维度变化,适用于抽象和实现都可能变化的场景。
- 缺点:
- 增加系统设计的复杂度,需要准确识别抽象和实现两个维度。
- 理解和应用难度较高,尤其是对于初学者,需要对抽象和接口有较深的理解。
- 适用环境:
- 当一个类存在两个独立变化的维度,且需要独立扩展时。
- 希望在抽象和具体实现之间增加更多灵活性,避免使用继承导致类数量剧增。
某软件公司要开发一个跨平台图像浏览系统,要求该系统能够显示BMP、JPG、GIF、PNG等多种格式的文件,并且能够在Windows、Linux、UNIX等多个操作系统上运行。系统首先将各种格式的文件解析为像素矩阵(Matrix),然后将像素矩阵显示在屏幕上,在不同的操作系统中可以调用不同的绘制函数来绘制像素矩阵(变化最大,可考虑成业务实现部分)。另外,系统需具有较好的扩展性,以便在将来支持新的文件格式和操作系统。试使用桥接模式设计该跨平台图像浏览系统。
2. 适配器模式(Adapter)
- 定义:将一个类的接口转换为客户端期望的另一个接口,解决接口不兼容问题。
- 类型:
- 类适配器:通过继承实现适配(Java 中仅支持单继承,使用较少)。
- 对象适配器:通过组合实现适配(更常用)。
- 角色(对象适配器):
- 目标接口(Target):客户端期望的接口。
- 适配者(Adaptee):需要被适配的类。
- 适配器(Adapter):连接目标和适配者的类。
- 优点:提高类的复用性,无需修改原有代码;符合开闭原则。
- 适用环境:整合不同接口的第三方库,或新旧系统接口兼容。
在为某学校开发教务管理系统时,开发人员发现需要对学生成绩进行排序和查找,该系统的设计人员已经开发了一个成绩操作接口ScoreOperation,在该接口中声明了排序方法Sort(int[]) 和查找方法Search(int[], int),为了提高排序和查找的效率,开发人员决定重用现有算法库中的快速排序算法类QuickSortClass和二分查找算法类BinarySearchClass,其中QuickSortClass的QuickSort(int[])方法实现了快速排序,BinarySearchClass的BinarySearch (int[], int)方法实现了二分查找。
由于某些原因,开发人员已经找不到该算法库的源代码,无法直接通过复制和粘贴操作来重用其中的代码;而且部分开发人员已经针对ScoreOperation接口(自己开发的接口)编程,如果再要求对该接口进行修改或要求大家直接使用QuickSortClass类和BinarySearchClass类将导致大量代码需要修改。
现使用适配器模式设计一个系统,在不修改已有代码的前提下将类QuickSortClass和类BinarySearchClass的相关方法适配到ScoreOperation接口中。
3. 装饰器模式(Decorator)
- 定义:动态地给对象添加额外职责,比继承更灵活(不修改原有类)。
- 角色:
- 组件接口(Component):定义对象接口。
- 具体组件(ConcreteComponent):接口实现类。
- 装饰器抽象类(Decorator):持有组件引用,实现接口。
- 具体装饰器(ConcreteDecorator):添加额外功能。
- 优点:避免子类爆炸,可动态组合多个装饰器;符合开闭原则。
- 适用环境:需要动态扩展对象功能,或多个扩展功能可组合的场景(如 Java IO 流)。
某软件公司基于面向对象技术开发了一套图形界面构件库——VisualComponent,该构件库提供了大量基本构件,如窗体、文本框、列表框等,由于在使用该构件库时,用户经常要求定制一些特殊的显示效果,如带滚动条的窗体、带黑色边框的文本框、既带滚动条又带黑色边框的列表框等等,因此经常需要对该构件库进行扩展以增强其功能。
现使用装饰模式来设计该图形界面构件库。
4. 代理模式(Proxy)
- 定义:为其他对象提供一种代理以控制对这个对象的访问,代理对象在客户端和目标对象之间起到中介作用。
- 角色:
- 主题接口(Subject):定义真实主题和代理主题的共同接口,客户端通过该接口访问真实对象。
- 真实主题(RealSubject):实现主题接口,是代理对象所代表的真实对象,是最终要引用的对象。
- 代理主题(Proxy):持有真实主题的引用,在客户端调用时进行预处理或后处理,再将请求转发给真实主题对象。
某软件公司承接了某信息咨询公司的收费商务信息查询系统的开发任务,该系统的基本需求如下:
(1) 在进行商务信息查询之前用户需要通过身份验证,只有合法用户才能够使用该查询系统;
(2) 在进行商务信息查询时系统需要记录查询日志,以便根据查询次数收取查询费用。
该软件公司开发人员已完成了商务信息查询模块的开发任务,现希望能够以一种松耦合的方式向原有系统增加身份验证和日志记录功能,客户端代码可以无区别地对待原始的商务信息查询模块和增加新功能之后的商务信息查询模块,而且可能在将来还要在该信息查询模块中增加一些新的功能。
现使用代理模式设计并实现该收费商务信息查询系统。
优点:
- 职责清晰,真实主题专注于业务逻辑,代理主题负责其他事务。
- 高扩展性,代理类可以灵活扩展,而不影响真实主题。
- 保护真实主题,代理类可以控制对真实主题的访问权限。
缺点:
- 增加系统复杂度,引入代理对象会使系统处理变慢。
- 可能导致类数量增加,尤其是动态代理场景。
适用环境:
- 远程代理:为一个对象在不同的地址空间提供局部代表,隐藏对象存在于不同地址空间的事实。
- 虚拟代理:根据需要创建开销很大的对象,通过它来存放实例化需要很长时间的真实对象。
- 保护代理:控制对原始对象的访问,用于对象应该有不同的访问权限的时候。
- 智能指引:取代了简单的指针,在访问对象时执行一些附加操作,如引用计数、线程安全检查等。
(三)行为型模式(Behavioral Patterns)
1. 观察者模式(Observer)
- 定义:当对象状态变化时,自动通知依赖它的其他对象(发布 - 订阅模式)。
- 角色:
- 主题(Subject):维护观察者列表,通知状态变化。
- 观察者(Observer):定义更新接口。
- 具体主题(ConcreteSubject):实现主题接口,管理状态。
- 具体观察者(ConcreteObserver):实现更新逻辑。
- 优点:降低主题与观察者耦合度,支持广播通知;便于扩展新观察者。
- 适用环境:需要实时响应状态变化的场景(如消息推送、股票行情监控)。
在某多人联机对战游戏中,多个玩家可以加入同一战队组成联盟,当战队中的某一成员受到敌人攻击时将给所有其他盟友发送通知,盟友收到通知后将做出响应。
现使用观察者模式设计并实现该过程,以实现战队成员之间的联动。
2. 命令模式(Command)
- 定义:将请求封装为对象,使客户端与接收者解耦,支持请求排队、撤销等操作。
- 角色:
- 命令接口(Command):定义执行方法。
- 具体命令(ConcreteCommand):持有接收者引用,实现执行逻辑。
- 接收者(Receiver):执行具体操作。
- 调用者(Invoker):触发命令执行。
- 优点:支持日志记录、撤销操作(Undo);符合开闭原则,易于扩展新命令。
- 适用环境:需要支持撤销、事务或异步操作的场景(如文本编辑器的撤销功能)。
为了用户使用方便,某系统提供了一系列功能键,用户可以自定义功能键的功能,例如功能键FunctionButton 可以用于退出系统(由SystemExitClass类来实现),也可以用于显示帮助文档(由DisplayHelpClass类来实现)。
用户可以通过修改配置文件来改变功能键的用途,现使用命令模式来设计改系统,使得功能键类与功能类之间解耦,可为同一个功能键设置不同的功能。
七、模式对比与总结
- 创建型模式关注对象的创建逻辑,解决复杂对象初始化问题(如单例、工厂、原型)。
- 结构型模式关注类 / 对象的组合,优化系统结构(如适配器、装饰器、桥接)。
- 行为型模式关注对象间的交互,提升系统灵活性(如观察者、命令)。