# design-pattern **Repository Path**: uRick/design-pattern ## Basic Information - **Project Name**: design-pattern - **Description**: 深入设计模式实践,探究Java设计模式的代码复用,提升编码思维与质量。 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-10-13 - **Last Updated**: 2022-10-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 1. 设计模式 **本仓库仅作为学习探索资源** ## 1.1. 代码模板 - code template ```template /** * ${PROJECT_NAME} * ${PACKAGE_NAME} * @author uRick rickwork@163.com * @version 1.0.0 * date: ${DATE} ${TIME} */ ``` - readme template --- ```text project: ${PROJECT_NAME} package: ${PACKAGE_NAME} author: uRick rickwork@163.com version: 1.0.0 date: ${DATE} ${TIME} ``` --- ## 1.2. 设计原则 在了解设计模式之前,先要理解设计模式的6大设计原则,很有必要,所有的设计模式都是围绕这6大原则设计,复用代码,提高代码的可维护性、可读性以及软件质量。 1. **单一职责原则—Simple Responsibility Pinciple, SRP** 面向对象中,在类、接口功能属性设计上尽可能保证职责单一,具体如何设计还是要根据业务需求来完成,也就避免类、接口设计过于臃肿,不利于组件复用、可移植性、灵活性;该原则实践中仁者见仁智者见智,每个设计者都有自己的理解和依据。 2. **里式替换原则—Liskov Substitution Principle, LSP** 在面向对象开发的继承体系中,子类可以扩展父类的功能,但不能改变父类原有的功能,但在实践中,很多设计并未完全遵守该原则,实现要求: - 子类可以实现父类的抽象方法,但是不能覆盖/重写父类的非抽象方法;`实践中,为了拓展流程,覆盖流程时会违背该原则` - 子类中可以增加自己特有的方法;`新增新方法` - 当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松;`父HashMap,子Map,其实这里不应该是重写了,而是重载;体现出,在使用过程中,首先使用父类方法` - 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格或相同。`返回值类型更具体,如父List,子ArrayList` 3. **依赖倒置原则—Dependence Inversion Principle, DIP** 各个功能模块之间应该依赖抽象,而不是依赖细节;“面向抽象编程,细节应该依赖抽象”。 该原则减少了类之间的耦合性,保证类设计的稳定,提供代码组织的可维护性以及可读性;同时避免了需求变动修改带来的风险,在面向对象开发中,要面向抽象编程(接口、抽象类),细节依赖抽象拓展功能。 4. **接口隔离原则—Interface Segregation Principle, ISP** 该原则的思想就是让设计的接口职责单一,也就是尽可能的小,避免设计过于臃肿的接口,不利于后期拓展业务;实践中要根据业务触发来设计,脱离业务都是耍流氓。 5. **迪米特原则—Law of Demeter, LoD** 迪米特原则又叫最少知道原则,尽量降低类之间的耦合程度,不相关的类,不应当纠缠不清;“只跟朋友交流,不与陌生人说话”。 6. **开闭原则—Open-Closed Principle, OCP** 一个类、模块和函数应该对“扩展开放,对修改关闭,抽象构建架构,实现拓展细节”,在面向对象的开发中,遵守开闭原则,要以“抽象”为核心来拓展开发,确定抽象底层,极少变动(修改关闭),拓展由具体实现类来完成。对于抽象层的定义,需要设计者具备优秀的抽象思维能力,能够预见未来的所有拓展功能,因为它作为拓展的根基,定以后不应该随便更改,尽可能保证稳定性;对于拓展,只需复用抽象以及现有实现的组件来拓展衍生出新的功能组件。 7. **合成复用原则(拓展)—Composite/Aggregate Reuse Principle, CARP** 指尽量使用对象组合(has-a)/聚合(contanis-a),而不是继承关系达到软件复用的目的。可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少。 继承我们叫做白箱复用,相当于把所有的实现细节暴露给子类。组合/聚合也称之为黑箱复用,对类以外的对象是无法获取到实现细节的。 ## 1.3. 设计模式分类 统一建模语言,类图符号关系: ```text 依赖:带箭头的虚线表示依赖关系 泛化:使用带空心箭头的实线表示,箭头指向父类(继承) 关联:用一条实线来表示关联关系 聚合:用一个带空心菱形的实线表示,空心菱形指向的是代表“整体”的类 实现:用一个带空心箭头的虚线表示(实现接口) 属性&方法可见性 “+”表示public方法和字段,可以从类外部访问这些方法和字段。 “-”表示private方法和字段,无法从类外部访问这些方法和字段。 “#”表示protect方法和字段,能够访问这些方法和字段的只能是该类自身、该类的子类以及同一包中的类。 “~”表示只有同一包中的类才能访问的方法和字段。 ``` 1. 创建型 > 创建型是通过对象实例化过程的抽象,定义抽象的接口,封装对象创建的时机。 | 序号 | 类型 | 英文 | 说明 | | :--: | :----------: | :---------------: | :-------------------------------------------------------------------------------------------------------------------- | | 1 | 抽象工厂模式 | Abstract Factory | 提供创建一组或一系列或相互依赖对象的接口, 适合基于工厂创建不同的产品系列 | | 2 | 构造器模式 | Builder | 创建复杂对象时,可以使用构造器模式,将复杂的构建过程或状态屏蔽在构造器中 | | 3 | 工厂方法模式 | Factory Method | 具体的创建对象,由子类或者拓展类来实现;适用于某个类创建实例不清楚具体由那个子类创建的, 通过工厂方法来传相关参数实现 | | 4 | 原型模式 | Prototype | 以现有的对象,通过原型拷贝获取一个新的对象 | | 5 | 单例模式 | Singleton | 只允许创建一份实例对象 | 2. 结构型 > 结构型主要用于组合已有的类或对象生成一个更大的体系结构,一般采用继承组合接口来实现,对外提供统一的功能。 | 序号 | 类型 | 英文 | 说明 | | :--: | :--------: | :-------: | :--------------------------------------------------------------------------------------------------- | | 1 | 适配器模式 | Adapter | 将一类接口转换为另一类接口,通常用于接口适配兼容性问题,包括对象适配(组合)、类适配(继承) | | 2 | 桥接模式 | Bridge | 将接口与实现分离,分离两个独立相关的组件,组件之间通过组合关联,关联对象可以是抽象或实现 | | 3 | 组合模式 | Composite | 组合复杂的对象,”部分与整体“的关系,适合具有相同特征的组件抽象 | | 4 | 装饰模式 | Decorator | 动态的为对象添加额外的责任或功能 | | 5 | 外观模式 | Facade | 对外提供统一的接口,屏蔽内部接口或子系统的细节 | | 6 | 享元模式 | Flyweight | 通过共享对象来降低性能开销,也就是“通过共享实例,而避免new实例” | | 7 | 代理模式 | Proxy | 代理某个对象处理相关事务,实践中常见用在”面向切面“拓展编程中,如记录日志、构建监控、植入插件程序等 | 3. 行为型 > 行为型主要用于对象之间的职责以及提供服务的分配,不仅是描述对象和类的模式,还描述他们之间的通信模式。 | 序号 | 类型 | 英文 | 说明 | | :--: | :----------: | :-------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 1 | 责任链模式 | Chain | 对象之间,业务流程之间可以通过责任链传递消息,每一个链之间具有相关链性,前一个链输出作为下一个链的输入 | | 2 | 命令模式 | Commond | 把接收的请求封装为对象,做为参数传递,并把请求放入队列中,按操作执行相关命令,支持撤销操作 | | 3 | 迭代器模式 | Iterator | 提供数据集合的遍历方式,简化集合遍历,提供统一遍历接口 | | 4 | 解释器模式 | Interpreter | 通常用于解释定义的语言或表达式,通过上下文传输层层解析(类似迭代)语法结构,实际工作中使用较少 | | 5 | 中介者模式 | Mediator | 用Mediator对象来封装一系列的对象交互,降低对象间的耦合度,不直接引用对象,而是通过中间人协调;
可以把该模式理解为一种思想,当不想对外暴露过多的功能组件时,可以通过中间者来协调、仲裁、通讯 ,对外仅暴露中间者 | | 6 | 备忘录模式 | Memento | 备忘录模式也可以叫后悔药模式,通过备忘录来记录历史版本记录(保存快照),可以支持撤销、重做;
实践中常见的版本管理、游戏存档、程序发布与该模式有很多相似之处 | | 7 | 观察者模式 | Observer | 观察主体事件,实时广播观察到的消息 | | 8 | 状态模式 | State | 其本质就是把变化的状态封装到对象中,状态的变化通过对象来传递,实践中可以用于复杂的状态切换场景。
在项目开发中很多状态维护都是面向过程的开发方式,随着状态增大,出现大量`if-else`,
导致可读性、可维护性极差,而通过`state`模式改造后,业务代码易于理解、结构清晰、拓展性更高,
对状态进行分类,不同类别做不同的状态切换操作 | | 9 | 策略模式 | Strategy | 算法与业务分离,把算法封装为独立的策略组件,业务根据需求动态使用不同策略算法替换 | | 10 | 模板方法模式 | Template Method | 抽象类根据处理流程提供模板方法,子类实现该模板方法,适用于对通用流程的封装 | | 11 | 访问者模式 | Visitor | 将数据处理与数据结构分离,可以理解为“解耦业务处理与数据”,适合对数据处理操作变更频繁的场景 | ![design-mode-realtio](src/main/resources/design-mode-realtion.png) ## 1.4. 参考资源 1. 《图解设计模式》——结城洁著,杨文轩译 2. [Refactoring](https://refactoringguru.cn/refactoring) 3. [Gof23设计模式速记(迷你图)](https://blog.csdn.net/lilongsy/article/details/102475296) 4. 《重学Java设计模式》——小傅哥著