该文档为在个人学习过程中的学习笔记,主要参照的资料为:
- 设计模式java: 项目github地址 阅读地址
- 图说设计模式: 项目github地址 阅读地址
- 学习书籍: 《设计模式:可复用面向对象软件的基础》
:innocent:学习方法
-
先理论,再实践
-
学习这门课的目的:在学习设计模式的过程中,学习一些常见问题的最优解决方案,有助于提升自己在代码编写和系统设计上的能力,让自己写出更高的代码,也能够提升自己对于工程系统的认识。
-
学习的过程为:先了解并掌握设计模式的基础理论知识和核心概念,然后设计UML类图,最后对照UML类图编写模式的代码。
-
设计模式的基础理论包括:学科基础导论,核心内容部分。其中核心内容部分分为两部分来看,一部分是设计原则,一部分是设计模式。设计原则是为了构建更加高效,可扩展,高可用的系统的指导思想。设计模式的实现是为了遵循或者达到设计原则的要求而提出的解决方案。
-
学习过程使用到的工具有:
-
IDEA ---编写java代码
-
draw.io ---制作UML类图有离线版和在线版。
-
Typora ---用来编辑文档
-
Snipaste ---用来截图
-
:fire:2.杂项导言
-
在软件工程领域,设计模式是一套通用的可复用的解决方案,用来解决在软件设计过程中产生的通用问题。==它不是一个可以直接转换成源代码的设计,只是一套在软件系统设计过程中程序员应该遵循的最佳实践准则==。 ==官方定义==
-
设计模式就是在构建系统工程的时候对于解决一些特定问题的最佳实践。设计模式的角色类似于==系统代码构建指南或者系统构建的解决方案==。学好设计模式有助于系统设计过程中代码组织的有效性和合理性。
-
24种设计模式是GOF的23种设计模式加上简单工厂模式。设计模式不只有这24种,还有更多的用于解决更高级复杂的问题的模式方法。所以在学习的时候,不能局限的认为这几种设计模式就是整个设计模式的全部。而是应该去学习设计模式的设计思想,然后在遇到特定问题的时候使用设计模式去解决问题。
-
==不要滥用设计模式。==
-
设计模式学习的整体划分--按照解决的问题分为三个大类
- 构建型(类的创建): 用于解决对象创建的问题,
- 结构型(代码的结构层次): 用于解决系统的结构设计
- 行为型: 用于解决儿功能角色的设计
-
学习设计模式的基础课程
- UML类图和时序图
- 面向对象语言
:heart_eyes:3.UML类图和时序图基础
- 学习工具-draw.io
- UML:统一建模语言,常见的可建模的图分为:时序图,用例图,活动图,组件图,类图。
1.类图之类或接口符号
2. 类图之类关系标识符号
- 关联关系默认不强调方向,表示对象间相互知道;如果特别强调方向,使用单向箭头标识A-B,表示A依赖B但B不依赖A.
- 关联关系强调一种拥有关系,而依赖这强调的是一种使用关系。
3.时序图
- 时序图(Sequence Diagram)用来表示对象之间传递消息的时间顺序,它用来表示用例的行为顺序。==时序图中显示的是参与交互的对象及其对象之间消息交互的顺序。==
- 我们在画时序图时会涉及7种元素:角色(Actor)、对象(Object)、生命线(LifeLine)、控制焦点(Activation)、消息(Message)、自关联消息、组合片段。其中前6种是比较常用和重要的元素,剩余的一种组合片段元素不是很常用
3.1 系统角色(Actor)
-
系统角色,可以是人或者其他系统,子系统。表示系统的用户,或者事件的触发者。使用方式跟对象相同,有自己的生命线。作为事件按照时间顺序的发起者或者执行者。
3.2 对象(Object)
-
对象位于时序图的顶部,以一个矩形表示,对象的命名方式为
- 对象名:类名
- 对象名
- 类名
3.3 生命线(LifeLine)
-
用一条垂直的虚线表示来表示对象的生命周期,从创建到消亡,顺序为由上而下。
3.4 控制焦点(Activation)
-
控制焦点代表对象在生命线上某段时期执行的操作,在该期间,对象处于激活状态,需要执行任务,其他时间对象出于休眠状态。==有时候称为对象激活期==。以一个竖直的窄矩形表示。矩阵的高度表示该激活时期的长短,从高处开始,到低处结束。
3.5 消息(Message)
表示对象之间进行信息交互。按照类型分有3种消息。
-
同步消息(Synchronous Message)
- 消息的发送者把控制传递给消息的接收者,然后停止活动,等待消息的接收者放弃或者返回控制。用来表示同步的意义。以一条实线+实心箭头表示。
-
异步消息(Asynchronous Message)
- 消息发送者通过消息把信号传递给消息的接收者,然后继续自己的活动,不等待接受者返回消息或者控制。异步消息的接收者和发送者是并发工作的。以一条实线+大于号表示。
-
返回消息(Return Message)
- 返回消息表示从过程调用返回。以小于号+虚线表示。
3.6 自关联消息
-
表示方法的自身调用或者一个对象内的一个方法调用另外一个方法。以一个半闭合的长方形+下方实心箭头表示。
-
==消息为对象之间的信息传递或者交互,自关联消息可以理解为对象自己跟自己交互。==
3.7 组合片段
- 组合片段用来解决交互执行的条件和方式,它允许在序列图中直接表示逻辑组件,用于通过指定条件或子进程的应用区域,为任何生命线的任何部分定义特殊条件和子进程。
- ==简单理解就是用来表示程序执行逻辑的符号==。
3.8 简单的时序图示例
4.开篇:7大设计原则
- 这个是系统设计的指导思想,
:star2:1. 开闭原则
-
一个软件实体应当对扩展开放,对修改关闭。==即实体应尽量在不修改原有代码的情况下进行扩展。==
-
开闭原则是面向对象设计的目标
:star2:2. 单一职责原则
-
单一职责原则是最简单的面向对象设计原则,它用于控制类的粒度大小。
-
单一职责原则定义如下: 单一职责原则(Single Responsibility Principle, SRP):==一个类只负责一个功能领域中的相应职责==,或者可以定义为:==就一个类而言,应该只有一个引起它变化的原因==。
-
单一职责原则告诉我们:==个类不能太“累”!在软件系统中,一个类(大到模块,小到方法)承担的职责越多,它被复用的可能性就越小,而且一个类承担的职责过多,就相当于将这些职责耦合在一起,当其中一个职责变化时,可能会影响其他职责的运作,因此要将这些职责进行分离,将不同的职责封装在不同的类中,即将不同的变化原因封装在不同的类中,如果多个职责总是同时发生改变则可将它们封装在同一类中。单一职责原则是实现高内聚、低耦合的指导方针,它是最简单但又最难运用的原则,需要设计人员发现类的不同职责并将其分离。==
3. 里氏替换原则
- 所有引用基类(父类)的地方必须能透明地使用其子类的对象。超类的引用指向子类的实例.
:boom:4. 依赖倒转原则
-
依赖倒转原则就是面向对象设计的主要实现机制之一,它是系统抽象化的具体实现.
-
依赖倒转原则要求==我们在程序代码中传递参数时或在关联关系中,尽量引用层次高的抽象层类==,即使用接口和抽象类进行变量类型声明、参数类型声明、方法返回类型声明,以及数据类型的转换等,而不要用具体类来做这些事情。为了确保该原则的应用,一个具体类应当只实现接口或抽象类中声明过的方法,而不要给出多余的方法,否则将无法调用到在子类中增加的新方法。
- 模块间的依赖通过抽象发生,==实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的==
- 接口或抽象类不依赖于实现类
- 实现类依赖于接口或抽象类
5. 接口隔离原则
- 接口隔离原则(Interface Segregation Principle, ISP):使用多个专门的接口,而不使用单一的总接口,即==客户端不应该依赖那些它不需要的接口==。
- 当一个接口太大时,==我们需要将它分割成一些更细小的接口,使用该接口的客户端仅需知道与之相关的方法即可。==每一个接口应该承担一种相对独立的角色,不干不该干的事,该干的事都要干。这里的“接口”往往有两种不同的含义:==一种是指一个类型所具有的方法特征的集合,仅仅是一种逻辑上的抽象;==另外一种是指某种语言具体的“接口”定义,有严格的定义和结构,比如Java语言中的interface。
:blush:6. 合成复用原则
-
合成复用原则就是在一个新的对象里通过关联关系(包括组合关系和聚合关系)来使用一些已有的对象,使之成为新对象的一部分;新对象通过委派调用已有对象的方法达到复用功能的目的。简言之:==复用时要尽量使用组合/聚合关系(关联关系),少用继承。==
-
类之间的关系:
-
关联:一个类的实例是另一个类的成员变量
-
关联关系包含:组合和聚合。
-
关联关系在实现上都是使用其他的类作为属性实现的,强调一种整体与部分的组合关系。
-
组合关系:概念上强调的是:部分不能脱离整体而存在,A类的构造方法里创建B类的对象;描述的是整体与部分的关系。整体和部分的生命周期相同,同一时刻产生,同一时刻消亡。
-
聚合关系:概念上强调的是: 脱离了整体,部分依然可以有意义。整体与部分存在同生命周期的概念。在代码的实现上:A类的对象在创建时不会立即创建B类的对象(在构造器中不创建B对象),而是等待一个外界的对象传给它;描述的是整体与个人的关系。
-
-
依赖关系:==一般指由局部变量、函数参数,函数调用、返回值建立的对于其他对象的调用关系==。
-
继承关系(泛化的一种)
-
实现关系
-
:fire:7. 迪米特法则
- 一个软件实体应当尽可能少地与其他实体发生相互作用。
- 其他的定义形式就是类比为少和陌生人说话
:one:1.创建型模式(对象创建型模式) ==6个==
- 创建型模式(Creational Pattern)对==类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离。==
- 为了使软件的结构更加清晰,==外界对于这些对象只需要知道它们共同的接口,而不清楚其具体的实现细节,使整个系统的设计更加符合单一职责原则==。
- 创建型模式在创建什么(What),由谁创建(Who),何时创建(When)等方面都为软件设计者提供了尽可能大的灵活性。
- ==创建型模式隐藏了类的实例的创建细节,通过隐藏对象如何被创建和组合在一起达到使整个系统独立的目的。==
- 其中的工厂类的模式分为三种:简单工厂,工厂方法,抽象工厂。工厂类模式解决的问题都是相同的。
:bamboo:1. 简单工厂模式(静态工厂方法模式)
-
三种角色: 抽象产品,具体产品,具体工厂
-
模式代码实现
- Product.java
public interface Product { void work(); }
- ProductA.java
public class ProductA implements Product{ @Override public void work() { System.out.println("产品A正在工作"); } }
- Product2.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(); } } }
- 执行结果
-
基本概念
- 简单工厂是为了解决简单的对象创建的问题,他解决的问题为:需要创建多个产品,这多个产品可能是属于一个类型(有相同的父类),这个模式通过提供一个工厂类解决创建类型数量不多的,有相同父类的对象.
- :bell:需要注意的是,简单工厂的本质特征是使用一个工厂类创建多个对象。简单工厂的实现方式,可以是有多个方法来创建类。并不单单是指一个工厂只创建一个类型的,有共同接口的对象。:pushpin:有点疑惑,跟书上和其他材料讲的不一样,其他的材料中讲到一盒产品类对应一个工厂类。这个得琢磨琢磨。
- 简单工厂模式的要点在于:当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节。简单工厂模式结构比较简单,其核心是工厂类的设计。简单工厂模式提供了专门的工厂类用于创建对象,将对象的创建和对象的使用分离开。
- 定义一个工厂类,因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此==简单工厂模式又被称为静态工厂方法(Static Factory Method)模式==,==一个工厂创建多个产品类的实例。==
-
优点
- 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可, 再使用工厂类的时候,由工厂类提供判断逻辑对参数进行判断,决定创建并返回哪一个产品。而客户只需使用无需参与产品的生成,对于一些复杂的类名,通过简单工厂模式可以在一定程度减少使用者的记忆量。
-
缺点
- 简单工厂模式最大的缺点是当有新产品要加入到系统中时,必须修改工厂类,需要在其中加入必要的业务逻辑,==这违背了“开闭原则”==。
- 在简单工厂模式中:所有的产品都由一个工厂创建,工厂的职责过重。
-
适用场景
- 工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
- 客户端只知道传入工厂类的参数,并关心返回的结果,对于如何创建对象并不关心。
2. 工厂方法模式
- 工厂方法模式又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式或者多态工厂(Polymorphic Factory)模式。==工厂模式跟简单工厂的最大的区别就在于:工厂方法生产产品是通过使用不同的工厂而不是通过传递参数。==
- 简单的理解就是一个工厂只生产一种产品。存在产品和工厂的一对一关系。
-
四种角色:抽象产品,具体产品,抽象工厂,具体工厂
-
模式代码实现
Product.java
public interface Product { void work(); }
ProductA.java
public class ProductA implements Product { @Override public void work() { System.out.println("产品A正在工作"); } }
ProductB.java
public class ProductB implements Product{ @Override public void work() { System.out.println("产品B正在工作"); } }
Factory.java
public interface Factory { Product makeProduct(Character param); }
Factory1.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
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
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("生产使用过程结束" + ""); } }
执行结果
-
基础知识
- 工厂方法模式是为了解决简单工厂模式最大缺点,==需要创建新类型的对象时就得去修改工厂中创建实例对象的方法。==需要不断的去修改工厂类适应新的变化。在工厂方法模式中,==我们不再提供一个统一的工厂类来创建所有的产品对象==,而是针对不同的产品提供不同的工厂,系统提供一个与产品等级结构对应的工厂等级结构。==一个工厂负责一个产品类实例的创建。==
- ==工厂方法模式是简单工厂模式的延伸,它继承了简单工厂模式的优点,同时还弥补了简单工厂模式的不足。==工厂方法模式是使用频率最高的设计模式之一,是很多开源框架和API类库的核心模式。
- 与简单工厂模式相比,==工厂方法模式最重要的区别是引入了抽象工厂角色,抽象工厂可以是 接口,也可以是抽象类或者具体类==。抽象工厂类是工厂方法模式的核心,所有创建对象的工厂类都必须实现该接口。在抽象工厂类中,声明了工厂方法(Factory Method),用于返回一个 产品。
-
优点
- 在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。==这个核心类仅仅负责给出具体工厂必须实现的接口,而不负责哪一个产品类被实例化这种细节,这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。==
- 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够让工厂可以自主确 定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,就正是因为所有的具体工厂类都具有同一抽象父类。
- 使用工厂方法模式的另一个优点是在系统中加入新产品时,无须修改抽象工厂和抽象产品 提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了,这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。
-
缺点
- 工厂方法模式通过引入工厂等级结构,==解决了简单工厂模式中工厂类职责太重的问题==,但由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销。
- 由于考虑到系统的可扩展性,需要引入抽象层,==在客户端代码中均使用抽象层进行定义, 增加了系统的抽象性和理解难度==,且在实现时可能需要用到DOM、反射等技术,增加了系统 的实现难度。
-
适用场景
- 客户端不知道它所需要的对象的类。在工厂方法模式中,客户端不需要知道具体产品类的 类名,只需要知道所对应的工厂即可,==具体的产品对象由具体工厂类创建,可将具体工厂类的类名存储在配置文件或数据库中.==
3. 抽象工厂模式
- 首先理解概念:产品族和产品等级的关系
-
四种角色:抽象产品,具体产品,抽象工厂,具体工厂
-
模式代码实现
XiaomiProduct.java
public interface XiaomiProduct { }
HaierProduct.java
public interface HaierProduct { }
TV.java
public interface TV { void playVideo(); }
HaierTV.java
public class HaierTV implements TV,HaierProduct { @Override public void playVideo() { System.out.println("正在使用海尔电视播放大闹天宫。。。"); } }
XiaomiTV.java
public class XiaomiTV implements XiaomiProduct,TV{ @Override public void playVideo() { System.out.println("正在使用小米电视播放光头强。。。"); } }
Phone.java
public interface Phone { void callOther(); }
XiaomiPhone.java
public class XiaomiPhone implements Phone,XiaomiProduct{ @Override public void callOther() { System.out.println("正在使用小米手机打给。。。。。"); } }
HaierPhone.java
public class HaierPhone implements HaierProduct,Phone { @Override public void callOther() { System.out.println("正在使用海尔手机打给。。。。。。"); } }
Factory.java
public interface Factory { Phone makePhone(); TV makeTV(); }
XiaomiFactory.java
public class XiaomiFactory implements Factory { @Override public Phone makePhone() { return new XiaomiPhone(); } @Override public TV makeTV() { return new XiaomiTV(); } }
HaierFactory.java
public class HaierFactory implements Factory { @Override public Phone makePhone() { return new HaierPhone(); } @Override public TV makeTV() { return new HaierTV(); } }
main.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(); } } }
运行截图
-
基础知识
- ==抽象工厂模式为创建一组对象(一个产品族)提供了一种解决方案。与工厂方法模式相比,抽象工厂模式中的具体工厂不只是创建一种产品,它负责创建一族产品。==
- 提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式。每一个具体工厂都提供了多个工厂方法用于产生多种不同类型的产品,这些产品构成了一个产品族。
-
主要优点
- ==工厂方法的优点都是对客服隐藏了用户所需对象的实现细节,只返回客户需要的对象。创建过程对用户透明==
- 增加新的产品族很方便,无须修改已有系统,符合“开闭原则”。
-
主要缺点
- 增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码, 这显然会带来较大的不便,违背了“开闭原则”。这个也可以成为“开闭原则”的==倾斜性==。扩展产品族很方便,但是新增产品很复杂,需要对抽象工厂和工厂的实现类进行扩展。
-
适用场景
- 系统中有多于一个的产品族,而每次只使用其中某一产品族。可以通过配置文件等方式来使得用户可以动态改变产品族,也可以很方便地增加新的产品族。
- 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。==同一个产品族中的产品可以是没有任何关系的对象,但是它们都具有一些共同的约束,如同一操作 系统下的按钮和文本框,按钮与文本框之间没有直接关系,但它们都是属于某一操作系统 的,此时具有一个共同的约束条件:操作系统的类型。==
- 产品等级结构稳定,设计完成之后,不会向系统中增加新的产品等级结构或者删除已有的产品等级结构。
4. 单例模式(确保对象的唯一性)
-
单例模式是为了实现可以确保对象随时都可以被访问的全局变量,并且防止多次实例化产生多个实例,确保该类型实例唯一。实现的思路和过程为:
- 将构造函数私有化
- 通过静态方法获取一个唯一实例
- 保证线程安全
- 防止反序列化造成的新实例等。
-
需要保证唯一的单例类:
SingletonTargetObject.java
public class SingletonTargetObject { public static void work(){ System.out.println("单例对象正在工作。。。。"); } }
-
根据JVM加载类的逻辑实现单例
-
静态属性只初始化一次 ==饿汉式==
- 优点:线程安全
- 缺点:耗内存
public class Method1 { private static SingletonTargetObject singletonTargetObject = new SingletonTargetObject(); public static SingletonTargetObject getSingletonTargetObject(){ return singletonTargetObject; } }
-
利用静态代码块进行初始化类加载过程中,静态代码块只执行一次 ==饿汉式==
- 优点:线程安全
- 缺点:耗内存
public class Method2 { private static SingletonTargetObject singletonTargetObject; static { singletonTargetObject = new SingletonTargetObject(); } public static void main(String[] args) { singletonTargetObject.work(); } }
-
静态内部类单例模式
- 我把这种方法称之为:beginner:静态内部类的静态实例
- ==静态内部类和非静态内部类一样,都不会因为外部类的加载而加载,同时静态内部类的加载不需要依附外部类,在使用时才加载,不过在加载静态内部类的过程中也会加载外部类==
- 优点:线程安全、保证单例对象唯一性,同时也延迟了单例的实例化,避免了反射入侵
- 缺点:需要两个类去做到这一点,虽然不会创建静态内部类的对象,但是其 Class 对象还是会被创建,而且是属于永久代的对象。(综合来看,私以为这种方式是最好的单例模式)
public class Method3 { private static class innerClass{ private static SingletonTargetObject singletonTargetObject = new SingletonTargetObject(); } public static SingletonTargetObject getSingletonTargetObject(){ return innerClass.singletonTargetObject; } }
-
-
利用枚举的特性
-
每个枚举实例都是static final类型的,也就表明只能被实例化一次。在调用构造方法时,我们的单例被实例化。也就是说,因为enum中的实例被保证只会被实例化一次
-
优点:线程安全
-
缺点:枚举耗内存,能不用枚举就不用
public enum Method4 { INSTANCE; private SingletonTargetObject singletonTargetObject; Method4(){ singletonTargetObject = new SingletonTargetObject(); } public SingletonTargetObject getSingletonObject(){ return singletonTargetObject; } } //调用方式 Method4.INSTANCE.getSingletonObject()
-
优缺点
-
优点:获取对象的速度快,线程安全(因为虚拟机保证只会装载一次,在装载类的时候是不会发生并发的)
-
缺点:耗内存(若类中有静态方法,在调用静态方法的时候类就会被加载,类加载的时候就完成了单例的初始化,拖慢速度)
-
-
-
使用双重测试锁(Double Check Lock(DCL))
-
优点:既能保证线程安全,且单例对象初始化后调用getInstance不进行同步锁,资源利用率高
-
缺点:第一次加载稍慢,由于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; } }
-
-
使用容器实现单例模式
- 在程序的初始化,将多个单例类型注入到一个统一管理的类中,使用时通过key来获取对应类型的对象,==这种方式使得我们可以管理多种类型的单例,并且在使用时可以通过统一的接口进行操作。这种方式是利用了Map的key唯一性来保证单例。== 单例服务注册
public class Method6 { private static Map<String,Object singletonMap = new HashMap<(); public static void addSingleton(String key,Object singleton){ if(!singletonMap.containsKey(key)){ singletonMap.put(key,singleton); } } public static Object getSingleton(String name){ if(singletonMap.containsKey(name)){ return singletonMap.get(name); } return null; } }
-
适用场景
-
系统要求全局某个类的实例必须唯一的时候。
-
5. 原型模式(克隆模式)
-
当系统中需要大量创建相同或者相似的对象时,就可以通过“原型设计模式”来实现。
-
原型模式的核心思想是,通过拷贝指定的“原型实例(对象)”,创建跟该对象一样的新对象。==简单理解就是“克隆指定对象”。这里提到的“原型实例(对象)”,就是被克隆的对象,它的作用就是指定要创建的对象种类。==
-
原型模式用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
6. 建造者模式(复杂对象的组装与创建)
- 建造者模式相关----这个在java的源码设计中经常看到==
- 建造者模式用于构建一个包含多个属性的复杂对象的构建过程,该模式用于将复杂模式的构建和表示分离,通过链式调用构造出一个复杂的对象。也能够实现同样的构建过程可以构建不同的对象。
- 当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,考虑使用构造者模式。
- 该模式在java源码中和框架的代码中有大量的应用。
- 一个复杂类和构建器是一对一的关系。
-
代码实现
TargetObject.java 复杂对象
public class TargetObejct { private String name; private String address; private String sex; private int age; private float height; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public float getHeight() { return height; } public void setHeight(float height) { this.height = height; } @Override public String toString() { return "TargetObejct{" + "name='" + name + '\'' + ", address='" + address + '\'' + ", sex='" + sex + '\'' + ", age=" + age + ", height=" + height + '}'; } }
TargetObjectBuilder.java
public class TargetObjectBuilder { private TargetObejct targetObejct; public TargetObjectBuilder(){ targetObejct = new TargetObejct(); } public TargetObjectBuilder buildName(String name){ targetObejct.setName(name); return this; } public TargetObjectBuilder buildAddress(String address){ targetObejct.setAddress(address); return this; } public TargetObjectBuilder buildSex(String sex){ targetObejct.setSex(sex); return this; } public TargetObjectBuilder buildAge(int age){ targetObejct.setAge(age); return this; } public TargetObjectBuilder buildHeight(float height){ targetObejct.setHeight(height); return this; } public TargetObejct build() { return targetObejct; } }
main.java
public class main { public static void main(String[] args) { TargetObejct targetObejct =new TargetObjectBuilder() .buildAddress("宁夏") .buildName("Littlebaby") .build(); System.out.println(targetObejct.toString()); TargetObejct targetObejct1 =new TargetObjectBuilder() .buildAddress("安徽") .buildAge(22) .buildSex("女") .buildName("Littleyao") .buildHeight(186.5f) .build(); System.out.println(targetObejct1.toString()); } }
执行结果:
2.结构型模式(类或对象的组合) ==7个==
- 结构型模式就是解决类(或者接口)或者对象组合的问题
- 类(或者接口)的组合:使用继承或者实现来完成。
- 类结构型模式
- 接口结构型模式
- 对象的组合:使用对象组合来完成。通过在一个类中创建另一个类的实例变量,然后调用其方法,完成组合复用。
- 对象结构型模式
- 类(或者接口)的组合:使用继承或者实现来完成。
- 根据合成复用原则:多用组合,少用继承,所以大部分的结构型模式都是对象结构性模式。
:star:1. 适配器模式(包装器模式)
-
三个对象:适配者类(现有的业务接口),目标抽象类(期望的业务接口),适配器类(解决兼容性的类)
-
实现代码
Adaptee.java
public class Adaptee { public void playCartoon(){ System.out.println("我是适配者,我正在播放卡通动画"); } }
Target.java
public interface Target { void playVideo(); }
Client.java
public class Client { public static void main(String[] args) { Target t = new Adapter(); t.playVideo(); } }
==类适配器和对象适配器有点不同的是在适配器类的写法上:==
-
类适配器
Adapter.java
public class Adapter extends Adaptee implements Target{ @Override public void playVideo() { super.playCartoon(); } }
-
对象适配器
Adapter.java
public class Adapter implements Target{ @Override public void playVideo() { Adaptee adaptee = new Adaptee(); adaptee.playCartoon(); } }
-
-
基本概念
- 适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。它结合了两个独立接口的功能。==这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能,称之为适配类或者包装器类==。
- 适配器提供客户类需要的接口,适配器的实现就是把客户类的请求转化为对适配者的相应接口的调用。也就是说:当客户类调用适配器的方法时,在适配器类的内部将调用适配者类的方法,而这个过程对客户类是透明的,客户类并不直接访问适配者类。因此,适配器可以使由于接口不兼容而不能交互的类可以一起工作。这就是适配器模式的模式动机。
- 类适配器模式和对象适配器模式最大的==区别在于适配器和适配者之间的关系不同,对象适配器模式中适配器和适配者之间是依赖关系,而类适配器模式中适配器和适配者是继承关系==。在实现方式上就是对象适配器类中依赖一个适配类,类适配器中继承适配类。
- ==接口适配器模式(Default Adapter Pattern):当不需要实现一个接口所提供的所有方法时,可先设计一个抽象类实现该接口,并为接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可以选择性地覆盖父类的某些方法来实现需求,它适用于不想使用一个接口中的所有方法的情况,又称为单接口适配器模式。==
-
优点
-
将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。
-
增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性。
-
灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合“开闭原则”。
-
类适配器模式还具有如下优点:
由于适配器类是适配者类的子类,因此可以在适配器类中置换一些适配者的方法,使得适配器的灵活性更强。
-
对象适配器模式还具有如下优点:
一个对象适配器可以把多个不同的适配者适配到同一个目标,也就是说,同一个适配器可以把适配者类和它的子类都适配到目标接口。
- 缺点
-
类适配器模式的缺点如下:
对于Java等不支持多重继承的语言,一次最多只能适配一个适配者类,而且目标抽象类只能为抽象类,不能为具体类,==其使用有一定的局限性,不能将一个适配者类和它的子类都适配到目标接口。==
-
对象适配器模式的缺点如下:
与类适配器模式相比,要想置换适配者类的方法就不容易。如果一定要置换掉适配者类的一个或多个方法,就只好先做一个适配者类的子类,将适配者类的方法置换掉,然后再把适配者类的子类当做真正的适配者进行适配,实现过程较为复杂。
- 适用环境
-
系统需要使用现有的类,而这些类的接口不符合系统的需要。
-
想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
2. 桥接模式
-
四种角色:抽象类,扩展抽象层,实现类接口,具体实现类
-
实现代码
Phone.java ---关键的类 该类建桥
public abstract class Phone { PhoneShell phoneShell; public Phone(PhoneShell phoneShell) { this.phoneShell = phoneShell; } public abstract void sellPhone(); }
HuaweiPhone.java
public class HuaweiPhone extends Phone{ public HuaweiPhone(PhoneShell phoneShell) { super(phoneShell); } @Override public void sellPhone() { phoneShell.addPhoneShell(); System.out.println("套好保护壳的华为手机已经准备好了。。。"); } }
XiaomiPhone.java
public class XiaomiPhone extends Phone { public XiaomiPhone(PhoneShell phoneShell) { super(phoneShell); } @Override public void sellPhone() { phoneShell.addPhoneShell(); System.out.println("套好保护壳的小米手机已经准备好了。。。。"); } }
PhoneShell.java
public interface PhoneShell { void addPhoneShell(); }
RedShell.java
public class RedShell implements PhoneShell { @Override public void addPhoneShell() { System.out.println("我给手机套上了红色的壳子"); } }
BlueShell.java
public class BlueShell implements PhoneShell { @Override public void addPhoneShell() { System.out.println("我给手机套上了蓝色的壳子"); } }
Seller.java
public class Seller { public static void main(String[] args) { System.out.println("---有客人要买红色壳的小米手机--"); XiaomiPhone xiaomiPhone = new XiaomiPhone(new RedShell()); xiaomiPhone.sellPhone(); System.out.println("---有客人要买蓝色壳的华为手机--"); HuaweiPhone huaweiPhone = new HuaweiPhone(new BlueShell()); huaweiPhone.sellPhone(); } }
执行结果:
-
基本知识
- ==将抽象部分与它的实现部分分离,使它们都可以独立地变化。==它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。
- 在使用桥接模式时,==我们首先应该识别出一个类所具有的两个独立变化的维度==,将它们设计为两个独立的继承等级结构,==为两个维度都提供抽象层,并建立抽象耦合==。通常情况下,我们将具有两个独立变化维度的类的一些普通业务方法和与之关系最密切的维度设计为“抽象类”层次结构(抽象部分,可以理解为核心的业务),而将另一个维度设计为“实现类”层次结构(实现部分可以理解为附加业务)
- 与多层继承方案不同,它将两个独立变化的维度设计为两个独立的继承等级结构,并且在抽象层建立一个抽象关联,该关联关系就像一条桥一样,将两个独立继承结构的类联接起来,故名桥接模式。
- 可以明显看出,桥接模式使用组合代替了继承,将类之间的静态继承关系转换为动态的对象组合关系,使用组合而不用继承,会使系统更加灵活,并易于扩展,同时有效控制了系统中类的个数。
-
优点:
- 桥接模式提高了系统的可扩充性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统。
- 实现细节对客户透明,屏蔽系统的复杂性。
-
缺点:
- 桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性。
-
适用场景
- 桥接模式是一种很实用的结构型设计模式,在软件开发时,如果某个类存在两个独立变化的维度,可以运用桥接模式将这两个维度分离出来,使两者可以独立扩展,让系统更加符合“单一职责原则”。
:trophy:3. 组合模式----树形结构
-
角色:叶子对象,容器对象,元素的统一接口
-
代码实现
Component.java
public interface Component { void playMusic(); }
Leaf.java
public class Leaf implements Component { private String musicName; public Leaf(String musicName){ this.musicName = musicName; } @Override public void playMusic() { System.out.println("正在播放"+musicName); } }
Composite.java
public class Composite implements Component { private ArrayList<Component components = new ArrayList<(); @Override public void playMusic() { System.out.println("我是容器,不播放东西"); } public void addComponent(Component component){ components.add(component); } public boolean removeComponent(Component component){ return components.remove(component); } public Component getLeaf(int index){ return components.get(index); } public ListIterator<Component getIterator(){ return components.listIterator(); } }
main.java
public class main { public static void main(String[] args) { Composite composite1 = new Composite(); Composite composite2 = new Composite(); composite1.addComponent(composite2); composite2.addComponent(new Leaf("日本歌")); composite2.addComponent(new Leaf("韩国歌曲")); composite1.addComponent(new Leaf("欧美流行")); composite1.addComponent(new Leaf("民歌")); findAll(composite1); } private static void findAll(Component component){ if(component instanceof Leaf){ ((Leaf)component).playMusic(); return ; } if(component instanceof Composite){ Iterator<Component iter = ((Composite) component).getIterator(); while(iter.hasNext()){ findAll(iter.next()); } } } }
运行结果:
-
基本知识
- 组合模式定义了如何将容器对象和叶子对象进行递归组合,==使得客户在使用的过程中无须进行区分,可以对他们进行一致的处理。==
- 组合模式(Composite Pattern):==组合多个对象形成树形结构以表示具有“整体—部分”关系的层次结构==。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性,组合模式又可以称为“整体—部分”(Part-Whole)模式,它是一种对象结构型模式。
- 组合模式的关键是定义了一个抽象构件类,它既可以代表叶子,又可以代表容器,而客户端针对该抽象构件类进行编程,无须知道它到底表示的是叶子还是容器,可以对其进行统一处理。同时容器对象与抽象构件类之间还建立一个聚合关联关系,在容器对象中既可以包含叶子,也可以包含容器,以此实现递归组合,形成一个树形结构。
:star:4. 装饰模式
-
角色:装饰目标类接口,具体目标类,装饰抽象类,具体装饰类
-
实现代码
Phone.java
public interface Phone { void playMusic(); }
XiaomiPhone.java
public class XiaomiPhone implements Phone { @Override public void playMusic() { System.out.println("正在播放小米之歌"); } }
Decorator.java
public abstract class Decorator implements Phone { Phone phone; public Decorator(Phone phone) { this.phone = phone; } @Override public void playMusic() { phone.playMusic(); } public abstract void addFunction(); }
XiaomiDecorator.java
public class XiaomiDecorator extends Decorator { @Override public void playMusic() { super.playMusic(); addFunction(); } public XiaomiDecorator(Phone phone) { super(phone); } @Override public void addFunction() { System.out.println("给小米的手机在播放音乐的时候加个跑马灯"); } }
main.java 充当客户端
public class main { public static void main(String[] args) { Decorator decorator = new XiaomiDecorator(new XiaomiPhone()); decorator.playMusic(); } }
运行结果:
-
基本知识
- 装饰模式是为了给对象添加职能,添加职能的方式常用的为静态代理模式或者继承来生成子类对对象的功能进行增强。装饰模式比生成子类实现更为灵活。装饰模式是一种对象结构型模式。
- 装饰模式是一种用于替代继承的技术,==它通过一种无须定义子类的方式来给对象动态增加职责,使用对象之间的关联关系取代类之间的继承关系。==在装饰模式中引入了装饰类,在装饰类中既可以调用待装饰的原有类的方法,还可以增加新的方法,以扩充原有类的功能。
-
优点
- ==装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性==。
- 具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”
-
缺点
- 使用装饰模式进行系统设计时将产生很多小对象,这些对象的区别在于它们之间相互连接的方式有所不同,而不是它们的类或者属性值有所不同,同时还将产生很多具体装饰类。这些装饰类和小对象的产生将增加系统的复杂度,加大学习与理解的难度。
- 这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。
-
适用场景
- 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。需要动态地给一个对象增加功能,这些功能也可以动态地被撤销。
5. 外观模式
-
两个角色: 子系统类,,门面类
-
代码实现
Facade.java 门面类
public class Facade { SubClass1 subClass1 = new SubClass1(); SubClass2 subClass2 = new SubClass2(); SubClass3 subClass3 = new SubClass3(); public void work(){ subClass1.work(); } public void work1(){ subClass2.work1(); } public void work2(){ subClass3.work2(); } }
SubClass1.java
public class SubClass1 { public void work(){ System.out.println("我这个系统可以播放音乐"); } }
SubClass2.java
public class SubClass2 { public void work1(){ System.out.println("我这系统可以播放电影"); } }
SubClass3.java
public class SubClass3 { public void work2(){ System.out.println("我这个系统可以打电话"); } }
main.java
public class main { public static void main(String[] args) { Facade facade = new Facade(); facade.work(); facade.work1(); facade.work2(); } }
运行结果:
-
基本知识
- 外观模式是一种使用频率非常高的结构型设计模式,它通过引入一个外观角色(门面类)来简化客户端与子系统之间的交互,==为复杂的子系统调用提供一个统一的入口,降低子系统与客户端的耦合度,且客户端调用非常方便。==
- 外观模式的主要目的在于降低系统的复杂程度,在面向对象软件系统中,类与类之间的关系越多,不能表示系统设计得越好,反而表示系统中类之间的耦合度太大,这样的系统在维护和修改时都缺乏灵活性,因为一个类的改动会导致多个类发生变化,而外观模式的引入在很大程度上降低了类与类之间的耦合关系。引入外观模式之后,增加新的子系统或者移除子系统都非常方便,客户类无须进行修改(或者极少的修改),只需要在外观类中增加或移除对子系统的引用即可。从这一点来说,外观模式在一定程度上并不符合开闭原则,增加新的子系统需要对原有系统进行一定的修改,虽然这个修改工作量不大
-
优点
- 对客户屏蔽子系统组件,减少了客户处理的对象数目并使得子系统使用起来更加容易。通过引入外观模式,客户代码将变得很简单,与之关联的对象也很少。
- 实现了子系统与客户之间的松耦合关系,这使得子系统的组件变化不会影响到调用它的客户类,只需要调整外观类即可。
- 降低了大型软件系统中的编译依赖性,并简化了系统在不同平台之间的移植过程,因为编译一个子系统一般不需要编译所有其他的子系统。一个子系统的修改对其他子系统没有任何影响,而且子系统内部变化也不会影响到外观对象。
- 只是提供了一个访问子系统的统一入口,并不影响用户直接使用子系统类。
-
缺点
- 不能很好地限制客户使用子系统类,如果对客户访问子系统类做太多的限制则减少了可变性和灵活性。
- 在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”。
-
适用环境
- 当要为一个复杂子系统提供一个简单接口时可以使用外观模式。该接口可以满足大多数用户的需求,而且用户也可以越过外观类直接访问子系统。
- 客户程序与多个子系统之间存在很大的依赖性。引入外观类将子系统与客户以及其他子系统解耦,可以提高子系统的独立性和可移植性。
- 在层次化结构中,可以使用外观模式定义系统中每一层的入口,层与层之间不直接产生联系,而通过外观类建立联系,降低层之间的耦合度。
6. 享元模式(Flyweight pattern)
- 四个对象: 享元工厂,抽象享元,具体享元,非享元
-
实现代码
FlyWeightFactory.java
public class FlyWeightFactory { private static Map<String,FlyWeight> 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
public interface FlyWeight { void operation(UnsharedComponent unsharedComponent); }
ConcreteFlyWeight.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
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
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("爱上课","学习哥")); } }
运行结果:
-
基础知识
- 所谓的享元模式:就是把一个经常被创建的对象,按照属性的变化情况,把属性分为内部状态(有大量重复的),外部状态(经常变化的),然后按照内部状态创建对象称为享元(意为共享单元),并且预留一个接收外部状态的方法来实现完整的逻辑,并且存到容器中,然后将外部状态也组织成一个类型,在使用的过程中,将该外部对象传到享元的方法中,执行完整的逻辑。避免一个个生成对象,造成内存耗费巨大。
- 享元模式,==第一个想到的应该就是池技术了,String常量池、数据库连接池、缓冲池等等都是享元模式的应用,所以说享元模式是池技术的重要实现方式。==
- 享元模式(Flyweight Pattern):==运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。==由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,它是一种对象结构型模式
- 所谓“享元”,顾名思义就是被共享的单元。==享元模式的意图是复用对象,节省内存,前提是享元对象是不可变对象。==
- ==具体来讲,当一个系统中存在大量重复对象的时候,我们就可以利用享元模式,将对象设计成享元,在内存中只保留一份实例,供多处代码引用,这样可以减少内存中对象的数量,以起到节省内存的目的。实际上,不仅仅相同对象可以设计成享元,对于相似对象,我们也可以将这些对象中相同的部分(字段),提取出来设计成享元,让这些大量相似对象引用这些享元==
-
优点
- 享元模式的优点在于它可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份。
- 享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。
-
缺点
- 享元模式使得系统更加复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化。
- 为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。
-
适用环境
- 一个系统有大量相同或者相似的对象,由于这类对象的大量使用,造成内存的大量耗费。
- 对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。
- 使用享元模式需要维护一个存储享元对象的享元池,而这需要耗费资源,因此,应当在多次重复使用享元对象时才值得使用享元模式。
:star:7. 代理模式
-
三个角色:抽象接口,实现接口的目标对象,代理对象
-
实现代码
Phone.java
public interface Phone { void playMusic(); }
XiaomiPhone.java
public class XiaomiPhone implements Phone { @Override public void playMusic() { System.out.println("打开小米手机的网易云放首歌!额,卡住了!"); } }
Proxy.java
public class Proxy implements Phone { private XiaomiPhone xiaomiPhone = new XiaomiPhone(); @Override public void playMusic() { xiaomiPhone.playMusic(); } }
main.java
public class main { public static void main(String[] args) { Proxy p = new Proxy(); p.playMusic(); } }
运行结果:
-
基本知识
- :christmas_tree:代理模式重点不在于增强,而在于代替。
- 代理模式是常用的结构型设计模式之一,当无法直接访问某个对象或访问某个对象存在困难 时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,所访问的真实对象与代理对象需要实现相同的接口。根据代理模式的使用目的不同,代理模式又可以分为多种类型,例如保护代理、远程代理、虚拟代理、缓冲代理等,它们应用于不同的场合,满足用户的不同需求。
- 远程代理(Remote Proxy)是一种常用的代理模式,它使得客户端程序可以访问在远程主机上的 对象,远程主机可能具有更好的计算性能与处理速度,可以快速响应并处理客户端的请求。 远程代理可以将网络的细节隐藏起来,使得客户端不必考虑网络的存在。客户端完全可以认 为被代理的远程业务对象是在本地而不是在远程,而远程代理对象承担了大部分的网络通信工作,并负责对远程业务方法的调用。
- 虚拟代理(Virtual Proxy)也是一种常用的代理模式,对于一些占用系统资源较多或者加载时间 较长的对象,可以给这些对象提供一个虚拟代理。在真实对象创建成功之前虚拟代理扮演真实对象的替身,而当真实对象创建之后,虚拟代理将用户的请求转发给真实对象
-
优点
- 代理模式能够协调调用者和被调用者,在一定程度上降低了系 统的耦合度。
- 远程代理使得客户端可以访问在远程机器上的对象,远程机器 可能具有更好的计算性能与处理速度,可以快速响应并处理客户端请求。
- 虚拟代理通过使用一个小对象来代表一个大对象,可以减少系 统资源的消耗,对系统进行优化并提高运行速度。
- 保护代理可以控制对真实对象的使用权限。
-
缺点
- 由于在客户端和真实主题之间增加了代理对象,因此 有些类型的代理模式可能会造成请求的处理速度变慢。
- 实现代理模式需要额外的工作,有些代理模式的实现 非常复杂。
-
适用环境
- 远程(Remote)代理:为一个位于不同的地址空间的对象提供一个本地 的代理对象,这个不同的地址空间可以是在同一台主机中,也可是在 另一台主机中,远程代理又叫做大使(Ambassador)。
- 虚拟(Virtual)代理:如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。
- Copy-on-Write代理:它是虚拟代理的一种,把复制(克隆)操作延迟 到只有在客户端真正需要时才执行。一般来说,对象的深克隆是一个 开销较大的操作,Copy-on-Write代理可以让这个操作延迟,只有对象被用到的时候才被克隆。
- 保护(Protect or Access)代理:控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限。
- 缓冲(Cache)代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。
- 防火墙(Firewall)代理:保护目标不让恶意用户接近。
- 同步化(Synchronization)代理:使几个用户能够同时使用一个对象而没有冲突。
- 智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,如将此对象被调用的次数记录下来等。
3.行为型模式 ==11==
- 行为型模式(Behavioral Pattern)是对在不同的对象之间划分责任和算法的抽象化。行为型模式不仅仅关注类和对象的结构,而且重点关注它们之间的相互作用。
1. 职责链模式
-
角色: 抽象处理者,具体处理者,处理链组装,封装请求和响应的Request和Response
-
实现代码
LRequest.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
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
public interface Handler { LResponse handler(LRequest request); }
ConcreteHandler.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 --做责任链的组装
public class main { private static java.util.List<Handler> 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("-----处理结束----"); } }
运行结果:
-
基本知识
-
职责链模式定义如下:职责链模式(Chain of Responsibility Pattern):==避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。==职责链模式是一种对象行为型模式。
==纯与不纯的职责链模式==
- 职责链模式可分为纯的职责链模式和不纯的职责链模式两种:
- (1) 纯的职责链模式 一个纯的职责链模式要求一个具体处理者对象只能在两个行为中选择一个:要么承担全部责 任,要么将责任推给下家,不允许出现某一个具体处理者对象在承担了一部分或全部责任后 又将责任向下传递的情况。而且在纯的职责链模式中,要求一个请求必须被某一个处理者对 象所接收,不能出现某个请求未被任何一个处理者对象处理的情况。在前面的采购单审批实 例中应用的是纯的职责链模式。
- (2)不纯的职责链模式 在一个不纯的职责链模式中允许某个请求被一个具体处理者部分处理后再向下传递,或者一 个具体处理者处理完某请求后其后继处理者可以继续处理该请求,而且一个请求可以最终不被任何处理者对象所接收。
- 职责链模式可分为纯的职责链模式和不纯的职责链模式两种:
-
职责链模式通过建立一条链来组织请求的处理者,请求将沿着链进行传递,请求发送者无须知道请求在何时、何处以及如何被处理,实现了请求发送者与处理者的解耦。在软件开发中,==如果遇到有多个对象可以处理同一请求时可以应用职责链模式==,例如在Web应用开发中创 建一个过滤器(Filter)链来对请求数据进行过滤,在工作流系统中实现公文的分级审批等等,使用职责链模式可以较好地解决此类问题.
-
实现方法:
- 定义一个请求的处理抽象接口
- 去实现处理请求的多个具体实现类,然后按照请求的顺序构建链式调用的处理规则。
-
:star:2. 策略模式
-
角色:策略抽象接口,具体策略实现,执行环境(执行调用)
-
实现代码
Strategy.java
public interface Strategy { void operation(String param); }
ConcreteStrategy1.java
public class ConcreteStrategy1 implements Strategy{ @Override public void operation(String paranm) { System.out.println("我用勺子吃"+paranm); } }
ConcreteStrategy2.java
public class ConcreteStrategy2 implements Strategy{ @Override public void operation(String param) { System.out.println("我用吸管喝"+param); } }
Context.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
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); } }
-
基础知识
- 在策略模式中,==我们可以定义一些独立的类来封装不同的算法,每一个类封装一种具体的算法,在这里,每一个封装算法的类我们都可以称之为一种策略(Strategy)==,为了保证这些策略在使用时具有一致性,一般会提供一个抽象的策略类来做规则的定义,而每种算法则对应于一个具体策略类。
- 策略模式的主要目的是将算法的定义与使用分开,也就是将算法的行为和环境分开,将算法的定义放在专门的策略类中,每一个策略类封装了一种实现算法,使用算法的环境类针对抽象策略类进行编程,符合“依赖倒转原则”。在出现新的算法时,只需要增加一个新的实现了抽象策略类的具体策略类即可。策略模式定义如下: 策略模式(Strategy Pattern):定义一系列算法类,将每一个算法封装起来,并让它们可以相互替换,策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。策略模式是一种对象行为型模式。
:star:3. 命令模式
-
四个角色:命令接收者抽象,具体的命令接收者,调用者,命令接口,具体命令
-
实现代码
Receiver.java
public interface Receiver { void play(); void rewind(); void stop(); }
XiaomiPhoneReceiver.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
public interface Command { void execute(); }
WorkCommand.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
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
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
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
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(); } }
运行结果:
-
基本知识
- 命令模式是对命令的封装。命令模式把发出命令的责任(由调用者)和执行命令的责任分隔开,委派给不同的对象。==本质上就是对接收者的业务处理使用一个命令对象做一个统一的封装==。每一个处理方法对应一个封装类。
- 命令模式的前提是,已经有任务的执行者,就是接收者,接收者具体执行任务,命名对象不过是把执行的命令,封装成一个统一的接口。
- 一个命令封装成一个命令对象,这就保证了命令对象调用的透明性,客户端只需要调用命令的execute()方法就可以了。系统的扩展性很强
- 命令模式(Command Pattern):将一个请求封装为一个对象,从而让我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式。
- 命令模式的核心在于引入了命令类,通过命令类来降低发送者和接收者的耦合度,请求发送者只需指定一个命令对象,再通过命令对象来调用请求接收者的处理方法。
- 调用者是通过提供Command的设置入口,从而使invoker可以调用不同的接口。
:star:4. 观察者模式
-
角色:被观察抽象,具体被观察者,观察者抽象,具体观察者
-
代码实现
Subject.java
public interface Subject { void addObserver(Observer observer); void removeObserver(Observer observer); void notifyAllObs(); void operation(); }
ConcreteSubject.java
public class ConcreteSubject implements Subject{ private ArrayList<Observer> 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
public interface Observer { void operation(); }
Observer1.java
public class Observer1 implements designModel.L18Observer.Observer { @Override public void operation() { System.out.println("上海观察站收到!"); } }
Observer2.java
+++++++++++++++++++++ public class Observer2 implements designModel.L18Observer.Observer { @Override public void operation() { System.out.println("南京观察站收到!"); } }
main.java
public class main { public static void main(String[] args) { Subject subject = new ConcreteSubject(); subject.addObserver(new Observer1()); subject.addObserver(new Observer2()); subject.operation(); } }
-
基本知识
- 观察者模式是使用频率最高的设计模式之一,==它用于建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应作出反应。==在观察者模式中,==发生改变的对象称为观察目标,而被通知的对象称为观察者==。
- 一个观察目标可以对应多个观察者,而且这些观察者之间可以没有任何相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展。
- 观察者模式定义如下:定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式的别名包括发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。观察者模式是一种对象行为型模式。
- 观察者和被观察者的定义可以属于相同的类型也可以属于不同的类型。
5. 解释器模式
-
角色: 上下文,解析器抽象,终结符解析器,非终结符解析器,客户端
-
基本知识
- 解释器模式描述了如何为简单的语言定义一个文法,如何在该语言中表示一个句子,以及如 何解释这些句子。
6. 迭代器模式
-
角色:集合对象(聚合对象)接口,具体集合,迭代器接口,具体迭代器
-
这个太常见了,代码略
-
基本知识
- 迭代器模式(Iterator Pattern):提供一种方法来访问聚合对象,而不用暴露这个对象的内部表 示,其别名为游标(Cursor)。迭代器模式是一种对象行为型模式。
7. 中介者模式
-
角色:抽象中介者,具体中介者,交互对象抽象,具体交互对象的实现
-
代码
Meditor.java
public abstract class Meditor { ArrayList<Colleague> colleagueArrayList = new ArrayList<>(); public void addColleagur(Colleague colleague){ colleagueArrayList.add(colleague); } public abstract void cowork(Colleague colleague); }
ConcreteMeditor.java
public class ConcreteMeditor extends Meditor{ @Override public void cowork(Colleague colleague) { for(Colleague colleague1 : colleagueArrayList){ if(!colleague1.equals(colleague)){ colleague1.selfwork(); } } } }
Colleague.java
public interface Colleague { void selfwork(); void cowork(); }
ConcreteColleague1.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
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
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(); }
运行图片
-
基本知识
- 中介者模式(Mediator Pattern):用一个中介对象(中介者)来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式又称为调停者模式,它是一种对象行为型模式。
8. 备忘录模式
-
角色:原发者,备忘录对象,备忘录存储
-
代码
Originator.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
public class Memento { private int state; public Memento(int state) { this.state = state; } public int getState() { return state; } }
MementoTaker.java
public class MementoTaker { private static Memento memento; public static void setMemento(Memento memento1) { memento = memento1; } public static Memento getMemento(){ return memento; } }
main.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); } }
运行结果:
-
基本知识:
- 备忘录模式(Memento Pattern):在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。它是一种对象行为型模式,其别名为Token。
- 状态保存可以保存最新的状态,也可以使用列表记录多次的状态,恢复的时候使用游标来进行位置标定。
9. 状态模式
- 角色:上下文环境,状态抽象接口,状态实现类。
-
实现代码
State.java
public interface State { void handler(); }
ConcreteState1.java
public class ConcreteState1 implements State{ @Override public void handler() { System.out.println("状态1开始干活"); } }
ConcreteState2.java
public class ConcreteState2 implements State { @Override public void handler() { System.out.println("状态2开始工作"); } }
Context.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
public class main { public static void main(String[] args) { Context context = new Context(); context.handler(1); System.out.println("状态发生改变了"); context.handler(2); } }
运行结果
-
基础知识
- 状态模式(State Pattern):允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修 改了它的类。其别名为状态对象(Objects for States),状态模式是一种对象行为型模式。
10. 模版方法模式
-
角色:模版方法,具体实现方法
-
实现代码
AbstractClass.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
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
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
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(); } }
运行结果:
-
基础知识
- 模板方法模式是结构最简单的行为型设计模式,在其结构中只存在父类与子类之间的继承关 系。通过使用模板方法模式,可以将一些复杂流程的实现步骤封装在一系列基本方法中,在 抽象父类中提供一个称之为模板方法的方法来定义这些基本方法的执行次序,而通过其子类 来覆盖某些步骤,从而使得相同的算法框架可以有不同的执行结果。模板方法模式提供了一 个模板方法来定义算法框架,而某些具体步骤的实现可以在其子类中完成。
11. 访问者模式
- 角色:抽象访问者,具体访问者,对象结构元素(存储),抽象元素,具体元素
-
实现代码
Element.java
public interface Element { void accept(Visitor visitor); }
ConcreteElement1.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
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
public interface Visitor { void check(ConcreteElement1 concreteElement1); void check(ConcreteElement2 concreteElement2); }
ConcreteVisitor1.java
public class ConcreteVisitor1 implements Visitor { @Override public void check(ConcreteElement1 concreteElement1) { concreteElement1.welcomeVisitor1(); } @Override public void check(ConcreteElement2 concreteElement2) { concreteElement2.welcomeVisitor3(); } }
ConcreteVisitor2.java
public class ConcreteVisitor2 implements Visitor{ @Override public void check(ConcreteElement1 concreteElement1) { concreteElement1.welcomeVisitor2(); } @Override public void check(ConcreteElement2 concreteElement2) { concreteElement2.welcomeVisitor4(); } }
ObjectStruct.ajva
public class ObjectStruct { private ArrayList<Element> 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
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()); } }
运行结果
-
基础知识
- 访问者模式(Visitor Pattern):提供一个作用于某对象结构中的各元素的操作表示,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式是一种对象行为型模式。
- 访问者模式,就是设置访问者的角色,来完成,需要对一个集合对象中不同的类型完成不同的操作,而且把操作和对象集合进行解耦,使用外部对象来完成操作。有点抽象,得多写代码体会这些设计模式的深层次的指导意义。