23种设计模式简述

目录

一、设计模式的分类

1.1 创建型模式

1.2 结构型模式

1.3 行为型模式

二、设计模式的六大原则

2.1 开闭原则

2.2 里氏替换原则

2.3 依赖倒转原则

2.4 接口隔离原则

2.5 迪米特法则

2.6 合成复用原则

三、设计模式

3.1 单例模式

3.2 工厂模式

3.3 建造者模式

3.4 原型模式     

3.5 代理模式   

3.6 桥接模式  

3.7 装饰器模式

3.8 适配器模式

3.9 外观(门面)模式

3.10 组合模式

3.11 享元模式

3.12 观察者模式

3.13 模板模式

3.14 策略模式

3.15 责任链模式

3.16 迭代器模式

3.17 状态模式

3.18 访问者模式

3.19 备忘录模式

3.20 命令模式

3.21 解释器模式

3.22 中介模式

3.23 抽象工厂模式



一、设计模式的分类

1.1 创建型模式

        这种模式提供·了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。包括(工厂模式,抽象工厂模式,单例模式,建造者模式,原型模式

1.2 结构型模式

        这种模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。包括(适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式

1.3 行为型模式

        这些设计模式特别关注对象之间的通信。包括(策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式

二、设计模式的六大原则

2.1 开闭原则

        对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类。

2.2 里氏替换原则

        里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范

2.3 依赖倒转原则

        是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体

2.4 接口隔离原则

        使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。

2.5 迪米特法则

        又称最少知道原则,一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立

2.6 合成复用原则

        尽量使用合成/聚合的方式,而不是使用继承

三、设计模式

3.1 单例模式

        介绍:用来创建全局唯一的对象。一个类只允许创建一个对象(或者叫实例),那这个类就是一个单例类,这种设计模式就叫作单例模式。单例有几种经典的实现方式,它们分别是:饿汉式、懒汉式、双重检测、静态内部类、枚举

        场景:对于一些全局类,没有后续扩展需求并且不依赖外部系统的场景中可以使用。例如多线程的线程池,数据库的连接池等当对象需要被共享的场合。由于单例模式只允许创建一个对象,共享该对象可以节省内存,并加快对象访问速度

        不足:1.单例对OOP特性的支持不友好

                   2.单例会隐藏类之间的依赖关系

                   3.单例对代码的扩展性不友好、

                   4.单例对代码的可测试性不友好

                   5.单例不支持有参数的构造函数

3.2 工厂模式

       介绍: 工厂模式包括简单工厂、工厂方法、抽象工厂这3种细分模式。用来创建不同但是相关类型的对象(继承同一父类或者接口的一组子类),由给定的参数来决定创建哪种类型的对象。

        场景:当对象创建逻辑比较复杂,是一个“大工程”的时候,就考虑使用工厂模式,封装对象的创建过程,将对象的创建和使用相分离。Spring IOC、Google Guice就是使用的工厂模式。

        优点:1.封装变化:创建逻辑有可能变化,封装成工厂类之后,创建逻辑的变更对调用者透明

                   2.代码复用:创建代码抽离到独立的工厂类之后可以复用

                   3.隔离复杂性:封装复杂的创建逻辑,调用者无需了解如何创建对象

                   4.控制复杂度:将创建代码抽离出来,让原本的函数或类职责更单一,代码更简洁

         不足:1.简单工厂,耦合度高,如果有变动就需要修改唯一的工厂

                    2.工厂方法,优点符合开闭(具体的业务类有具体工厂),缺点是每增加一个产品,相应的也要增加一个子工厂,加大了额外的开发量

3.3 建造者模式

        介绍:用来创建复杂对象,可以通过设置不同的可选参数,“定制化”地创建不同的对象。与工厂模式不同的是,建造者的目的在于把复杂构造过程从不同对象展现中抽离出来,使得同样的构造工序可以展现出不同的产品对象。建造者模式注重零部件的组装过程,而工厂方法模式更注重零部件的创建过程,但两者可以结合使用

        场景:创建组装复杂对象。StringBuilder 类中提供了 append() 方法,这就是一种链式创建对象的方法,开放构造步骤,最后调用 toString() 方法就可以获得一个完整的对象。MyBatis 中 SqlSessionFactoryBuiler 类用到了建造者模式

        优点:1.各个具体的建造者相互独立,有利于系统的扩展

                   2.客户端不必知道产品内部组成的细节,便于控制细节风险

        不足:1.产品的组成部分必须相同,这限制了其使用范围

                   2.如果产品的内部变化复杂,该模式会增加很多的建造者类

3.4 原型模式     

        介绍:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式有两种实现方法,深拷贝和浅拷贝。 原型模式的目的是 降低实例对象个数 , 减少构造函数的调用次数

        场景:如果对象的创建成本比较大,而同一个类的不同对象之间差别不大(大部分字段都相同),在这种情况下,我们可以利用对已有对象(原型)进行复制(或者叫拷贝)的方式,来创建新对象,以达到节省创建时间的目的。Spring 中原型 bean 的创建

        优点:1.性能高 : 使用原型模式复用的方式创建实例对象 , 比使用构造函数重新创建对象性能要高 ; ( 针对类实例对象开销大的情况 )

                   2.流程简单 : 原型模式可以简化创建的过程 , 可以直接修改现有的对象实例的值 , 达到复用的目的 ; ( 针对构造函数繁琐的情况 )

        不足:1.覆盖 clone 方法 ( 必须 ) : 必须重写对象的 clone 方法 , Java 中提供了 cloneable 标识该对象可以被拷贝 , 但是必须覆盖 Object 的 clone 方法才能被拷贝 ;

                   2.深拷贝 与 浅拷贝 风险 : 克隆对象时进行的一些修改 , 容易出错 ; 需要灵活运用深拷贝与浅拷贝操作 ;

3.5 代理模式   

        介绍:在不改变原始类接口的条件下,为原始类定义一个代理类,主要目的是控制访问,而非加强功能,这也是它跟装饰器模式最大的不同。

        场景:在需要用比较通用和复杂的对象指针代替简单的指针的时候,也常用在业务系统中开发一些非功能性需求。Spring的面向切面AOP,监控、统计、鉴权、限流、事务、幂等、日志,RPC、缓存

        优点:1.代理模式能将代理对象与真实被调用的目标对象分离

                   2.一定程度上降低了系统的耦合度,扩展性好

                   3.可以起到保护目标对象的作用

                   4.可以对目标对象的功能增强

        不足:1.代理模式会造成系统设计中类的数量增加

                   2.在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢

                   3.增加了系统的复杂度

3.6 桥接模式  

        介绍:将抽象部分与它的实现部分分离,使它们都可以独立地变化。是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度

        场景:1.抽象和具体实现之间 , 需要增加更多灵活性的情况。

                   2.不希望使用继承 , 或 因多层继承导致系统类的个数增加。

                   3.一个类存在 2 个或更多的 独立变化维度 , 并且这些维度都需要独立扩展。源码中JDBC 规范和不同数据库厂商驱动都用的桥接模式

        优点:1.抽象与实现分离,扩展能力强

                   2.符合开闭原则

                   3.符合合成复用原则

                   4.实现细节透明化

        不足:由于聚合关系建立在抽象层,要求开发者针对抽象化进行设计与编程,能正确地识别出系统中两个独立变化的维度,这增加了系统的理解与设计难度

3.7 装饰器模式

        介绍:允许向一个现有的对象添加新的功能,同时又不改变其结构。主要解决继承关系过于复杂的问题,通过组合来替代继承,给原始类动态添加增强功能

        场景:1.在不想增加很多子类的情况下扩展类时可用。

                   2.想要动态的为类增加功能

        在Mybatis中Executor接口,是一个承上启下的执行器,在执行的过程中就会有本地缓存的一个使用,所以Mybatis使用上缓存的情况下,要在原有执行的方法上做增强(缓存),就考虑到装饰器模式来做缓存。

        优点:1.饰类和被装饰类可以独立发展,而不会相互耦合。是继承的一个替代模式。

                   2.装饰模式可以动态地扩展或撤销一个实现类的功能

        不足:会出现更多的代码,更多的类,增加程序复杂性

3.8 适配器模式

        介绍:适配器模式是用来做适配的,它将不兼容的接口转换为可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作。适配器模式有两种实现方式:类适配器和对象适配器。其中,类适配器使用继承关系来实现,对象适配器使用组合关系来实现。

        场景:1.封装有缺陷的接口设计

                   2.统一多个类的接口设计

                   3.替换依赖的外部系统

                   4.兼容老版本接口

                   5.适配不同格式的数据

        在Spring 的 AOP 面向切面编程

        优点:1.更好的复用性,系统需要使用现有的类,而此类的接口不符合系统的需要,那么通过适配器模式就可以让这些功能得到更好的复用。

                   2.透明、简单,客户端可以调用同一接口,因而对客户端来说是透明的

                   3.更好的扩展性,在实现适配器功能的时候,可以调用自己开发的功能,从而自然地扩展系统的功能

                   4.解耦性,目标类和适配者类解耦,通过引入一个适配器类重用现有的适配者类,而无需修改原有代码

        不足:过多的使用适配器,会让系统非常零乱,不易整体进行把握

3.9 外观(门面)模式

        介绍:通过封装细粒度的接口,提供组合各个细粒度接口的高层次接口,来提高接口的易用性,或者解决性能、分布式事务等问题。当你需要构建一个层次结构的子系统时,使用facade模式定义子系统中每层的入口点。如果子系统之间是相互依赖的,你可以让它们仅通过facade进行通讯,从而简化了它们之间的依赖关系

        场景:1.子系统相对独立时可使用,Tomcat源码中有很多不同组件,每个组件要相互通信。mybatis源码

        优点:1.松耦合,用户与子系统解耦,屏蔽子系统;可以提高子系统的独立性;

                   2.使用简单,用户只与门面对接,有统一的入口;不需要知道所有子系统及内部构造;

                   3.更好的划分访问层次

         不足:1.没有面向抽象编程,而是通过增加中介层,转换服务提供方的服务接口;

                    2.不符合开闭原则,如果要改东西很麻烦,继承重写都不合适

3.10 组合模式

        介绍:组合模式所应用的就是树形结构以表达“部分/整体”的层次结构。主要是用来处理树形结构数据,与其说是一种设计模式,倒不如说是对业务场景的一种数据结构和算法的抽象

        场景:1.适用于处理树形结构

                   2.忽略差异 : 希客户端可以忽略 组合对象 与 单个对象 的差异

   SpringMVC框架中Security Oauth2框架中

        优点:1.定义层次 : 清楚地 定义 分层次 的 复杂对象 , 表示 对象 的 全部 或 部分 层次 

                   2.忽略层次 : 让 客户端 忽略 层次之间的差异 , 方便对 整个层次结构 进行控制 

                   3.简化客户端代码 

                   4.符合开闭原则 

         不足:1.限制类型复杂 : 限制类型时 , 比较复杂 

                    2.使设计变得更加抽象 

3.11 享元模式

        介绍:又称轻量级模式,对象池的一种实现。所谓“享元”,顾名思义就是被共享的单元。享元模式的意图是复用对象,节省内存,前提是享元对象是不可变对象。运用共享技术有效地支持大量细粒度的对象。

        场景:1.常常应用于系统底层的开发,以便解决系统的性能问题。

                   2.系统有大量相似的对象、需要缓存池的场景。

                   String类,Interger,Long等基本包装类中

        优点:1.减少对象的创建 ,降低内存中对象的数量 ,降低系统的内存 ,提高效率;

                   2.减少内存之外的其它资源占用。

         不足:1.关注内、外部状态、关注线程安全问题;

                    2.使系统、程序复杂化

3.12 观察者模式

        介绍:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新观察者 有多个 , 被观察的 主题对象 只有一个

        场景:1.一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。

                   2.需要在系统中创建一个触发链,使得事件拥有跨域通知(跨越两种观察者的类型)

                   JDK的util包中。MVC(Modew-View-Controller)架构中也应用了观察者模式,其中模型(Model)可以对应观察者模式中的观察目标,而视图(View)对应于观察者,控制器(Controller)就是中介者模式的应用

        优点:1.抽象耦合 : 在 观察者 和 被观察者 之间 , 建立了一个 抽象的 耦合 ; 由于 耦合 是抽象的 , 可以很容易 扩展 观察者 和 被观察者 ;

                   2.广播通信 : 观察者模式 支持 广播通信 , 类似于消息广播 , 如果需要接收消息 , 只需要注册一下即可

         不足:1.依赖过多 : 观察者 之间 细节依赖 过多 , 会增加 时间消耗 和 程序的复杂程度 ;

                    2.循环调用 : 避免 循环调用 , 观察者 与 被观察者 之间 绝对不允许循环依赖 , 否则会触发 二者 之间的循环调用 , 导致系统崩溃 ;

3.13 模板模式

        介绍:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。主要是用来解决复用和扩展两个问题

        场景:1.多个子类有共同的方法,且逻辑基本相同

                   2.可以把核心的算法和重要的功能设计为模板方法,子类去实现相关细节功能

                   3.系统在进行重构或者是功能优化的时候可以将子类重复的代码抽离到父类中

                   在Java Servlet、JUnit TestCase、Java InputStream、Java AbstractList中都涉及到模板模式的运用

        优点:1.通过把子类中不变的部分抽离到子类中,从而达到去除子类方法的重复代码便于维护

                   2.扩展可变部分,子类实现模板父类的某些细节,有助于模板父类的扩展

                   3.通过一个父类调用子类实现的操作,通过子类扩展增加新的行为(行为由父类控制,子类实现 符合开闭原则

         不足:1.按照设计习惯,抽象类负责声明最抽象、最一般的事物属性和方法,实现类负责完成具体的事务属性和方法,但是模板方式正好相反,子类执行的结果影响了父类的结果,会增加代码阅读的难度

                    2.每个不同的实现都需要一个子类去实现,导致类的个数不断增加,使得系统更为庞大

3.14 策略模式

        介绍:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。简单理解,应该是对于同一个业务功能,在不同的场景需求下提供不同的实现逻辑,来达到动态切换业务算法,满足不同场景的目的。同时它也有另外的好处,即优化代码结构,使其脱离大量逻辑判断,对外只提供 Context上下文,让算法与实际业务代码解耦,对使用者屏蔽底层实现逻辑

        场景:1.业务代码需要根据场景不同,切换不同的实现逻辑

                   2.避免使用多重条件判断。

                  策略模式在 JDK 中,ThreadPoolExecutor 类TreeMap

        优点:1.算法可以自由切换

                   2.扩展可变部分,子类实现模板父类的某些细节,有助于模板父类的扩展

                   3.扩展性良好

         不足:1.策略类会增多

                    2.所有策略类都需要对外暴露

3.15 责任链模式

        介绍:如果有多个对象有机会处理请求,责任链可使请求的发送者和接受者解耦,请求沿着责任链传递,直到有一个对象处理了它为止

        场景:1.多个对象可以处理同一个请求,但具体由哪个对象处理则在运行时动态决定。
                   2. 在请求处理者不明确的情况下向对个对象中的一个提交一个请求。
                   3. 需要动态处理一组对象处理请求

            常用在框架开发中,用来实现过滤器、拦截器功能,让框架的使用者在不需要修改框架源码的情况下,添加新的过滤、拦截功能。 Servlet 中的过滤器 Filter 

        优点:1.解耦 : 请求的 发送者 和 接收者 解耦 ; 接收者 是 请求的处理者 ;

                   2.动态组合 : 责任链 可以 动态组合 , 使用配置 设置责任链的 顺序及 是否出现 ; 可以随时对责任链排序 , 随时增加拆除责任链中的某个请求对象 ;

         不足:1.性能 : 如果 责任链 太长 , 或责任链中请求的 处理时间过长 , 可能会 影响性能 ;

                    2.个数 : 责任链 可能过多 ;

3.16 迭代器模式

        介绍:迭代器模式也叫游标模式,它用来遍历集合对象。这里说的“集合对象”,我们也可以叫“容器”“聚合对象”,实际上就是包含一组对象的对象,比如,数组、链表、树、图、跳表。迭代器模式主要作用是解耦容器代码和遍历代码。简单来说,不同种类的对象可能需要不同的遍历方式,我们对每一种类型的对象配一个迭代器,最后多个迭代器合成一个。

        场景:1.访问一个集合对象的内容而无需暴露它的内部表示
                   2. 为遍历不同的集合结构提供一个统一的访问接口

            JAVA 中的 iterator

        优点:1.它支持以不同的方式遍历一个聚合对象。

                   2.迭代器简化了聚合类

                   3.在同一个聚合上可以有多个遍历

                   4.在迭代器模式中,增加新的聚合类和迭代器类都很方便,无须修改原有代码

         不足:由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性

3.17 状态模式

        介绍:又称状态对象(Pattern of Objects for States)模式,是一种对象的行为模式。状态模式允许一个对象在其内部状态改变的时候改变其行为。这个对象看上去就像是改变了它的类一样。 本质:根据状态来分离和选择行为  

        场景:1.一个由一个或多个动态变化的属性导致发生不同行为的对象,在与外部事件产生互动时,其内部状态就会改变,从而使得系统的行为也随之发生变化,那么这个对象,就是有状态的对象
                   2. 代码中包含大量与对象状态有关的条件语句,像是if else或switch case语句,且这些条件执行与否依赖于该对象的状态

        优点:1.简化应用逻辑控, 把负责逻辑控制的代码分散到单独的状态类中,不用再关注代码执行状态的逻辑,只需要关注整个对象的状态就好,使得代码结构化和意图更清晰,从而简化应用的逻辑控制

                    2.更好地分离状态和行为,  状态模式通过设置所有状态类的公共接口,把状态和状态对应的行为分离开,把所有与一个特定的状态相关的行为都放入一个对象中,使得应用程序在控制的时候,只需要关心状态的切换,而不用关心这个状态对应的真正处理。

                   3.更好的扩展性, 引入了状态处理的公共接口后,使得扩展新的状态变得非常容易,只需要新增加一个实现状态处理的公共接口的实现类,然后在进行状态维护的地方,设置状态变化到这个新的状态即可

                   4.显式化进行状态转换,为不同的状态引入独立的对象,使得状态的转换变得更加明确。而且状态对象可以保证上下文不会发生内部状态不一致的情况,因为上下文中只有一个变量来记录状态对象,只要为这一个变量赋值就可以了

         不足:1.一个状态对应一个状态处理类,会使得程序引入太多的状态类,这样程序变得杂乱。

                   2.没有遵守开闭原则,引入新的新的状态会导致原有状态的修改

                   3.没有很好的处理耦合关系

3.18 访问者模式

        介绍:将作用域某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作封装 作用于 某种 数据结构 的 各元素 操作 , 数据结构指的是 List , Set , Map 等 ;在 不改变 元素类 的前提下 , 定义 作用于 元素 的操作 

        场景:1.一个对象结构包含多个类型的对象,希望对这些对象实施一些依赖其具体类型的操作
                   2.在访问者中针对每一种具体的类型都提供了一个访问操作,不同类型的对象可以有不同的访问操作

                   3.需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作污染这些对象的类,也不希望在增加新操作时修改这些类

            JDK源码中,Files 类提供了 walkFileTree() 方法。Spring源码中PropertySourcesPlaceholderConfigurer 允许我们用 Properties 文件中的属性来定义应用上下文

        优点:1.将元素对象的访问行为集中到一个访问者对象中,而不是分散在一个个的元素类中。类的职责更加清晰,有利于对象结构中元素对象的复用,相同的对象结构可以供多个不同的访问者访问

                   2.增加新的访问操作就意味着增加一个新的具体访问者类,方便扩展,无须修改源代码,符合开闭原则

         不足:1.增加新的元素类很困难。在访问者模式中,每增加一个新的元素类都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作,这违背了开闭原则的要求。

                   2.破坏封装。访问者模式要求访问者对象访问并调用每一个元素对象的操作,这意味着元素对象有时候必须暴露一些自己的内部操作和内部状态,否则无法供访问者访问。

3.19 备忘录模式

        介绍:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存着这个状态。这样以后就可将该对象恢复到原先保存的状态.备忘录模式又可以分为“白箱”备忘录模式和“黑箱”备忘录模式

        场景:1.提供一个可回滚的操作
                   2.保存一个对象在某一个时刻的状态或部分状态,这样以后需要时它能够恢复到先前的状态。

                   3.如果用一个接口来让其他对象得到这些状态,将会暴露对象的实现细节并破坏对象的封装性,一个对象不希望外界直接访问其内部状态,通过负责人可以间接访问其内部状态

            Spring源码,类StateManageableMessageContext中

        优点:1.如果某个操作错误地破坏了数据的完整性,此时可以使用备忘录模式将数据恢复成原来正确的数据

                   2.备份的状态数据保存在发起人角色之外,这样发起人就不需要对各个备份的状态进行管理。而是由备忘录角色进行管理,而备忘录角色又是由管理者角色管理,符合单一职责原则

                   3.提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤,当新的状态无效或者存在问题时,可以使用先前存储起来的备忘录将状态复原。

                   4.实现了信息的封装,一个备忘录对象是一种原发器对象的表示,不会被其他代码改动,这种模式简化了原发器对象,备忘录只保存原发器的状态,采用堆栈来存储备忘录对象可以实现多次撤销操作,可以通过在负责人中定义集合对象来存储多个备忘录。

         不足:1.消耗资源。如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存。

                   2.在实际的系统中,可能需要维护多个备份,需要额外的资源,这样对资源的消耗比较严重。资源消耗过大,如果类的成员变量太多,就不可避免占用大量的内存,而且每保存一次对象的状态都需要消耗内存资源,如果知道这一点大家就容易理解为什么一些提供了撤销功能的软件在运行时所需的内存和硬盘空间比较大了

3.20 命令模式

        介绍:将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供灵敏的撤销和恢复公共能。在命令模式中,会将一个请求封装为一个对象,以便使用不同参数来表示不同的请求(即命名),同时命令模式也支持可撤销的操作

        场景:需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互;需要在不同的时间指定请求、将请求排队和执行请求;需要支持命令的撤销操作和恢复操作,需要将一组操作组合在一起,即支持宏命令

        优点:1.降低系统的耦合度

                   2.新的命令可以很容易地加入到系统中。

                   3.可以比较容易地设计一个命令队列和宏命令(组合命令)。

                   4.可以方便地实现对请求的Undo和Redo。

         不足:使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类,这将影响命令模式的使用

3.21 解释器模式

        介绍:给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解析器来解释语言中的句子。也就是说,用编译语言的方式来分析应用中的实例。这种模式实现了文法表达式处理的接口,该接口解释一个特定的上下文。

        场景:1.解释器模式适用场景 : 某个 特定类型问题 发生频率 足够高 ;
                   2. 日志处理 : 使用 脚本语言 或 编程语言 处理日志时 , 有很多服务 会产生 大量的日志 , 需要 对日志进行解析 , 生成报表 ;各个服务的日志格式不同 , 数据中的要素相同 , 这种情况下 , 通过程序解决上述问题 , 主要的解决方案就是使用解释器模式 ;

            Spring 框架中 SpelExpressionParser 就使用解释器模式。日常项目中 , 解释器模式使用情况很少 ;解释器一般是 开源包 , 如 Express4J , JEP ;

        优点:1.扩展性好。由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法

                   2.容易实现。在语法树中的每个表达式节点类都是相似的,所以实现其文法较为容易

         不足:1.执行效率较低。解释器模式中通常使用大量的循环和递归调用,当要解释的句子较复杂时,其运行速度很慢,且代码的调试过程也比较麻烦。

                   2.会引起类膨胀。解释器模式中的每条规则至少需要定义一个类,当包含的文法规则很多时,类的个数将急剧增加,导致系统难以管理与维护。

                   3.可应用的场景比较少。在软件开发中,需要定义语言文法的应用实例非常少,所以这种模式很少被使用到。

3.22 中介模式

        介绍:又叫做调停模式,定义一个封装一组对象如何交互的对象 ,通过使对象明确地相互引用 , 促进松散耦合 , 允许独立改变它们之间的 交互 ;比如我们各种设备之间的通信,就是通过服务器作为中介对象来进行交互

        场景:1.系统中对象之间存在复杂的引用关系,系统结构混乱且难以理解

                   2. 一个对象由于引用了其他很多对象并且直接和这些对象通信,导致难以复用该对象

                   3.需要通过一个中间类来封装多个类中的行为,但又不想生成太多的子类

           在MVC框架中,控制器(Controller)就是模型(Model)和视图(View)之间的中介者

        优点:1.遵守单一职责原则,各个组件的职责都可以保持克制和单一

                   2.遵守开闭原则,各个组件的代码不需要修改,但是他们的行为的可以通过实现中介类来做扩展

                   3.遵守迪米特法则,各个组件之间无需知晓对方的知识,只需要关注和中介的基础交互即可

         不足:组件的可扩展、可维护,是将复杂度转移到中介对象上为代价,因此如果不加控制和设计,中介对象很容已成为一个“上帝对象”,啥都要管,谁都不敢改动

3.23 抽象工厂模式

        介绍:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类

        场景:1.客户端(应用层)不依赖与产品类示例如何被创建、实现等细节

                   2.强调一系列相关的产品对象(数据同一产品族)一起使用创建对象需要大量的重复代码

                   3.提供一个产品类的库,所有的产品以同样的接口出现,使得客户端不依赖于具体实现

           Spring 中,BeanFactory 是用于管理 Bean 的一个工厂,所有工厂都是 BeanFactory 的子类

        优点:1.具体产品在应用层的代码隔离,无需关系创建的细节

                   2.将一个系列的产品统一到一起创建

         不足:1.规定了所有可能被创建的产品集合,产品族中扩展新的产品困难

                    2.增加了系统的抽象性和理解难度

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值