# littleyao的设计模式课 **Repository Path**: lx201418/design_pattern ## Basic Information - **Project Name**: littleyao的设计模式课 - **Description**: 该仓库为自己学习设计模式的总结 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-06-04 - **Last Updated**: 2024-05-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README :cat:1.设计模式学习记录 该文档为在个人学习过程中的学习笔记,主要参照的资料为: 1. 设计模式java: [项目github地址](https://github.com/quanke/design-pattern-java) [阅读地址](https://gof.quanke.name/) 2. 图说设计模式: [项目github地址](https://github.com/me115/design_patterns) [阅读地址](http://design-patterns.readthedocs.org/zh_CN/latest/index.html) 3. 学习书籍: 《设计模式:可复用面向对象软件的基础》 ## :innocent:学习方法 - 先理论,再实践 - 学习这门课的目的:在学习设计模式的过程中,学习一些常见问题的最优解决方案,有助于提升自己在代码编写和系统设计上的能力,让自己写出更高的代码,也能够提升自己对于工程系统的认识。 - 学习的过程为:先了解并掌握设计模式的基础理论知识和核心概念,然后设计UML类图,最后对照UML类图编写模式的代码。 - 设计模式的基础理论包括:学科基础导论,核心内容部分。其中核心内容部分分为两部分来看,一部分是设计原则,一部分是设计模式。设计原则是为了构建更加高效,可扩展,高可用的系统的指导思想。设计模式的实现是为了遵循或者达到设计原则的要求而提出的解决方案。 - 学习过程使用到的工具有: 1. IDEA ---编写java代码 ![image-20210602133214770](https://gitee.com/lx201418/picRepository/raw/master/img/20210602133214.png) 2. draw.io ---制作UML类图有离线版和[在线版](https://app.diagrams.net/)。 ![image-20210605235147434](https://gitee.com/lx201418/picRepository/raw/master/img/20210605235147.png) 3. Typora ---用来编辑文档 ![image-20210605235226816](https://gitee.com/lx201418/picRepository/raw/master/img/20210605235227.png) 4. Snipaste ---用来截图 ![image-20210602133619612](https://gitee.com/lx201418/picRepository/raw/master/img/20210602133619.png) # :fire:2.杂项导言 - 在软件工程领域,设计模式是一套通用的可复用的解决方案,用来解决在软件设计过程中产生的通用问题。==它不是一个可以直接转换成源代码的设计,只是一套在软件系统设计过程中程序员应该遵循的最佳实践准则==。 ==官方定义== - 设计模式就是在构建系统工程的时候对于解决一些特定问题的最佳实践。设计模式的角色类似于==系统代码构建指南或者系统构建的解决方案==。学好设计模式有助于系统设计过程中代码组织的有效性和合理性。 - 24种设计模式是GOF的23种设计模式加上简单工厂模式。设计模式不只有这24种,还有更多的用于解决更高级复杂的问题的模式方法。所以在学习的时候,不能局限的认为这几种设计模式就是整个设计模式的全部。而是应该去学习设计模式的设计思想,然后在遇到特定问题的时候使用设计模式去解决问题。 - ==不要滥用设计模式。== - 设计模式学习的整体划分--按照解决的问题分为三个大类 1. 构建型(类的创建): 用于解决对象创建的问题, 2. 结构型(代码的结构层次): 用于解决系统的结构设计 3. 行为型: 用于解决儿功能角色的设计 - 学习设计模式的基础课程 1. UML类图和时序图 2. 面向对象语言 # :heart_eyes:3.UML类图和时序图基础 - 学习工具-draw.io - UML:统一建模语言,常见的可建模的图分为:时序图,用例图,活动图,组件图,类图。 ## 1.类图之类或接口符号 ![image-20210602155552890](https://gitee.com/lx201418/picRepository/raw/master/img/20210602155553.png) ## 2. 类图之类关系标识符号 ![image-20210609201112471](https://gitee.com/lx201418/picRepository/raw/master/img/20210609201112.png) - 关联关系默认不强调方向,表示对象间相互知道;如果特别强调方向,使用单向箭头标识A-B,表示A依赖B但B不依赖A. - 关联关系强调一种拥有关系,而依赖这强调的是一种使用关系。 ## 3.时序图 - 时序图(Sequence Diagram)用来表示对象之间传递消息的时间顺序,它用来表示用例的行为顺序。==时序图中显示的是参与交互的对象及其对象之间消息交互的顺序。== - 我们在画时序图时会涉及7种元素:角色(Actor)、对象(Object)、生命线(LifeLine)、控制焦点(Activation)、消息(Message)、自关联消息、组合片段。其中前6种是比较常用和重要的元素,剩余的一种组合片段元素不是很常用 ### 3.1 系统角色(Actor) - 系统角色,可以是人或者其他系统,子系统。表示系统的用户,或者事件的触发者。使用方式跟对象相同,有自己的生命线。作为事件按照时间顺序的发起者或者执行者。 ![image-20210602202753475](https://gitee.com/lx201418/picRepository/raw/master/img/20210602202753.png) ### 3.2 对象(Object) - 对象位于时序图的顶部,以一个矩形表示,对象的命名方式为 1. 对象名:类名 2. 对象名 3. 类名 ![image-20210602202945808](https://gitee.com/lx201418/picRepository/raw/master/img/20210602202945.png) ### 3.3 生命线(LifeLine) - 用一条垂直的虚线表示来表示对象的生命周期,从创建到消亡,顺序为由上而下。
### 3.4 控制焦点(Activation) - 控制焦点代表对象在生命线上某段时期执行的操作,在该期间,对象处于激活状态,需要执行任务,其他时间对象出于休眠状态。==有时候称为对象激活期==。以一个竖直的窄矩形表示。矩阵的高度表示该激活时期的长短,从高处开始,到低处结束。
### 3.5 消息(Message) 表示对象之间进行信息交互。按照类型分有3种消息。 1. ###### 同步消息(Synchronous Message) - 消息的发送者把控制传递给消息的接收者,然后停止活动,等待消息的接收者放弃或者返回控制。用来表示同步的意义。以一条实线+实心箭头表示。 ![image-20210602203828945](https://gitee.com/lx201418/picRepository/raw/master/img/20210602203829.png) 2. ###### 异步消息(Asynchronous Message) - 消息发送者通过消息把信号传递给消息的接收者,然后继续自己的活动,不等待接受者返回消息或者控制。异步消息的接收者和发送者是并发工作的。以一条实线+大于号表示。 ![image-20210602204146948](https://gitee.com/lx201418/picRepository/raw/master/img/20210602204147.png) 3. ###### 返回消息(Return Message) - 返回消息表示从过程调用返回。以小于号+虚线表示。 ![image-20210602204256834](https://gitee.com/lx201418/picRepository/raw/master/img/20210602204256.png) ### 3.6 自关联消息 - 表示方法的自身调用或者一个对象内的一个方法调用另外一个方法。以一个半闭合的长方形+下方实心箭头表示。 - ==消息为对象之间的信息传递或者交互,自关联消息可以理解为对象自己跟自己交互。==
### 3.7 组合片段 - 组合片段用来解决交互执行的条件和方式,它允许在序列图中直接表示逻辑组件,用于通过指定条件或子进程的应用区域,为任何生命线的任何部分定义特殊条件和子进程。 - ==简单理解就是用来表示程序执行逻辑的符号==。 ### 3.8 简单的时序图示例
# 4.开篇:7大设计原则 - 这个是系统设计的指导思想, ## :star2:1. 开闭原则 - 一个软件实体应当对扩展开放,对修改关闭。==即实体应尽量在不修改原有代码的情况下进行扩展。== - 开闭原则是面向对象设计的目标 ## :star2:2. 单一职责原则 - 单一职责原则是最简单的面向对象设计原则,它用于控制类的粒度大小。 - 单一职责原则定义如下: 单一职责原则(Single Responsibility Principle, SRP):==一个类只负责一个功能领域中的相应职责==,或者可以定义为:==就一个类而言,应该只有一个引起它变化的原因==。 - 单一职责原则告诉我们:==个类不能太“累”!在软件系统中,一个类(大到模块,小到方法)承担的职责越多,它被复用的可能性就越小,而且一个类承担的职责过多,就相当于将这些职责耦合在一起,当其中一个职责变化时,可能会影响其他职责的运作,因此要将这些职责进行分离,将不同的职责封装在不同的类中,即将不同的变化原因封装在不同的类中,如果多个职责总是同时发生改变则可将它们封装在同一类中。单一职责原则是实现高内聚、低耦合的指导方针,它是最简单但又最难运用的原则,需要设计人员发现类的不同职责并将其分离。== ## 3. 里氏替换原则 - 所有引用基类(父类)的地方必须能透明地使用其子类的对象。超类的引用指向子类的实例. ## :boom:4. 依赖倒转原则 - 依赖倒转原则就是面向对象设计的主要实现机制之一,它是系统抽象化的具体实现. - 依赖倒转原则要求==我们在程序代码中传递参数时或在关联关系中,尽量引用层次高的抽象层类==,即使用接口和抽象类进行变量类型声明、参数类型声明、方法返回类型声明,以及数据类型的转换等,而不要用具体类来做这些事情。为了确保该原则的应用,一个具体类应当只实现接口或抽象类中声明过的方法,而不要给出多余的方法,否则将无法调用到在子类中增加的新方法。 > 1. 模块间的依赖通过抽象发生,==实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的== > 2. 接口或抽象类不依赖于实现类 > 3. 实现类依赖于接口或抽象类 ## 5. 接口隔离原则 - 接口隔离原则(Interface Segregation Principle, ISP):使用多个专门的接口,而不使用单一的总接口,即==客户端不应该依赖那些它不需要的接口==。 - 当一个接口太大时,==我们需要将它分割成一些更细小的接口,使用该接口的客户端仅需知道与之相关的方法即可。==每一个接口应该承担一种相对独立的角色,不干不该干的事,该干的事都要干。这里的“接口”往往有两种不同的含义:==一种是指一个类型所具有的方法特征的集合,仅仅是一种逻辑上的抽象;==另外一种是指某种语言具体的“接口”定义,有严格的定义和结构,比如Java语言中的interface。 ## :blush:6. 合成复用原则 - 合成复用原则就是在一个新的对象里通过关联关系(包括组合关系和聚合关系)来使用一些已有的对象,使之成为新对象的一部分;新对象通过委派调用已有对象的方法达到复用功能的目的。简言之:==复用时要尽量使用组合/聚合关系(关联关系),少用继承。== - 类之间的关系: 1. 关联:一个类的实例是另一个类的成员变量 - 关联关系包含:组合和聚合。 - 关联关系在实现上都是使用其他的类作为属性实现的,强调一种整体与部分的组合关系。 - 组合关系:概念上强调的是:部分不能脱离整体而存在,A类的构造方法里创建B类的对象;描述的是整体与部分的关系。整体和部分的生命周期相同,同一时刻产生,同一时刻消亡。 - 聚合关系:概念上强调的是: 脱离了整体,部分依然可以有意义。整体与部分存在同生命周期的概念。在代码的实现上:A类的对象在创建时不会立即创建B类的对象(在构造器中不创建B对象),而是等待一个外界的对象传给它;描述的是整体与个人的关系。 2. 依赖关系:==一般指由局部变量、函数参数,函数调用、返回值建立的对于其他对象的调用关系==。 3. 继承关系(泛化的一种) 4. 实现关系 ## :fire:7. 迪米特法则 - 一个软件实体应当尽可能少地与其他实体发生相互作用。 - 其他的定义形式就是类比为少和陌生人说话 # :one:1.创建型模式(对象创建型模式) ==6个== 1. 创建型模式(Creational Pattern)对==类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离。== 2. 为了使软件的结构更加清晰,==外界对于这些对象只需要知道它们共同的接口,而不清楚其具体的实现细节,使整个系统的设计更加符合单一职责原则==。 3. 创建型模式在创建什么(What),由谁创建(Who),何时创建(When)等方面都为软件设计者提供了尽可能大的灵活性。 4. ==创建型模式隐藏了类的实例的创建细节,通过隐藏对象如何被创建和组合在一起达到使整个系统独立的目的。== 5. 其中的工厂类的模式分为三种:简单工厂,工厂方法,抽象工厂。工厂类模式解决的问题都是相同的。 ## :bamboo:1. 简单工厂模式(静态工厂方法模式) 1. ###### 三种角色: 抽象产品,具体产品,具体工厂 ![image-20210603000117772](https://gitee.com/lx201418/picRepository/raw/master/img/20210603000117.png) 2. **模式代码实现** - Product.java ```java public interface Product { void work(); } ``` - ProductA.java ```java public class ProductA implements Product{ @Override public void work() { System.out.println("产品A正在工作"); } } ``` - Product2.java ```java public class ProductB implements Product{ @Override public void work() { System.out.println("产品B正在工作"); } } ``` - Factory.java ``` public class Factory { public static Product makeProduct(Character param){ if('A' == param){ return new ProductA(); }else if('B' == param){ return new ProductB(); }else { System.out.println("警告!!!!该工厂不生产此种商品"); return null; } } } ``` - main.java ---使用工厂 ``` public class main { public static void main(String[] args) { System.out.println("-----第一个生产流程----"); Product product1 = Factory.makeProduct('B'); if(!Objects.equals(null,product1)){ product1.work(); } System.out.println("-----第二个生产流程----"); Product product2 = Factory.makeProduct('C'); if(!Objects.equals(null,product2)){ product2.work(); } System.out.println("-----第三个生产流程----"); Product product3 = Factory.makeProduct('A'); if(!Objects.equals(null,product3)){ product3.work(); } } } ``` - 执行结果 ![image-20210602231713075](https://gitee.com/lx201418/picRepository/raw/master/img/20210602231713.png) 3. **基本概念** 1. 简单工厂是为了解决简单的对象创建的问题,他解决的问题为:需要创建多个产品,这多个产品可能是属于一个类型(有相同的父类),这个模式通过提供一个工厂类解决创建**类型**数量不多的,有相同父类的对象. 2. :bell:需要注意的是,简单工厂的本质特征是使用一个工厂类创建多个对象。简单工厂的实现方式,可以是有多个方法来创建类。并不单单是指一个工厂只创建一个类型的,有共同接口的对象。:pushpin:有点疑惑,跟书上和其他材料讲的不一样,其他的材料中讲到一盒产品类对应一个工厂类。这个得琢磨琢磨。 3. 简单工厂模式的要点在于:当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节。简单工厂模式结构比较简单,其核心是工厂类的设计。**简单工厂模式提供了专门的工厂类用于创建对象,将对象的创建和对象的使用分离开。** 4. 定义一个工厂类,因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此==简单工厂模式又被称为静态工厂方法(Static Factory Method)模式==,==一个工厂创建多个产品类的实例。== 4. 优点 - **客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,** 再使用工厂类的时候,由工厂类提供判断逻辑对参数进行判断,决定创建并返回哪一个产品。而客户只需使用无需参与产品的生成,对于一些复杂的类名,通过简单工厂模式可以在一定程度减少使用者的记忆量。 5. 缺点 - 简单工厂模式最大的缺点是当有新产品要加入到系统中时,必须修改工厂类,需要在其中加入必要的业务逻辑,==这违背了“开闭原则”==。 - 在简单工厂模式中:所有的产品都由一个工厂创建,工厂的职责过重。 6. 适用场景 - 工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。 - 客户端只知道传入工厂类的参数,并关心返回的结果,对于如何创建对象并不关心。 ## 2. 工厂方法模式 - 工厂方法模式又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式或者多态工厂(Polymorphic Factory)模式。==工厂模式跟简单工厂的最大的区别就在于:工厂方法生产产品是通过使用不同的工厂而不是通过传递参数。== - 简单的理解就是一个工厂只生产一种产品。存在产品和工厂的一对一关系。 1. **四种角色:抽象产品,具体产品,抽象工厂,具体工厂** ![image-20210603000058380](https://gitee.com/lx201418/picRepository/raw/master/img/20210603000058.png) 2. 模式代码实现 Product.java ```java public interface Product { void work(); } ``` ProductA.java ```java public class ProductA implements Product { @Override public void work() { System.out.println("产品A正在工作"); } } ``` ProductB.java ```java public class ProductB implements Product{ @Override public void work() { System.out.println("产品B正在工作"); } } ``` Factory.java ```java public interface Factory { Product makeProduct(Character param); } ``` Factory1.java ```java public class Factory1 implements Factory { @Override public Product makeProduct(Character param) { if('A' == param){ return new ProductA(); }else{ System.out.println("\n------警告!工厂1暂不生产该产品-----"); return null; } } } ``` Factory2.java ```java public class Factory2 implements Factory { @Override public Product makeProduct(Character param) { if('B' == param){ return new ProductB(); }else{ System.out.println("\n------警告!工厂2暂不生产该产品-----"); return null; } } } ``` main.java ```java public class main { public static void main(String[] args) { System.out.println("****开始使用工厂1生成A类的产品****"); Factory factory1 = new Factory1(); Product productA = factory1.makeProduct('A'); if(!Objects.equals(null,productA)){ productA.work(); } Product productA1 = factory1.makeProduct('D'); if(!Objects.equals(null,productA1)){ productA1.work(); } System.out.println("\n****开始使用工厂2生成B类的产品****"); Factory factory2 = new Factory2(); Product productB = factory2.makeProduct('B'); if(!Objects.equals(null,productB)){ productB.work(); } Product productB1 = factory2.makeProduct('C'); if(!Objects.equals(null,productB1)){ productB1.work(); } System.out.println("生产使用过程结束" + ""); } } ``` 执行结果 ![image-20210603103844691](https://gitee.com/lx201418/picRepository/raw/master/img/20210603103844.png) 3. 基础知识 1. 工厂方法模式是为了解决简单工厂模式最大缺点,==需要创建新类型的对象时就得去修改工厂中创建实例对象的方法。==需要不断的去修改工厂类适应新的变化。在工厂方法模式中,==我们不再提供一个统一的工厂类来创建所有的产品对象==,而是针对不同的产品提供不同的工厂,**系统提供一个与产品等级结构对应的工厂等级结构**。==一个工厂负责一个产品类实例的创建。== 2. ==工厂方法模式是简单工厂模式的延伸,它继承了简单工厂模式的优点,同时还弥补了简单工厂模式的不足。==工厂方法模式是使用频率最高的设计模式之一,是很多开源框架和API类库的核心模式。 3. 与简单工厂模式相比,==工厂方法模式最重要的区别是引入了抽象工厂角色,抽象工厂可以是 接口,也可以是抽象类或者具体类==。**抽象工厂类是工厂方法模式的核心**,所有创建对象的工厂类都必须实现该接口。在抽象工厂类中,声明了工厂方法(Factory Method),用于返回一个 产品。 4. 优点 1. 在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。==这个核心类仅仅负责给出具体工厂必须实现的接口,而不负责哪一个产品类被实例化这种细节,这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。== 2. 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够让工厂可以自主确 定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,就正是因为所有的具体工厂类都具有同一抽象父类。 3. 使用工厂方法模式的另一个优点是在系统中加入新产品时,无须修改抽象工厂和抽象产品 提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了,这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。 5. 缺点 1. **工厂方法模式通过引入工厂等级结构**,==解决了简单工厂模式中工厂类职责太重的问题==,**但由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销。** 2. 由于考虑到系统的可扩展性,需要引入抽象层,==在客户端代码中均使用抽象层进行定义, 增加了系统的抽象性和理解难度==,且在实现时可能需要用到DOM、反射等技术,增加了系统 的实现难度。 6. 适用场景 1. 客户端不知道它所需要的对象的类。在工厂方法模式中,客户端不需要知道具体产品类的 类名,只需要知道所对应的工厂即可,==具体的产品对象由具体工厂类创建,可将具体工厂类的类名存储在配置文件或数据库中.== ## 3. 抽象工厂模式 - 首先理解概念:产品族和产品等级的关系 ![image-20210603132139470](https://gitee.com/lx201418/picRepository/raw/master/img/20210603132139.png) 1. **四种角色:抽象产品,具体产品,抽象工厂,具体工厂** ![image-20210603152939890](https://gitee.com/lx201418/picRepository/raw/master/img/20210603152940.png) 2. 模式代码实现 XiaomiProduct.java ```java public interface XiaomiProduct { } ``` HaierProduct.java ```java public interface HaierProduct { } ``` TV.java ```java public interface TV { void playVideo(); } ``` HaierTV.java ```java public class HaierTV implements TV,HaierProduct { @Override public void playVideo() { System.out.println("正在使用海尔电视播放大闹天宫。。。"); } } ``` XiaomiTV.java ```java public class XiaomiTV implements XiaomiProduct,TV{ @Override public void playVideo() { System.out.println("正在使用小米电视播放光头强。。。"); } } ``` Phone.java ```java public interface Phone { void callOther(); } ``` XiaomiPhone.java ```java public class XiaomiPhone implements Phone,XiaomiProduct{ @Override public void callOther() { System.out.println("正在使用小米手机打给。。。。。"); } } ``` HaierPhone.java ```java public class HaierPhone implements HaierProduct,Phone { @Override public void callOther() { System.out.println("正在使用海尔手机打给。。。。。。"); } } ``` Factory.java ```java public interface Factory { Phone makePhone(); TV makeTV(); } ``` XiaomiFactory.java ```java public class XiaomiFactory implements Factory { @Override public Phone makePhone() { return new XiaomiPhone(); } @Override public TV makeTV() { return new XiaomiTV(); } } ``` HaierFactory.java ```java public class HaierFactory implements Factory { @Override public Phone makePhone() { return new HaierPhone(); } @Override public TV makeTV() { return new HaierTV(); } } ``` main.java ```java public class main { public static void main(String[] args) { System.out.println("---海尔的工厂生产一台电视,看个动画片。。。"); HaierFactory haierFactory = new HaierFactory(); TV haierTV = haierFactory.makeTV(); if(haierTV != null){ haierTV.playVideo(); } System.out.println("---小米的工厂生产一台手机,打个电话试试。。。"); XiaomiFactory xiaomiFactory = new XiaomiFactory(); Phone xiaomiPone = new XiaomiPhone(); if(xiaomiPone != null){ xiaomiPone.callOther(); } } } ``` 运行截图 ![image-20210603155215641](https://gitee.com/lx201418/picRepository/raw/master/img/20210603155215.png) 3. 基础知识 1. ==抽象工厂模式为创建一组对象(一个产品族)提供了一种解决方案。与工厂方法模式相比,抽象工厂模式中的具体工厂不只是创建一种产品,它负责创建一族产品。== 2. 提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式。每一个具体工厂都提供了多个工厂方法用于产生多种不同类型的产品,这些产品构成了一个产品族。 4. 主要优点 - ==工厂方法的优点都是对客服隐藏了用户所需对象的实现细节,只返回客户需要的对象。创建过程对用户透明== - 增加新的产品族很方便,无须修改已有系统,符合“开闭原则”。 5. 主要缺点 - 增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码, 这显然会带来较大的不便,违背了“开闭原则”。这个也可以成为“开闭原则”的==倾斜性==。扩展产品族很方便,但是新增产品很复杂,需要对抽象工厂和工厂的实现类进行扩展。 6. 适用场景 - 系统中有多于一个的产品族,而每次只使用其中某一产品族。可以通过配置文件等方式来使得用户可以动态改变产品族,也可以很方便地增加新的产品族。 - 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。==同一个产品族中的产品可以是没有任何关系的对象,但是它们都具有一些共同的约束,如同一操作 系统下的按钮和文本框,按钮与文本框之间没有直接关系,但它们都是属于某一操作系统 的,此时具有一个共同的约束条件:操作系统的类型。== - 产品等级结构稳定,设计完成之后,不会向系统中增加新的产品等级结构或者删除已有的产品等级结构。 ![image-20210603161527784](https://gitee.com/lx201418/picRepository/raw/master/img/20210603161527.png) ## 4. 单例模式(确保对象的唯一性) 1. 单例模式是为了实现可以确保对象随时都可以被访问的全局变量,并且防止多次实例化产生多个实例,确保该类型实例唯一。实现的思路和过程为: 1. 将构造函数私有化 2. 通过静态方法获取一个唯一实例 3. 保证线程安全 4. 防止反序列化造成的新实例等。 2. 需要保证唯一的单例类: SingletonTargetObject.java ```java public class SingletonTargetObject { public static void work(){ System.out.println("单例对象正在工作。。。。"); } } ``` 3. 根据JVM加载类的逻辑实现单例 1. 静态属性只初始化一次 ==饿汉式== - 优点:线程安全 - 缺点:耗内存 ```java public class Method1 { private static SingletonTargetObject singletonTargetObject = new SingletonTargetObject(); public static SingletonTargetObject getSingletonTargetObject(){ return singletonTargetObject; } } ``` 2. 利用静态代码块进行初始化类加载过程中,静态代码块只执行一次 ==饿汉式== - 优点:线程安全 - 缺点:耗内存 ```java public class Method2 { private static SingletonTargetObject singletonTargetObject; static { singletonTargetObject = new SingletonTargetObject(); } public static void main(String[] args) { singletonTargetObject.work(); } } ``` 3. 静态内部类单例模式 - 我把这种方法称之为:beginner:静态内部类的静态实例 - ==静态内部类和非静态内部类一样,都不会因为外部类的加载而加载,同时静态内部类的加载不需要依附外部类,在使用时才加载,不过在加载静态内部类的过程中也会加载外部类== - 优点:线程安全、保证单例对象唯一性,同时也延迟了单例的实例化,避免了反射入侵 - 缺点:需要两个类去做到这一点,虽然不会创建静态内部类的对象,但是其 Class 对象还是会被创建,而且是属于永久代的对象。(综合来看,私以为这种方式是最好的单例模式) ```java public class Method3 { private static class innerClass{ private static SingletonTargetObject singletonTargetObject = new SingletonTargetObject(); } public static SingletonTargetObject getSingletonTargetObject(){ return innerClass.singletonTargetObject; } } ``` 4. 利用枚举的特性 - 每个枚举实例都是static final类型的,也就表明只能被实例化一次。在调用构造方法时,我们的单例被实例化。也就是说,因为enum中的实例被保证只会被实例化一次 - 优点:线程安全 - 缺点:枚举耗内存,能不用枚举就不用 ```java public enum Method4 { INSTANCE; private SingletonTargetObject singletonTargetObject; Method4(){ singletonTargetObject = new SingletonTargetObject(); } public SingletonTargetObject getSingletonObject(){ return singletonTargetObject; } } //调用方式 Method4.INSTANCE.getSingletonObject() ``` 1. 优缺点 - 优点:获取对象的速度快,线程安全(因为虚拟机保证只会装载一次,在装载类的时候是不会发生并发的) - 缺点:耗内存(若类中有静态方法,在调用静态方法的时候类就会被加载,类加载的时候就完成了单例的初始化,拖慢速度) 5. 使用双重测试锁(Double Check Lock(DCL)) - 优点:既能保证线程安全,且单例对象初始化后调用getInstance不进行同步锁,资源利用率高 - 缺点:第一次加载稍慢,由于Java内存模型一些原因偶尔会失败,在高并发环境下也有一定的缺陷,但概率很小。 ```java public class Method5 { private static SingletonTargetObject singletonTargetObject; public static SingletonTargetObject getSingletonTargetObject(){ if(singletonTargetObject == null){ synchronized(Method5.class){ //再判断一次是确保对象为null是才能创建对象过的实例 if (singletonTargetObject == null){ singletonTargetObject = new SingletonTargetObject(); } } } return singletonTargetObject; } } ``` 6. 使用容器实现单例模式 - 在程序的初始化,将多个单例类型注入到一个统一管理的类中,使用时通过key来获取对应类型的对象,==这种方式使得我们可以管理多种类型的单例,并且在使用时可以通过统一的接口进行操作。这种方式是利用了Map的key唯一性来保证单例。== 单例服务注册 ```java public class Method6 { private static Map contain = new HashMap<(); public static FlyWeight getFlyWeight(String key){ FlyWeight flyWeight = contain.get(key); if(flyWeight == null){ flyWeight = new ConcreteFlyWeight(key); contain.put(key,flyWeight); } return flyWeight; } } ``` FlyWeight.java ```java public interface FlyWeight { void operation(UnsharedComponent unsharedComponent); } ``` ConcreteFlyWeight.java ```java public class ConcreteFlyWeight implements FlyWeight { private String schoolName; public ConcreteFlyWeight(String key) { this.schoolName = key; System.out.println("key:"+key+"享元创建完成,"); } @Override public void operation(UnsharedComponent unsharedComponent) { System.out.println(schoolName+"的"+unsharedComponent.getName()+"--"+unsharedComponent.getToken()+"创建成功"); } } ``` UnsharedComponent.java ```java public class UnsharedComponent { private String token; private String name; public UnsharedComponent(String token,String name) { this.token = token; this.name = name; } public String getToken() { return token; } public void setToken(String token) { this.token = token; } public String getName() { return name; } public void setName(String name) { this.name = name; } } ``` main.java ```java public class main { public static void main(String[] args) { FlyWeight flyWeight1 = FlyWeightFactory.getFlyWeight("浙江大学"); flyWeight1.operation(new UnsharedComponent("爱吃饭","小马哥")); flyWeight1.operation(new UnsharedComponent("爱学习","大马哈")); FlyWeight flyWeight2=FlyWeightFactory.getFlyWeight("清华大学"); flyWeight2.operation(new UnsharedComponent("爱体育","跑步哥")); flyWeight2.operation(new UnsharedComponent("爱上课","学习哥")); } } ``` 运行结果: ![image-20210604210412532](https://gitee.com/lx201418/picRepository/raw/master/img/20210604210412.png) 3. 基础知识 1. 所谓的享元模式:就是把一个经常被创建的对象,按照属性的变化情况,把属性分为内部状态(有大量重复的),外部状态(经常变化的),然后按照内部状态创建对象称为享元(意为共享单元),并且预留一个接收外部状态的方法来实现完整的逻辑,并且存到容器中,然后将外部状态也组织成一个类型,在使用的过程中,将该外部对象传到享元的方法中,执行完整的逻辑。避免一个个生成对象,造成内存耗费巨大。 2. 享元模式,==第一个想到的应该就是池技术了,String常量池、数据库连接池、缓冲池等等都是享元模式的应用,所以说享元模式是池技术的重要实现方式。== 3. 享元模式(Flyweight Pattern):==运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。==由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,它是一种对象结构型模式 4. 所谓“享元”,顾名思义就是被共享的单元。==享元模式的意图是复用对象,节省内存,前提是享元对象是不可变对象。== 5. ==具体来讲,当一个系统中存在大量重复对象的时候,我们就可以利用享元模式,将对象设计成享元,在内存中只保留一份实例,供多处代码引用,这样可以减少内存中对象的数量,以起到节省内存的目的。实际上,不仅仅相同对象可以设计成享元,对于相似对象,我们也可以将这些对象中相同的部分(字段),提取出来设计成享元,让这些大量相似对象引用这些享元== 4. 优点 1. 享元模式的优点在于它可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份。 2. 享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。 5. 缺点 1. 享元模式使得系统更加复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化。 2. 为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。 6. 适用环境 1. 一个系统有大量相同或者相似的对象,由于这类对象的大量使用,造成内存的大量耗费。 2. 对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。 3. 使用享元模式需要维护一个存储享元对象的享元池,而这需要耗费资源,因此,应当在多次重复使用享元对象时才值得使用享元模式。 ## :star:7. 代理模式 1. 三个角色:抽象接口,实现接口的目标对象,代理对象 ![image-20210610092406937](https://gitee.com/lx201418/picRepository/raw/master/img/20210610092407.png) 2. 实现代码 Phone.java ```java public interface Phone { void playMusic(); } ``` XiaomiPhone.java ```java public class XiaomiPhone implements Phone { @Override public void playMusic() { System.out.println("打开小米手机的网易云放首歌!额,卡住了!"); } } ``` Proxy.java ```java public class Proxy implements Phone { private XiaomiPhone xiaomiPhone = new XiaomiPhone(); @Override public void playMusic() { xiaomiPhone.playMusic(); } } ``` main.java ```java public class main { public static void main(String[] args) { Proxy p = new Proxy(); p.playMusic(); } } ``` 运行结果: ![image-20210604212219538](https://gitee.com/lx201418/picRepository/raw/master/img/20210604212219.png) 3. 基本知识 1. :christmas_tree:代理模式重点不在于增强,而在于代替。 2. 代理模式是常用的结构型设计模式之一,当无法直接访问某个对象或访问某个对象存在困难 时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,所访问的真实对象与代理对象需要实现相同的接口。根据代理模式的使用目的不同,代理模式又可以分为多种类型,例如保护代理、远程代理、虚拟代理、缓冲代理等,它们应用于不同的场合,满足用户的不同需求。 3. 远程代理(Remote Proxy)是一种常用的代理模式,它使得客户端程序可以访问在远程主机上的 对象,远程主机可能具有更好的计算性能与处理速度,可以快速响应并处理客户端的请求。 远程代理可以将网络的细节隐藏起来,使得客户端不必考虑网络的存在。客户端完全可以认 为被代理的远程业务对象是在本地而不是在远程,而远程代理对象承担了大部分的网络通信工作,并负责对远程业务方法的调用。 4. 虚拟代理(Virtual Proxy)也是一种常用的代理模式,对于一些占用系统资源较多或者加载时间 较长的对象,可以给这些对象提供一个虚拟代理。在真实对象创建成功之前虚拟代理扮演真实对象的替身,而当真实对象创建之后,虚拟代理将用户的请求转发给真实对象 4. 优点 1. 代理模式能够协调调用者和被调用者,在一定程度上降低了系 统的耦合度。 2. 远程代理使得客户端可以访问在远程机器上的对象,远程机器 可能具有更好的计算性能与处理速度,可以快速响应并处理客户端请求。 3. 虚拟代理通过使用一个小对象来代表一个大对象,可以减少系 统资源的消耗,对系统进行优化并提高运行速度。 4. 保护代理可以控制对真实对象的使用权限。 5. 缺点 1. 由于在客户端和真实主题之间增加了代理对象,因此 有些类型的代理模式可能会造成请求的处理速度变慢。 2. 实现代理模式需要额外的工作,有些代理模式的实现 非常复杂。 6. 适用环境 1. 远程(Remote)代理:为一个位于不同的地址空间的对象提供一个本地 的代理对象,这个不同的地址空间可以是在同一台主机中,也可是在 另一台主机中,远程代理又叫做大使(Ambassador)。 2. 虚拟(Virtual)代理:如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。 3. Copy-on-Write代理:它是虚拟代理的一种,把复制(克隆)操作延迟 到只有在客户端真正需要时才执行。一般来说,对象的深克隆是一个 开销较大的操作,Copy-on-Write代理可以让这个操作延迟,只有对象被用到的时候才被克隆。 4. 保护(Protect or Access)代理:控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限。 5. 缓冲(Cache)代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。 6. 防火墙(Firewall)代理:保护目标不让恶意用户接近。 7. 同步化(Synchronization)代理:使几个用户能够同时使用一个对象而没有冲突。 8. 智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,如将此对象被调用的次数记录下来等。 # 3.行为型模式 ==11== 1. 行为型模式(Behavioral Pattern)是对在不同的对象之间划分责任和算法的抽象化。行为型模式不仅仅关注类和对象的结构,而且重点关注它们之间的相互作用。 ## 1. 职责链模式 1. 角色: 抽象处理者,具体处理者,处理链组装,封装请求和响应的Request和Response ![image-20210605144742531](https://gitee.com/lx201418/picRepository/raw/master/img/20210605144742.png) 2. 实现代码 LRequest.java ```java public class LRequest { private String token; public LRequest(String token) { this.token = token; } public String getToken() { return token; } public void setToken(String token) { this.token = token; } } ``` LResponse.java ```java public class LResponse { private String returnValue; public LResponse(String returnValue) { this.returnValue = returnValue; } public String getReturnValue() { return returnValue; } public void setReturnValue(String returnValue) { this.returnValue = returnValue; } } ``` Handler.java ```java public interface Handler { LResponse handler(LRequest request); } ``` ConcreteHandler.java ```java public class ConcreteHandler implements Handler { private String handlerName; public ConcreteHandler(String handlerName) { this.handlerName = handlerName; } @Override public LResponse handler(LRequest request) { System.out.println(handlerName+"正在处理得到的请求,获取到的请求的信息为"+request.getToken()); return new LResponse(handlerName+"处理完成"); } } ``` main.java --做责任链的组装 ```java public class main { private static java.util.List handlers =new ArrayList<>(); public static void main(String[] args) { Handler handler1 =new ConcreteHandler("责任人:1号领导"); Handler handler2 =new ConcreteHandler("责任人:2号领导"); Handler handler3 =new ConcreteHandler("责任人:3号领导"); //组装责任链 handlers.add(handler1); handlers.add(handler2); handlers.add(handler3); LRequest request = new LRequest("无敌的口令"); //链式处理 针对不同的业务需求 可以做不同业务处理 for(Handler handlerTmp : handlers){ System.out.println("-----"+handlerTmp.handler(request).getReturnValue()); } System.out.println("-----处理结束----"); } } ``` 运行结果: ![image-20210605152651640](https://gitee.com/lx201418/picRepository/raw/master/img/20210605152651.png) 3. 基本知识 1. 职责链模式定义如下:职责链模式(Chain of Responsibility Pattern):==避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。==职责链模式是一种对象行为型模式。 ==纯与不纯的职责链模式== - 职责链模式可分为纯的职责链模式和不纯的职责链模式两种: - (1) 纯的职责链模式 一个纯的职责链模式要求一个具体处理者对象只能在两个行为中选择一个:要么承担全部责 任,要么将责任推给下家,不允许出现某一个具体处理者对象在承担了一部分或全部责任后 又将责任向下传递的情况。而且在纯的职责链模式中,要求一个请求必须被某一个处理者对 象所接收,不能出现某个请求未被任何一个处理者对象处理的情况。在前面的采购单审批实 例中应用的是纯的职责链模式。 - (2)不纯的职责链模式 在一个不纯的职责链模式中允许某个请求被一个具体处理者部分处理后再向下传递,或者一 个具体处理者处理完某请求后其后继处理者可以继续处理该请求,而且一个请求可以最终不被任何处理者对象所接收。 2. 职责链模式通过建立一条链来组织请求的处理者,请求将沿着链进行传递,请求发送者无须知道请求在何时、何处以及如何被处理,实现了请求发送者与处理者的解耦。在软件开发中,==如果遇到有多个对象可以处理同一请求时可以应用职责链模式==,例如在Web应用开发中创 建一个过滤器(Filter)链来对请求数据进行过滤,在工作流系统中实现公文的分级审批等等,使用职责链模式可以较好地解决此类问题. 3. 实现方法: 1. 定义一个请求的处理抽象接口 2. 去实现处理请求的多个具体实现类,然后按照请求的顺序构建链式调用的处理规则。 ## :star:2. 策略模式 1. 角色:策略抽象接口,具体策略实现,执行环境(执行调用) ![image-20210605151502025](https://gitee.com/lx201418/picRepository/raw/master/img/20210605151502.png) 2. 实现代码 Strategy.java ```java public interface Strategy { void operation(String param); } ``` ConcreteStrategy1.java ```java public class ConcreteStrategy1 implements Strategy{ @Override public void operation(String paranm) { System.out.println("我用勺子吃"+paranm); } } ``` ConcreteStrategy2.java ```java public class ConcreteStrategy2 implements Strategy{ @Override public void operation(String param) { System.out.println("我用吸管喝"+param); } } ``` Context.java ```java public class Context { private Strategy strategy; public Context(Strategy strategy) { this.strategy = strategy; } public void operation(String param){ strategy.operation(param); } public Strategy getStrategy() { return strategy; } public void setStrategy(Strategy strategy) { this.strategy = strategy; } } ``` main.java ```java public class main { public static void main(String[] args) { System.out.println("----今天女朋友给我买了个西瓜"); String param1 = "西瓜"; Strategy strategy1 = new ConcreteStrategy1(); Context context = new Context(strategy1); context.operation(param1); System.out.println("----今天女朋友又给我买了一杯柠檬水"); String param2 = "奶茶"; Strategy strategy2 = new ConcreteStrategy2(); context.setStrategy(strategy2); context.operation(param2); } } ``` 3. 基础知识 1. 在策略模式中,==我们可以定义一些独立的类来封装不同的算法,每一个类封装一种具体的算法,在这里,每一个封装算法的类我们都可以称之为一种策略(Strategy)==,为了保证这些策略在使用时具有一致性,一般会提供一个抽象的策略类来做规则的定义,而每种算法则对应于一个具体策略类。 2. 策略模式的主要目的是将算法的定义与使用分开,也就是将算法的行为和环境分开,将算法的定义放在专门的策略类中,每一个策略类封装了一种实现算法,使用算法的环境类针对抽象策略类进行编程,符合“依赖倒转原则”。在出现新的算法时,只需要增加一个新的实现了抽象策略类的具体策略类即可。策略模式定义如下: 策略模式(Strategy Pattern):定义一系列算法类,将每一个算法封装起来,并让它们可以相互替换,策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。策略模式是一种对象行为型模式。 ## :star:3. 命令模式 1. 四个角色:命令接收者抽象,具体的命令接收者,调用者,命令接口,具体命令 ![image-20210610102411565](https://gitee.com/lx201418/picRepository/raw/master/img/20210610102411.png) 2. 实现代码 Receiver.java ```java public interface Receiver { void play(); void rewind(); void stop(); } ``` XiaomiPhoneReceiver.java ```java public class XiaomiPhoneReceiver implements Receiver { private String musicName ; public XiaomiPhoneReceiver(String musicName) { this.musicName = musicName; } @Override public void play() { System.out.println("小米手机开始播放:"+musicName); } @Override public void rewind() { System.out.println("小米手机回退一下了正在播放的曲目:"+musicName); } @Override public void stop() { System.out.println("小米手机停止播放:"+musicName); } } ``` Command.java ```java public interface Command { void execute(); } ``` WorkCommand.java ```java public class WorkCommand implements Command { private Receiver receiver; public WorkCommand() { this.receiver = new XiaomiPhoneReceiver("摘石榴"); } public WorkCommand(Receiver receiver) { this.receiver = receiver; } @Override public void execute() { receiver.play(); } public Receiver getReceiver() { return receiver; } public void setReceiver(Receiver receiver) { this.receiver = receiver; } } ``` RewindCommand.java ```java public class RewindCommand implements Command{ private Receiver receiver; public RewindCommand(){ this.receiver = new XiaomiPhoneReceiver("摘石榴"); } public RewindCommand(Receiver receiver) { this.receiver = receiver; } @Override public void execute() { receiver.rewind(); } } ``` StopCommand.java ```java public class StopCommand implements Command{ private Receiver receiver; public StopCommand() { this.receiver = new XiaomiPhoneReceiver("摘石榴"); } public StopCommand(Receiver receiver) { this.receiver = receiver; } @Override public void execute() { receiver.stop(); } public Receiver getReceiver() { return receiver; } public void setReceiver(Receiver receiver) { this.receiver = receiver; } } ``` XiaomiMusicAppInvoker.java ```java public class XiaomiMusicAppInvoker { private Command command; public XiaomiMusicAppInvoker() { } public XiaomiMusicAppInvoker(Command workCommand) { this.command = workCommand; } public void action(){ command.execute(); } public Command getCommand() { return command; } public void setCommand(Command command) { this.command = command; } } ``` main.java ```java public class main { public static void main(String[] args) { //依赖接收者 System.out.println("---------依赖接受者的代码------------"); Receiver xiaomiReceive = new XiaomiPhoneReceiver("摘石榴"); WorkCommand workCommand =new WorkCommand(xiaomiReceive); RewindCommand rewindCommand =new RewindCommand(xiaomiReceive); StopCommand stopCommand = new StopCommand(xiaomiReceive); System.out.println("--开始播放"); XiaomiMusicAppInvoker xiaomiMusicAppInvoker = new XiaomiMusicAppInvoker(workCommand); xiaomiMusicAppInvoker.action(); System.out.println("--倒带播放"); xiaomiMusicAppInvoker.setCommand(rewindCommand); xiaomiMusicAppInvoker.action(); xiaomiMusicAppInvoker.setCommand(stopCommand); xiaomiMusicAppInvoker.action(); System.out.println("-----不依赖接收者的代码,就是在具体命令对象里面,对接收者默认赋值-----"); WorkCommand workCommand1 = new WorkCommand(); RewindCommand rewindCommand1 = new RewindCommand(); StopCommand stopCommand1 = new StopCommand(); XiaomiMusicAppInvoker appInvoker2= new XiaomiMusicAppInvoker(); System.out.println("----开始播放"); appInvoker2.setCommand(workCommand1); appInvoker2.action(); System.out.println("----倒带播放"); appInvoker2.setCommand(rewindCommand1); appInvoker2.action(); System.out.println("----停止播放"); appInvoker2.setCommand(stopCommand1); appInvoker2.action(); } } ``` 运行结果: ![image-20210605152943907](https://gitee.com/lx201418/picRepository/raw/master/img/20210605152944.png) 3. 基本知识 1. 命令模式是对命令的封装。命令模式把发出命令的责任(由调用者)和执行命令的责任分隔开,委派给不同的对象。==本质上就是对接收者的业务处理使用一个命令对象做一个统一的封装==。每一个处理方法对应一个封装类。 2. 命令模式的前提是,已经有任务的执行者,就是接收者,接收者具体执行任务,命名对象不过是把执行的命令,封装成一个统一的接口。 3. 一个命令封装成一个命令对象,这就保证了命令对象调用的透明性,客户端只需要调用命令的execute()方法就可以了。系统的扩展性很强 4. 命令模式(Command Pattern):将一个请求封装为一个对象,从而让我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式。 5. 命令模式的核心在于引入了命令类,通过命令类来降低发送者和接收者的耦合度,请求发送者只需指定一个命令对象,再通过命令对象来调用请求接收者的处理方法。 6. 调用者是通过提供Command的设置入口,从而使invoker可以调用不同的接口。 ## :star:4. 观察者模式 1. 角色:被观察抽象,具体被观察者,观察者抽象,具体观察者 ![image-20210610102952854](https://gitee.com/lx201418/picRepository/raw/master/img/20210610102953.png) 2. 代码实现 Subject.java ```java public interface Subject { void addObserver(Observer observer); void removeObserver(Observer observer); void notifyAllObs(); void operation(); } ``` ConcreteSubject.java ```java public class ConcreteSubject implements Subject{ private ArrayList observers =new ArrayList<>(); @Override public void addObserver(Observer observer) { observers.add(observer); } @Override public void removeObserver(Observer observer) { observers.remove(observer); } @Override public void notifyAllObs() { for(Observer observer1 : observers){ observer1.operation(); } } @Override public void operation() { System.out.println("杭州观察站报告!最近温度非常高!太热了"); notifyAllObs(); } } ``` Observer.java ```java public interface Observer { void operation(); } ``` Observer1.java ```java public class Observer1 implements designModel.L18Observer.Observer { @Override public void operation() { System.out.println("上海观察站收到!"); } } ``` Observer2.java ```java +++++++++++++++++++++ public class Observer2 implements designModel.L18Observer.Observer { @Override public void operation() { System.out.println("南京观察站收到!"); } } ``` main.java ```java public class main { public static void main(String[] args) { Subject subject = new ConcreteSubject(); subject.addObserver(new Observer1()); subject.addObserver(new Observer2()); subject.operation(); } } ``` 3. 基本知识 1. 观察者模式是使用频率最高的设计模式之一,==它用于建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应作出反应。==在观察者模式中,==发生改变的对象称为观察目标,而被通知的对象称为观察者==。 2. 一个观察目标可以对应多个观察者,而且这些观察者之间可以没有任何相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展。 3. 观察者模式定义如下:定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式的别名包括发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。观察者模式是一种对象行为型模式。 4. 观察者和被观察者的定义可以属于相同的类型也可以属于不同的类型。 ## 5. 解释器模式 1. 角色: 上下文,解析器抽象,终结符解析器,非终结符解析器,客户端 ![image-20210605171042148](https://gitee.com/lx201418/picRepository/raw/master/img/20210605171042.png) 2. 基本知识 1. 解释器模式描述了如何为简单的语言定义一个文法,如何在该语言中表示一个句子,以及如 何解释这些句子。 ## 6. 迭代器模式 1. 角色:集合对象(聚合对象)接口,具体集合,迭代器接口,具体迭代器 ![image-20210605172006261](https://gitee.com/lx201418/picRepository/raw/master/img/20210605172006.png) 2. 这个太常见了,代码略 3. 基本知识 1. 迭代器模式(Iterator Pattern):提供一种方法来访问聚合对象,而不用暴露这个对象的内部表 示,其别名为游标(Cursor)。迭代器模式是一种对象行为型模式。 ## 7. 中介者模式 1. 角色:抽象中介者,具体中介者,交互对象抽象,具体交互对象的实现 ![image-20210605175539485](https://gitee.com/lx201418/picRepository/raw/master/img/20210605175539.png) 2. 代码 Meditor.java ```java public abstract class Meditor { ArrayList colleagueArrayList = new ArrayList<>(); public void addColleagur(Colleague colleague){ colleagueArrayList.add(colleague); } public abstract void cowork(Colleague colleague); } ``` ConcreteMeditor.java ```java public class ConcreteMeditor extends Meditor{ @Override public void cowork(Colleague colleague) { for(Colleague colleague1 : colleagueArrayList){ if(!colleague1.equals(colleague)){ colleague1.selfwork(); } } } } ``` Colleague.java ```java public interface Colleague { void selfwork(); void cowork(); } ``` ConcreteColleague1.java ```java public class ConcreteColleague1 implements Colleague{ private Meditor meditor; private String name; public ConcreteColleague1(Meditor meditor,String name) { this.meditor = meditor; this.name = name; } @Override public void selfwork() { System.out.println(name+"正在完成其他同时委托的工作中。。。。。。"); } @Override public void cowork() { System.out.println(name+"已经发出消息"); meditor.cowork(this); } } ``` ConcreteColleague2.java ```java public class ConcreteColleague2 implements Colleague { private String name; private Meditor meditor; public ConcreteColleague2(Meditor meditor,String name) { this.meditor = meditor; this.name = name; } @Override public void selfwork() { System.out.println("我是无敌的另一类同事,正在完成交代过来的任务"+name); } @Override public void cowork() { System.out.println(name+"需要别的同学协助工作"); meditor.cowork(this); } } ``` main.java ```java public class main { public static void main(String[] args) { Meditor meditor =new ConcreteMeditor(); ConcreteColleague1 concreteColleague1 =new ConcreteColleague1(meditor,"杭州的同学"); ConcreteColleague2 concreteColleague2 = new ConcreteColleague2(meditor,"台湾的同学"); meditor.addColleagur(concreteColleague1); meditor.addColleagur(concreteColleague2); //同事1需要中介者完成交互 concreteColleague1.cowork(); System.out.println("-------"); //同事2需要中介者完成交互 concreteColleague2.cowork(); } ``` 运行图片 ![image-20210605195319857](https://gitee.com/lx201418/picRepository/raw/master/img/20210605195320.png) 3. 基本知识 1. 中介者模式(Mediator Pattern):用一个中介对象(中介者)来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式又称为调停者模式,它是一种对象行为型模式。 ## 8. 备忘录模式 1. 角色:原发者,备忘录对象,备忘录存储 ![image-20210605200454379](https://gitee.com/lx201418/picRepository/raw/master/img/20210605200454.png) 2. 代码 Originator.java ```java public class Originator { public int state; public Originator(int state) { this.state = state; restore(); } public int getState() { return state; } public void setState(int state) { restore(); this.state = state; } public void restore(){ MementoTaker.setMemento(createMemento()); } public void undo(){ state = MementoTaker.getMemento().getState(); } public Memento createMemento(){ return new Memento(state); } @Override public String toString() { return "现在的原发器的状态值为:{" + "state=" + state + '}'; } } ``` Memento.java ```java public class Memento { private int state; public Memento(int state) { this.state = state; } public int getState() { return state; } } ``` MementoTaker.java ```java public class MementoTaker { private static Memento memento; public static void setMemento(Memento memento1) { memento = memento1; } public static Memento getMemento(){ return memento; } } ``` main.java ```java public class main { public static void main(String[] args) { Originator originator = new Originator(12); System.out.println("-----开始测试备忘录----"); originator.setState(88); originator.setState(99); System.out.println("恢复前"+originator); originator.undo(); System.out.println(originator); } } ``` 运行结果: ![image-20210605202437488](https://gitee.com/lx201418/picRepository/raw/master/img/20210605202437.png) 3. 基本知识: 1. 备忘录模式(Memento Pattern):在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。它是一种对象行为型模式,其别名为Token。 2. 状态保存可以保存最新的状态,也可以使用列表记录多次的状态,恢复的时候使用游标来进行位置标定。 ## 9. 状态模式 1. 角色:上下文环境,状态抽象接口,状态实现类。 ![image-20210605210715594](https://gitee.com/lx201418/picRepository/raw/master/img/20210605210716.png) 2. 实现代码 State.java ```java public interface State { void handler(); } ``` ConcreteState1.java ```java public class ConcreteState1 implements State{ @Override public void handler() { System.out.println("状态1开始干活"); } } ``` ConcreteState2.java ```java public class ConcreteState2 implements State { @Override public void handler() { System.out.println("状态2开始工作"); } } ``` Context.java ```java public class Context { private State state; public Context() { } public State getState() { return state; } public void setState(State state) { this.state = state; } public void handler(int param){ if(1 == param){ if(!(state instanceof ConcreteState1)){ setState(new ConcreteState1()); } }else{ if(!(state instanceof ConcreteState2)){ setState(new ConcreteState2()); } } state.handler(); } } ``` main.java ```java public class main { public static void main(String[] args) { Context context = new Context(); context.handler(1); System.out.println("状态发生改变了"); context.handler(2); } } ``` 运行结果 ![image-20210605211437342](https://gitee.com/lx201418/picRepository/raw/master/img/20210605211437.png) 3. 基础知识 1. 状态模式(State Pattern):允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修 改了它的类。其别名为状态对象(Objects for States),状态模式是一种对象行为型模式。 ## 10. 模版方法模式 1. 角色:模版方法,具体实现方法 ![image-20210605212141106](https://gitee.com/lx201418/picRepository/raw/master/img/20210605212141.png) 2. 实现代码 AbstractClass.java ```java public abstract class AbstractClass { public abstract void start(); public abstract void whenDoing(); public abstract void finish(); public void templateMethod(){ start(); whenDoing(); finish(); } } ``` ConcreteClass1.java ```java public class ConcreteClass1 extends AbstractClass { @Override public void start() { System.out.println("我先把香蕉的皮剥了"); } @Override public void whenDoing() { System.out.println("我把香蕉切成块,一块一块吃"); } @Override public void finish() { System.out.println("吃完后把香蕉皮扔了"); } } ``` ConcreteClass2.java ```java public class ConcreteClass2 extends AbstractClass { @Override public void start() { System.out.println("我先准备好碗筷,还有下饭菜"); } @Override public void whenDoing() { System.out.println("我把饭菜都盛好!开始吃饭"); } @Override public void finish() { System.out.println("吃完饭了,我把碗筷洗好放到柜子里"); } } ``` main.java ```java public class main { public static void main(String[] args) { AbstractClass abstractClass1 =new ConcreteClass1(); AbstractClass abstractClass2 = new ConcreteClass2(); System.out.println("-----开始吃香蕉"); abstractClass1.templateMethod(); System.out.println("-----开始吃蛋炒饭"); abstractClass2.templateMethod(); } } ``` 运行结果: ![image-20210605212959790](https://gitee.com/lx201418/picRepository/raw/master/img/20210605213000.png) 3. 基础知识 1. 模板方法模式是结构最简单的行为型设计模式,在其结构中只存在父类与子类之间的继承关 系。通过使用模板方法模式,可以将一些复杂流程的实现步骤封装在一系列基本方法中,在 抽象父类中提供一个称之为模板方法的方法来定义这些基本方法的执行次序,而通过其子类 来覆盖某些步骤,从而使得相同的算法框架可以有不同的执行结果。模板方法模式提供了一 个模板方法来定义算法框架,而某些具体步骤的实现可以在其子类中完成。 ## 11. 访问者模式 1. 角色:抽象访问者,具体访问者,对象结构元素(存储),抽象元素,具体元素 ![image-20210605234717216](https://gitee.com/lx201418/picRepository/raw/master/img/20210605234717.png) 2. 实现代码 Element.java ```java public interface Element { void accept(Visitor visitor); } ``` ConcreteElement1.java ```java public class ConcreteElement1 implements Element { private String name; public ConcreteElement1(String name) { this.name = name; } @Override public void accept(Visitor visitor) { visitor.check(this); } public void welcomeVisitor1(){ System.out.println(">食堂厨师:"+name+"---欢迎大领导检查,最近伙食保障的非常好,大家都吃的很开心,也很便宜"); } public void welcomeVisitor2(){ System.out.println("<食堂厨师:"+name+"欢迎尧老板检查,食堂最近效益不错,而且投诉率也下降了"); } } ``` ConcreteElement2.java ```java public class ConcreteElement2 implements Element { private String name; public ConcreteElement2(String name) { this.name = name; } @Override public void accept(Visitor visitor) { visitor.check(this); } public void welcomeVisitor3(){ System.out.println("--程序员"+name+"欢迎大领导检查,我最近干活非常不错"); } public void welcomeVisitor4(){ System.out.println("++程序员"+name+"欢迎尧老板检查,我最近一直在加强产出"); } } ``` Visitor.java ```java public interface Visitor { void check(ConcreteElement1 concreteElement1); void check(ConcreteElement2 concreteElement2); } ``` ConcreteVisitor1.java ```java public class ConcreteVisitor1 implements Visitor { @Override public void check(ConcreteElement1 concreteElement1) { concreteElement1.welcomeVisitor1(); } @Override public void check(ConcreteElement2 concreteElement2) { concreteElement2.welcomeVisitor3(); } } ``` ConcreteVisitor2.java ```java public class ConcreteVisitor2 implements Visitor{ @Override public void check(ConcreteElement1 concreteElement1) { concreteElement1.welcomeVisitor2(); } @Override public void check(ConcreteElement2 concreteElement2) { concreteElement2.welcomeVisitor4(); } } ``` ObjectStruct.ajva ```java public class ObjectStruct { private ArrayList elements = new ArrayList<>(); public void addElement(Element element) { elements.add(element); } public void removeElement(Element element){ elements.remove(element); } public void welcomeVisitor(Visitor visitor){ elements.forEach(element -> element.accept(visitor)); } } ``` main.java ```java public class main { public static void main(String[] args) { ObjectStruct objectStruct =new ObjectStruct(); objectStruct.addElement(new ConcreteElement1("大熊猫")); objectStruct.addElement(new ConcreteElement1("树袋熊")); objectStruct.addElement(new ConcreteElement2("考拉")); objectStruct.addElement(new ConcreteElement2("大狗熊")); System.out.println("=======大领导来视察了======="); objectStruct.welcomeVisitor(new ConcreteVisitor1()); System.out.println("========区域经理来视察啦====="); objectStruct.welcomeVisitor(new ConcreteVisitor2()); } } ``` 运行结果 ![image-20210605234616229](https://gitee.com/lx201418/picRepository/raw/master/img/20210605234616.png) 3. 基础知识 1. 访问者模式(Visitor Pattern):提供一个作用于某对象结构中的各元素的操作表示,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式是一种对象行为型模式。 2. 访问者模式,就是设置访问者的角色,来完成,需要对一个集合对象中不同的类型完成不同的操作,而且把操作和对象集合进行解耦,使用外部对象来完成操作。有点抽象,得多写代码体会这些设计模式的深层次的指导意义。 3. ![image-20210605235513304](https://gitee.com/lx201418/picRepository/raw/master/img/20210605235513.png)