精华内容
下载资源
问答
  • Java常见五种设计模式
    千次阅读
    2019-09-10 13:45:43

    1 工厂模式

    常用的为静态工厂模式,类似于工具类,只负责输入输出的功能,静态的好处是不用去实例化这个工厂,可以直接调用里面的方法。

    2 静态工厂模式

    典型的是service层的模式,通过接口和实现类来实现产品的功能。这样的好处是不用修改原来的代码,只需要新增接口和新增实现方法就可以了。

    3 单例模式

    在内部创建一个实例,所有方法都在这个实例上改动,因为这个实例化只有一次,所以每次都指向同一个实例,避免了反复的创建对象和内存的浪费,缺点是拓展性差,在对象多元化的场景不适用。

    4 建造者模式

    通过链式调用来创建和赋值对象,注解@Accessors就是如此,方便快捷。

    5 原型模式

    通过实现CloneAble来克隆对象,这种创建对象不必实现构造方法等,因为是直接复制字节流实现的,但是实际应用作用不大。

    更多相关内容
  • Java常见设计模式总结

    万次阅读 多人点赞 2021-09-18 17:18:54
    设计模式是一套经过反复使用的代码设计经验,目的是为了重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式于己于人于系统都...总体来说,设计模式分为三大类:5创建型模式、7结构型模式、11行为型模式

     一、设计模式总述:

    1、什么是设计模式:

            设计模式是一套经过反复使用的代码设计经验,目的是为了重用代码、让代码更容易被他人理解、保证代码可靠性。 设计模式于己于人于系统都是多赢的,它使得代码编写真正工程化,它是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现实中都有相应的原理来与之对应,每种模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。总体来说,设计模式分为三大类:

    • 创建型模式:共5种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式
    • 结构型模式:共7种:适配器模式、装饰器模式、代理模式、桥接模式、外观模式、组合模式、享元模式
    • 行为型模式:共11种:策略模式、模板方法模式、观察者模式、责任链模式、访问者模式、中介者模式、迭代器模式、命令模式、状态模式、备忘录模式、解释器模式

    其实还有两类:并发型模式和线程池模式,用一个图片来整体描述一下:

    2、设计模式的六大原则:

    (1)开闭原则 (Open Close Principle) :

            开闭原则指的是对扩展开放,对修改关闭。在对程序进行扩展的时候,不能去修改原有的代码,想要达到这样的效果,我们就需要使用接口或者抽象类

    (2)依赖倒转原则 (Dependence Inversion Principle):

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

    (3)里氏替换原则 (Liskov Substitution Principle) :

            里氏替换原则是继承与复用的基石,只有当子类可以替换掉基类,且系统的功能不受影响时,基类才能被复用,而子类也能够在基础类上增加新的行为。所以里氏替换原则指的是任何基类可以出现的地方,子类一定可以出现。

            里氏替换原则是对 “开闭原则” 的补充,实现 “开闭原则” 的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏替换原则是对实现抽象化的具体步骤的规范。

    (4)接口隔离原则 (Interface Segregation Principle):

            使用多个隔离的接口,比使用单个接口要好,降低接口之间的耦合度与依赖,方便升级和维护方便

    (5)迪米特原则 (Demeter Principle):

            迪米特原则,也叫最少知道原则,指的是一个类应当尽量减少与其他实体进行相互作用,使得系统功能模块相对独立,降低耦合关系。该原则的初衷是降低类的耦合,虽然可以避免与非直接的类通信,但是要通信,就必然会通过一个“中介”来发生关系,过分的使用迪米特原则,会产生大量的中介和传递类,导致系统复杂度变大,所以采用迪米特法则时要反复权衡,既要做到结构清晰,又要高内聚低耦合。

    (6)合成复用原则 (Composite Reuse Principle):

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

    二、Java的23种设计模式:

            接下来我们详细介绍Java中23种设计模式的概念,应用场景等情况,并结合他们的特点及设计模式的原则进行分析

    1、创建型-工厂方法模式:

    工厂方法模式分为三种:

    (1)简单工厂模式:

    建立一个工厂类,并定义一个接口对实现了同一接口的产品类进行创建。首先看下关系图:

    (2)工厂方法模式:

    工厂方法模式是对简单工厂模式的改进,简单工厂的缺陷在于不符合“开闭原则”,每次添加新产品类就需要修改工厂类,不利于系统的扩展维护。而工厂方法将工厂抽象化,并定义一个创建对象的接口。每增加新产品,只需增加该产品以及对应的具体实现工厂类,由具体工厂类决定要实例化的产品是哪个,将对象的创建与实例化延迟到子类,这样工厂的设计就符合“开闭原则”了,扩展时不必去修改原来的代码。UML关系图如下:

     (3)静态工厂方法模式:

    静态工厂模式是将工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。

    工厂方法模式详情文章:Java设计模式之创建型:工厂模式详解(简单工厂+工厂方法+抽象工厂)

    2、创建型-抽象工厂模式:

            抽象工厂模式主要用于创建相关对象的家族。当一个产品族中需要被设计在一起工作时,通过抽象工厂模式,能够保证客户端始终只使用同一个产品族中的对象;并且通过隔离具体类的生成,使得客户端不需要明确指定具体生成类;所有的具体工厂都实现了抽象工厂中定义的公共接口,因此只需要改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。

            但该模式的缺点在于添加新的行为时比较麻烦,如果需要添加一个新产品族对象时,需要更改接口及其下所有子类,这必然会带来很大的麻烦。

            UML结构图如下:

    抽象工厂模式详情:Java设计模式之创建型:工厂模式详解(简单工厂+工厂方法+抽象工厂)

    3、创建型-建造者模式:

             建造者模式将复杂产品的创建步骤分解在在不同的方法中,使得创建过程更加清晰,从而更精确控制复杂对象的产生过程;通过隔离复杂对象的构建与使用,也就是将产品的创建与产品本身分离开来,使得同样的构建过程可以创建不同的对象;并且每个具体建造者都相互独立,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。UML结构图如下:

     建造者模式详情:Java设计模式之创建型:建造者模式

    4、创建型-单例模式:

            单例模式可以确保系统中某个类只有一个实例,该类自行实例化并向整个系统提供这个实例的公共访问点,除了该公共访问点,不能通过其他途径访问该实例。单例模式的优点在于:

    • 系统中只存在一个共用的实例对象,无需频繁创建和销毁对象,节约了系统资源,提高系统的性能
    • 可以严格控制客户怎么样以及何时访问单例对象。

    单例模式的写法有好几种,主要有三种:懒汉式单例、饿汉式单例、登记式单例。

    单例模式详情:Java设计模式之创建型:单例模式

    5、创建型-原型模式:

            原型模式也是用于对象的创建,通过将一个对象作为原型,对其进行复制克隆,产生一个与源对象类似的新对象。UML类图如下:

     在 Java 中,原型模式的核心是就是原型类 Prototype,Prototype 类需要具备以下两个条件:

    • 实现 Cloneable 接口:
    • 重写 Object 类中的 clone() 方法,用于返回对象的拷贝;

    Object 类中的 clone() 方法默认是浅拷贝,如果想要深拷贝对象,则需要在 clone() 方法中自定义自己的复制逻辑。

    • 浅复制:将一个对象复制后,基本数据类型的变量会重新创建,而引用类型指向的还是原对象所指向的内存地址。
    • 深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。

            使用原型模式进行创建对象不仅简化对象的创建步骤,还比 new 方式创建对象的性能要好的多,因为 Object 类的 clone() 方法是一个本地方法,直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显;

    原型模式详情:Java设计模式之创建型:原型模式

            

            上面我们介绍了5种创建型模式,下面我们就开始介绍下7种结构型模式:适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式。其中对象的适配器模式是各种模式的起源,如下图:

    6、结构型-适配器模式:

            适配器模式主要用于将一个类或者接口转化成客户端希望的格式,使得原本不兼容的类可以在一起工作,将目标类和适配者类解耦;同时也符合“开闭原则”,可以在不修改原代码的基础上增加新的适配器类;将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性,但是缺点在于更换适配器的实现过程比较复杂。

            所以,适配器模式比较适合以下场景:

    • (1)系统需要使用现有的类,而这些类的接口不符合系统的接口。
    • (2)使用第三方组件,组件接口定义和自己定义的不同,不希望修改自己的接口,但是要使用第三方组件接口的功能。

    下面有个非常形象的例子很好地说明了什么是适配器模式:

    适配器模式的主要实现有三种:类的适配器模式、对象的适配器模式、接口的适配器模式。三者的使用场景如下:

    • 类的适配器模式:当希望将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。
    • 对象的适配器模式:当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个Wrapper类,持有原类的一个实例,在Wrapper类的方法中,调用实例的方法就行。
    • 接口的适配器模式:当不希望实现一个接口中所有的方法时,可以创建一个抽象类Wrapper,实现所有方法,我们写别的类的时候,继承抽象类即可。

    适配器模式详情:Java设计模式之结构型:适配器模式

    7、结构型-装饰器模式:

            装饰器模式可以动态给对象添加一些额外的职责从而实现功能的拓展,在运行时选择不同的装饰器,从而实现不同的行为;比使用继承更加灵活,通过对不同的装饰类进行排列组合,创造出很多不同行为,得到功能更为强大的对象;符合“开闭原则”,被装饰类与装饰类独立变化,用户可以根据需要增加新的装饰类和被装饰类,在使用时再对其进行组合,原有代码无须改变。装饰器模式的UML结构图如下:

            但是装饰器模式也存在缺点,首先会产生很多的小对象,增加了系统的复杂性,第二是排错比较困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。

    装饰器模式详情:Java设计模式之结构型:装饰器模式

    8、结构型-代理模式:

            代理模式的设计动机是通过代理对象来访问真实对象,通过建立一个对象代理类,由代理对象控制原对象的引用,从而实现对真实对象的操作。在代理模式中,代理对象主要起到一个中介的作用,用于协调与连接调用者(即客户端)和被调用者(即目标对象),在一定程度上降低了系统的耦合度,同时也保护了目标对象。但缺点是在调用者与被调用者之间增加了代理对象,可能会造成请求的处理速度变慢。UML结构图如下:

    代理模式详情:Java设计模式之结构型:代理模式

    9、结构型-桥接模式:

            桥接模式将系统的抽象部分与实现部分分离解耦,使他们可以独立的变化。为了达到让抽象部分和实现部分独立变化的目的,桥接模式使用组合关系来代替继承关系,抽象部分拥有实现部分的接口对象,从而能够通过这个接口对象来调用具体实现部分的功能。也就是说,桥接模式中的桥接是一个单方向的关系,只能够抽象部分去使用实现部分的对象,而不能反过来。 

            桥接模式符合“开闭原则”,提高了系统的可拓展性,在两个变化维度中任意扩展一个维度,都不需要修改原来的系统;并且实现细节对客户不透明,可以隐藏实现细节。但是由于聚合关系建立在抽象层,要求开发者针对抽象进行编程,这增加系统的理解和设计难度。桥接模式的UML结构图如下:

            就像在Java中我们使用 JDBC 连接数据库时,在各个数据库之间进行切换,基本不需要动太多的代码,原因就是使用了桥接模式,JDBC 提供统一接口,每个数据库提供各自的实现,然后由桥接类创建一个连接数据库的驱动,使用某一个数据库的时候只需要切换一下就行。JDBC 的结构图如下:

             在 JDBC 中,桥接模式的实现化角色 (Implementor) 为的 Driver 接口,具体实现化 (Concrete Implementor) 角色对应 MysqlDriver、OracleDriver 和 MariadbDriver,扩展抽象化 (Refined Abstraction) 角色对应 DriverManager,不具有抽象化 (Abstraction) 角色作为扩展抽象化角色的父类。

    桥接模式详情:Java设计模式之结构型:桥接模式

    10、结构型-外观模式:

            外观模式通过对客户端提供一个统一的接口,用于访问子系统中的一群接口。使用外观模式有以下几点好处:

    (1)更加易用:使得子系统更加易用,客户端不再需要了解子系统内部的实现,也不需要跟众多子系统内部的模块进行交互,只需要跟外观类交互就可以了;

    (2)松散耦合:将客户端与子系统解耦,让子系统内部的模块能更容易扩展和维护。

    (3)更好的划分访问层次:通过合理使用 Facade,可以更好地划分访问的层次,有些方法是对系统外的,有些方法是系统内部使用的。把需要暴露给外部的功能集中到门面中,这样既方便客户端使用,也很好地隐藏了内部的细节。

            但是如果外观模式对子系统类做太多的限制则减少了可变性和灵活性,所以外观模式适用于为复杂子系统提供一个简单接口,提高系统的易用性场景 以及 引入外观模式将子系统与客户端进行解耦,提高子系统的独立性和可移植性。

            外观模式的UML结构图如下:

    外观模式详情: Java设计模式之结构型:外观模式

    11、结构型-组合模式:

            组合模式将叶子对象和容器对象进行递归组合,形成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性,能够像处理叶子对象一样来处理组合对象,无需进行区分,从而使用户程序能够与复杂元素的内部结构进行解耦。

            组合模式最关键的地方是叶子对象和组合对象实现了相同的抽象构建类,它既可表示叶子对象,也可表示容器对象,客户仅仅需要针对这个抽象构建类进行编程,这就是组合模式能够将叶子节点和对象节点进行一致处理的原因。组合模式的UML结构图如下:

    组合模式详情: Java设计模式之结构型:组合模式

    12、结构型-享元模式:

            享元模式通过共享技术有效地支持细粒度、状态变化小的对象复用,当系统中存在有多个相同的对象,那么只共享一份,不必每个都去实例化一个对象,极大地减少系统中对象的数量,从而节省资源。

            享元模式的核心是享元工厂类,享元工厂类维护了一个对象存储池,当客户端需要对象时,首先从享元池中获取,如果享元池中存在对象实例则直接返回,如果享元池中不存在,则创建一个新的享元对象实例返回给用户,并在享元池中保存该新增对象,这点有些单例的意思。

            工厂类通常会使用集合类型来保存对象,如 HashMap、Hashtable、Vector 等等,在 Java 中,数据库连接池、线程池等都是用享元模式的应用。

            享元模式的UML结构图如下:

             Java 中,String 类型就是使用享元模式,String 对象是 final 类型,对象一旦创建就不可改变。而 Java 的字符串常量都是存在字符串常量池中的,JVM 会确保一个字符串常量在常量池中只有一个拷贝。

            而且提到共享池,我们也很容易联想到 Java 里面的JDBC连接池,通过连接池的管理,实现了数据库连接的共享,不需要每一次都重新创建连接,节省了数据库重新创建的开销,提升了系统的性能!

    享元模式详情:Java设计模式之结构型:享元模式

            前面我们介绍了7种结构型设计模式,接下来我们介绍一下11种行为型设计模式:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。先来张图,看看这11中模式的关系:

     13、行为型-策略模式:

            将类中经常改变或者可能改变的部分提取为作为一个抽象策略接口类,然后在类中包含这个对象的实例,这样类实例在运行时就可以随意调用实现了这个接口的类的行为。

            比如定义一系列的算法,把每一个算法封装起来,并且使它们可相互替换,使得算法可独立于使用它的客户而变化,这就是策略模式。UML结构图如下:

            策略模式的优点在于可以动态改变对象的行为;但缺点是会产生很多策略类,并且策略模式的决定权在用户,系统只是提供不同算法的实现,所以客户端必须知道所有的策略类,并自行决定使用哪一个策略类; 

            策略模式适用用于以下几种场景:

    • (1)应用程序需要实现特定的功能服务,而该程序有多种实现方式使用,所以需要动态地在几种算法中选择一种
    • (2)一个类定义了多种行为算法,并且这些行为在类的操作中以多个条件语句的形式出现,就可以将相关的条件分支移入它们各自的Strategy类中以代替这些条件语句。

    策略模式详情:Java设计模式之行为型:策略模式

    14、行为型-模板方法:

            模板方法是基于继承实现的,在抽象父类中声明一个模板方法,并在模板方法中定义算法的执行步骤(即算法骨架)。在模板方法模式中,可以将子类共性的部分放在父类中实现,而特性的部分延迟到子类中实现,只需将特性部分在父类中声明成抽象方法即可,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤,不同的子类可以以不同的方式来实现这些逻辑。

            模板方法模式的优点在于符合“开闭原则”,也能够实现代码复用,将不变的行为转移到父类,去除子类中的重复代码。但是缺点是不同的实现都需要定义一个子类,导致类的个数的增加使得系统更加庞大,设计更加抽象。模板方法模式的UML图如下:

    模板方法详情:Java设计模式之行为型:模板方法模式

    15、行为型-责任链模式:

            职责链可以将请求的处理者组织成一条链,并将请求沿着链传递,如果某个处理者能够处理请求则处理,否则将该请求交由上级处理。客户端只需将请求发送到职责链上,无须关注请求的处理细节,通过职责链将请求的发送者和处理者解耦了,这也是职责链的设计动机。        

           职责链模式可以简化对象间的相互连接,因为客户端和处理者都没有对方明确的信息,同时处理者也不知道职责链中的结构,处理者只需保存一个指向后续者的引用,而不需要保存所有候选者的引用。

            另外职责链模式增加了系统的灵活性,我们可以任意增加或更改处理者,甚至更改处理者的顺序,不过有可能会导致一个请求无论如何也得不到处理,因为它可能被放置在链末端。

    所以责任链模式有以下几个优点:

    • (1)降低耦合度,将请求的发送者和接收者解耦。反映在代码上就是不需要在类中写很多丑陋的 if….else 语句,如果用了职责链,相当于我们面对一个黑箱,只需将请求递交给其中一个处理者,然后让黑箱内部去负责传递就可以了。
    • (2)简化了对象,使得对象不需要链的结构。
    • (3)增加系统的灵活性,通过改变链内的成员或者调动他们的次序,允许动态地新增或者删除处理者
    • (4)增加新的请求处理类很方便。

    但是责任链模式也存在一些缺点:

    • (1)不能保证请求一定被成功处理
    • (2)系统性能将受到一定影响,并且可能会造成循环调用。
    • (3)可能不容易观察运行时的特征,而且在进行代码调试时不太方便,有碍于除错。

            责任链模式的UML结构图如下:

    责任链模式详情:Java设计模式之行为型:责任链模式

    16、行为型-观察者模式:

            观察者模式又称为 发布-订阅模式,定义了对象之间一对多依赖关系,当目标对象(被观察者)的状态发生改变时,它的所有依赖者(观察者)都会收到通知。一个观察目标可以对应多个观察者,而这些观察者之间没有相互联系,所以能够根据需要增加和删除观察者,使得系统更易于扩展,符合开闭原则;并且观察者模式让目标对象和观察者松耦合,虽然彼此不清楚对方的细节,但依然可以交互,目标对象只知道一个具体的观察者列表,但并不认识任何一个具体的观察者,它只知道他们都有一个共同的接口。

            但观察者模式的缺点在于如果存在很多个被观察者的话,那么将需要花费一定时间通知所有的观察者,如果观察者与被观察者之间存在循环依赖的话,那么可能导致系统崩溃,并且观察者模式没有相应的机制让观察者知道被观察对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。观察者模式的UML结构图如下:

     观察者模式详情:Java设计模式之行为型:观察者模式

    17、行为型-访问者模式:

            访问者模式就是一种分离对象数据结构与行为 (基于数据结构的操作) 的方法,通过这种分离,达到为一个被访问者动态添加新的操作而无需做其它修改的效果,使得添加作用于这些数据结构的新操作变得简单,并且不需要改变各数据结构,为不同类型的数据结构提供多种访问操作方式,这样是访问者模式的设计动机。

            除了使新增访问操作变得更加简单,也能够在不修改现有类的层次结构下,定义该类层次结构的操作,并将有关元素对象的访问行为集中到一个访问者对象中,而不是分散搞一个个的元素类中。

           但访问者模式的缺点在于让增加新的元素类变得困难,每增加一个新的元素类都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作,违背了“开闭原则”的要求;

            所以访问者模式适用于对象结构中很少改变,但经常需要在此对象结构上定义新的操作的系统,使得算法操作的增加变得简单;或者需要对一个对象结构中进行很多不同并且不相关的操作,并且需要避免让这些操作污染这些对象,也不希望在增加新操作时修改这些类的场景。

            访问者模式的UML结构图如下:

            从上面的 UML 结构图中我们可以看出,访问者模式主要分为两个层次结构,一个是访问者层次结构,提供了抽象访问者和具体访问者,主要用于声明一些操作;一个是元素层次结构,提供了抽象元素和具体元素,主要用于声明 accept 操作;而对象结构 ObjectStructure 作为两者的桥梁,存储了不同类型的对象,以便不同的访问者来访问,相同访问者可以以不同的方式访问不同的元素,所以在访问者模式中增加新的访问者无需修改现有代码,可扩展行强。

            在访问者模式使用了双分派技术,所谓双分派技术就是在选择方法的时候,不仅仅要根据消息接收者的运行时区别,还要根据参数的运行时区别。在访问者模式中,客户端将具体状态当做参数传递给具体访问者,这里完成第一次分派,然后具体访问者作为参数的“具体状态”中的方法,同时也将自己this作为参数传递进去,这里就完成了第二次分派。双分派意味着得到的执行操作决定于请求的种类和接受者的类型。

     访问者模式详情:Java设计模式之行为型:访问者模式

    18、行为型-中介者模式:

             中介者模式通过中介者对象来封装一系列的对象交互,将对象间复杂的关系网状结构变成结构简单的以中介者为核心的星形结构,对象间一对多的关联转变为一对一的关联,简化对象间的关系,便于理解;各个对象之间的关系被解耦,每个对象不再和它关联的对象直接发生相互作用,而是通过中介者对象来与关联的对象进行通讯,使得对象可以相对独立地使用,提高了对象的可复用和系统的可扩展性。

            在中介者模式中,中介者类处于核心地位,它封装了系统中所有对象类之间的关系,除了简化对象间的关系,还可以对对象间的交互进行进一步的控制。中介者模式的UML结构图如下:

            但是,中介者对象封装了对象之间的关联关系,导致中介者对象变得比较庞大复杂,所承担的责任也比较多,维护起来也比较困难,它需要知道每个对象和他们之间的交互细节,如果它出问题,将会导致整个系统都会出问题。

    中介者模式详情:Java设计模式之行为型:中介者模式

    19、行为型-命令模式:

            命令模式的本质是将请求封装成对象,将发出命令与执行命令的责任分开,命令的发送者和接收者完全解耦,发送者只需知道如何发送命令,不需要关心命令是如何实现的,甚至是否执行成功都不需要理会。命令模式的关键在于引入了抽象命令接口,发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联。

            使用命令模式的优势在于降低了系统的耦合度,而且新命令可以很方便添加到系统中,也容易设计一个组合命令。但缺点在于会导致某些系统有过多的具体命令类,因为针对每一个命令都需要设计一个具体命令类。

            命令模式的UML结构图如下:

    命令模式详情: Java设计模式之行为型:命令模式

    20、行为型-状态模式:

            状态模式,就是允许对象在内部状态发生改变时改变它的行为,对象看起来就好像修改了它的类,也就是说以状态为原子来改变它的行为,而不是通过行为来改变状态。

            当对象的行为取决于它的属性时,我们称这些属性为状态,那该对象就称为状态对象。对于状态对象而言,它的行为依赖于它的状态,比如要预订房间,只有当该房间空闲时才能预订,想入住该房间也只有当你预订了该房间或者该房间为空闲时。对于这样的一个对象,当它的外部事件产生互动的时候,其内部状态就会发生变化,从而使得他的行为也随之发生变化。

            状态模式的UML结构图如下:

     从上面的UML结构图我们可以看出状态模式的优点在于:

    (1)封装了转换规则,允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块

    (2)将所有与状态有关的行为放到一个类中,可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。 

    但是状态模式的缺点在于:

    (1)需要在枚举状态之前需要确定状态种类

    (2)会导致增加系统类和对象的个数。

    (3)对 “开闭原则” 的支持并不友好,新增状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。

    所以状态模式适用于:代码中包含大量与对象状态有关的条件语句,以及对象的行为依赖于它的状态,并且可以根据它的状态改变而改变它的相关行为。

    状态模式详情:Java设计模式之行为型:状态模式

    21、行为型-备忘录模式:

            备忘录模式提供了一种恢复状态的机制,在不破坏封装的前提下,捕获对象的某个时刻内部状态,并保存在该对象之外,保证该对象能够恢复到某个历史状态;备忘录模式将保存的细节封装在备忘录中,除了创建它的创建者之外其他对象都不能访问它,并且实现了即使要改变保存的细节也不影响客户端。但是备忘录模式都是多状态和多备份的,会早用较多的内存,消耗资源。备忘录模式的额UML结构图如下:

             备忘录模式的核心就是备忘录 Memento,在备忘录中存储的就是原发器 Originator 的部分或者所有的状态信息,而这些状态信息是不能够被其他对象所访问的,也就是说我们是不能使用备忘录之外的对象来存储这些状态信息,如果暴漏了内部状态信息就违反了封装的原则,故备忘录除了原发器外其他对象都不可以访问。所以为了实现备忘录模式的封装,我们需要对备忘录的访问做些控制:

    (1)对原发器:可以访问备忘录里的所有信息。

    (2)对负责人 caretaker:不可以访问备忘录里面的数据,但是他可以保存备忘录并且可以将备忘录传递给其他对象。

    (3)其他对象:不可访问也不可以保存,它只负责接收从负责人那里传递过来的备忘录同时恢复原发器的状态。

    备忘录模式详情:Java设计模式之行为型:备忘录模式

    22、行为型-迭代器模式:

            迭代器模式提供一种访问集合中的各个元素,而不暴露其内部表示的方法。将在元素之间游走的职责交给迭代器,而不是集合对象,从而简化集合容器的实现,让集合容器专注于在它所应该专注的事情上,更加符合单一职责原则,避免在集合容器的抽象接口层中充斥着各种不同的遍历操作。迭代器模式的UML结构图如下:

    迭代器模式详情:Java设计模式之行为型:迭代器模式

    23、行为型-解释器模式:

            解释器模式,就是定义语言的文法,并建立一个解释器来解释该语言中的句子,通过构建解释器,解决某一频繁发生的特定类型问题实例。

            解释器模式描述了如何构成一个简单的语言解释器,主要应用在使用面向对象语言开发的编译器中,它描述了如何为简单的语言定义一个文法,如何在该语言中表示一个句子,以及如何解释这些句子。    

            解释器模式中除了能够使用文法规则来定义一个语言,还能通过使用抽象语法树来更加直观表示、更好地地表示一个语言的构成,每一颗抽象语法树对应一个语言实例。抽象语法树描述了如何构成一个复杂的句子,通过对抽象语法树的分析,可以识别出语言中的终结符和非终结符类。 在解释器模式中由于每一种终结符表达式、非终结符表达式都会有一个具体的实例与之相对应,所以系统的扩展性比较好。

            解释器模式的UML如下:

     解释器模式详情:Java设计模式之行为型:解释器模式


    相关推荐阅读:

    Spring常见面试题总结

    SpringMVC常见面试题总结

    Mybatis常见面试题总结

    MySQL常见面试题总结

    Redis常见面试题总结

    RabbitMQ消息队列常见面试题总结

    ElasticSearch搜索引擎常见面试题总结

    计算机网络常见面试题总结

    操作系统常见面试题总结

    Java基础、集合、多线程常见面试题总结

    Java虚拟机常见面试题总结

    Java常见设计模式总结

    海量数据处理的方法总结


    参考文章:

    Java之美[从菜鸟到高手演变]之设计模式

    Java之美[从菜鸟到高手演变]之设计模式二

    Java之美[从菜鸟到高手演变]之设计模式三

    Java之美[从菜鸟到高手演变]之设计模式四

    展开全文
  • 常见种设计模式

    千次阅读 2019-06-11 14:43:31
    设计模式是什么呢,在百度上从copy下来一段话: 设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的...常见种设计模式:...

    设计模式是什么呢,在百度上从copy下来一段话:
    设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
    总结一句话就是 ,设计模式就是 多年来前辈大牛们的开发设计经验的一个总结,方便后人使用。
    常见几种设计模式:

    策略模式

    策略模式主要针对判断条件居多但是判断条件相对来说简单的程序
    比如 redux中的action type的判断

    值:对应的代码
    const typeobj1 = {
    	"DIS"(state,action){
    	
    	}
    }
    const typeobj = {
    	...typeobj1,
    	"ADD"(state,action){
    		state.a = action.a;
    	},
    }
    const reducer = (state,action)=> {
    	typeobj[action.type] && typeobj[action.type](state,action)
    	return {...state}
    }
    

    观察者模式/发布订阅模式

    特点:
    1.要在开发中使用该模式,要做好封装,采用面向对象的方式
    2.要能够监听不同的类型;
    3.在发布动作触发的时候,要能够给所有的订阅者传递信息
    采用面向对象的方式的话,我们需要确定一个实例中应该有哪些属性和方法,我们需要一个events属性用来存储所有的订阅者,但是这里的list不是一个数组,应该是一个对象,因为我们需要对区分不同类型的订阅者,该对象中的属性名将作为订阅者的类型。还需要有on订阅方法,该方法用来执行订阅动作,这里的订阅动作不仅添加订阅者,还需要区分类型,因此会接收两个参数。一个字符串,一个函数。再需要一个发布动作emit,该方法需要接收一个字符串和一个载荷作为参数,字符串决定了触发何种类型的订阅者,载荷可以作为传递给各个订阅者的参数

    class watch {
    	constructor(){
    		this.events =[  ]/ {type:[listener,listener]}  //
    	}
    	on(type,listener){//订阅
    			if(!Array.isArray(this.events[type]) {
    				this.events[type] = []
    			}
    			this.events[type].push(listener)
    	}
    	emit(type,...reset){//发布
    		this.events.type.forEach(item=>{
    			item.call(null,...reset);
    		})
    	}
    }
    
    const  w = new Watch()
    w.on('ok',(msg)=>{
    	console.log(msg)
    })
    w.emit('ok','helloword')
    

    中间件模式

    【fn,fn,fn,fn】
    利用中间件模式将异步转为同步

    const arr =[
    	(next)=>console.log(1),next()
    	(next)=>console.log(2),next()
    	(next)=>{
    		setTimeout(()=>console.log(3),next(),2000)
    	},
    	()=>console.log(4)
    ]
    function run(arr){
    	let index = 0;
    	const next = ()=>{
    		index ++;
    		arr[index](next);
    	}
    	arr[0](next)
    }
    

    其他设计模式列表:

    工厂模式

    原型模式

    过滤器模式

    外观模式

    代理模式

    MVC模式

    拦截过滤器模式

    空对象模式

    装饰器模式

    具体内容待完善…

    展开全文
  • 常见的几种设计模式

    千次阅读 多人点赞 2019-02-28 09:45:27
    文章目录单例模式为什么会有单例设计模式?应用spring中IOC解决的问题设计思想工厂模式简单工厂模式工厂方法模式观察者模式观察者模式的定义装饰模式模板方法定义:主要的作用:优点:缺点:应用场景:适配器模式...

    单例模式

    为什么会有单例设计模式?

    单例模式主要是为了避免因为创建了多个实例造成资源的浪费,且多个实例由于多次调用容易导致结果的出错。而使用单例模式能够保证整个应用只有一个实例

    应用spring中IOC

    在整个应用中(一般只用一个IOC容器),只创建Bean的一个实例,多次注入同一具体类时都是注入同一个实例。

    IOC容器来实现过程简述如下:

    ​ 当需要注入Bean时,IOC容器首先解析配置找到具体类,然后判断其作用域(@Scope注解);

    ​ 默认的单例@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON),则查找容器中之前有没有为其创建了Bean实例;如果有则直接注入该Bean实例,如果没有生成一个放到容器中保存

    ConcurrentHashMap -- map.put(bean_id, bean)),再注入。

    注:其中解析配置查找具体类、生成Bean实例和注入过程都是通过Java反射机制实现的。

    解决的问题

    1. 可以保证一个类在内存中的对象的唯一性,在一些常用个工具类中,线程池,缓存和数据库,账号登陆系统,配置文件,等程序中之允许我们创建一个对象,
    2. 如果创建多个对象会造成资源的严重浪费,也有可能会造成程序的错误。
    3. 比如我们共享一个配置文件,当我们创建一个对象A修改其中的内容的时候,并不会真正改变类B.我们可能会想到把共享数据设置为静态数据。
    4. 但是我们都知道静态数据的生命周期是很长的,假如ConfigFile中有很多数据时,如果将其全部设成静态的,那将是对内存的极大损耗。

    设计思想

    1. 不允许其它的程序用New对象
    2. 在该类中创建对象
    3. 对外提供一个可以让其他程序获取该对象的方法

    ①懒汉式

    /**
     @author maxu
     @date 2018/11/3
    优点:从它的实现中我们可以看到,这种方式的实现比较简单,在类加载的时候就完成了实例化,避免了线程的同步
    *	 问题。
    缺点:由于在类加载的时候就实例化了,所以没有达到Lazy Loading(懒加载)的效果,也就是说可能我没有用到
    *	  这个实例,但是它也会加载,会造成内存的浪费(但是这个浪费可以忽略,所以这种方式也是推荐使用的)。
    */
    public class Singleton {
    
        private static Singleton instance = new Singleton();
        private Singleton() {}
        public static Singleton getInstance() {
            return instance;
        }
    }  
    

    ②饿汉式

    public class Singleton {
    
        private static Singleton instance = null;
        private Singleton() {}
        public static Singleton getInstance() {
            if (null == instance) {
                instance = new Singleton();
            }
            return instance;
        }
    }
    

    ③双重校验锁

    public class Singleton {
        private static Singleton instance = null;
    
        private Singleton() {
        }
    
        public static synchronized Singleton getInstance() {
            if (null == instance) {
                synchronized (Singleton.class) {
                    if (null == instance) {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    
    }
    

    ④静态内部类

    /**
    * 这种方式跟饿汉式方式采用的机制类似,但又有不同。两者都是采用了类装载的机制来保证初始化实例时只有一个线程。不同
    * 的地方在饿汉式方式是只要Singleton类被装载就会实例化,没有Lazy-Loading的作用,而静态内部类方式在Singleton类被装载时
    * 并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonHolder类,从而完成Singleton的实例化。
    * 类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的
    * 优点:避免了线程不安全,延迟加载,效率高。
    */
    public class Singleton {
    
    
        private Singleton() {
        }
    
        private static class Sinletonleader {
            private static Singleton singleton = new Singleton();
        }
    
        public Singleton getInstance() {
            return Sinletonleader.singleton;
        }
    }
    

    ⑤枚举

    /**
    * SingletonEnum.instance.method();
    * 借助JDK1.5中添加的枚举来实现单例模式。不仅能避免多线程同步问题,
    * 而且还能防止反序列化重新创建新的对象。可能是因为枚举在JDK1.5中才添加,所以在实际项目开发中
    * 很少见人这么写过,这种方式也是最好的一种方式,如果在开发中JDK满足要求的情况下建议使用这种方式。
    */
    public enum Singleton {
        instance;
    
        private Singleton() {
        }
    
        public void method() {
        }
    }
    

    工厂模式

    简单工厂模式

    ​ 是由一个对象根据收到的消息决定要创建哪一个类的对象实例。

    ​ 使用场景:工厂类负责创建的对象比较少,客户只需要传入工厂参数,对于如何创建对象不关心,违反了高内聚低耦合的原则。

    ​ 最大的优点:工厂类包含了必要的逻辑根据用户的需要逻辑动态实例化相关的类。

    ​ 缺点:只能生产同一级结构的产品,在添加新产品的时候需要修改代码

    在这里插入图片描述

    工厂方法模式

    ​ 定义一个创建对象的工厂接口,让子类去决定实例化哪一个类,将实例化的工作延迟到子类当中。

    场景:数据库访问的时候用户不知到最后系统采用那一个数据库以及数据库有什么变化。

    特点:用来产生统一等级下结构的产品,支持增加任意的产品。

    在这里插入图片描述


    观察者模式

    观察者模式的定义

    • 在对象之间定义一对多的依赖,当一个对象改变状态的时候,依赖它的对象就会收到通知,并自动更新。
    • 其实就是发布订阅模式,发布者发布信息,订阅者获取信息,订阅了就能收到信息,没订阅就收不到信息。

    首先定义一个被观察者的接口Observerable

    /**
    * @author maxu
    * @date 2018/11/3
    * 抽象者被观察者方法
    */
    public interface Observerable {
        void registerObserver(Observer observer);
        void removeObserver(Observer observer);
        void notifyObserver();
    
    }
    
    /**
    * @author maxu
    * @date 2018/11/3
    * 定义了一个update()方法,当被观察者调用notifyObservers()方法时,观察者的update()方法会被回调。
    * 观察者
    */
    public interface Observer {
        void update(String message);
    }
    
    /**
    * @author maxu
    * @date 2018/11/3
    */
    public class WechatServer implements Observerable {
        /**
         * 注意到这个List集合的泛型是Observer
         */
        // 这里保存着所有注册的观察者
        private List<Observer> list;
        private String message;
    
        public WechatServer() {
            list = new ArrayList<>();
        }
    
    	// 注册观察者
        @Override
        public void registerObserver(Observer observer) {
            list.add(observer);
        }
    
        // 移除观察者
        @Override
        public void removeObserver(Observer observer) {
            if (!list.isEmpty()) {
                list.remove(observer);
            }
        }
    
        // 通知所有的观察者的具体实现
        @Override
        public void notifyObserver() {
            for (Observer observer : list) {
                observer.update(message);
            }
        }
    
        /**
         * 发布消息,并通知给所有观察者
         * @param message
         */
        public void setInfomation(String message) {
            this.message = message;
            notifyObserver();
        }
    }
    
    /**
    * @author maxu
    * @date 2018/11/3
    * 观察者
    */
    public class User implements Observer {
        private String name;
        private String message;
    
        public User(String name) {
            this.name = name;
        }
    
        @Override
        public void update(String message) {
            this.message = message;
            read();
        }
    
        public void read(){
            System.out.println(name + "收到的消息" + message);
        }
    }
    /**
    * @author maxu
    * @date 2018/11/3
    */
    public class Test {
        public static void main(String[] args) {
            WechatServer server = new WechatServer();
            Observer user1 = new User("张山");
            Observer user2 = new User("小马");
            Observer user3 = new User("小白");
    
            server.registerObserver(user1);
            server.registerObserver(user2);
            server.registerObserver(user3);
    
            server.setInfomation("java是最好的语言");
    
            System.out.println("----------------------------------");
            server.removeObserver(user1);
            server.setInfomation("php是最好的语言");
        }
    }
    

    装饰模式

    原有的类不能满足现有的需求,对原有类的进行增强

    装饰器模式特点在于增强,他的特点是被装饰类和所有的装饰类必须实现同一个接口,而且必须持有被装饰的对象,可以无限装饰。

    在这里插入图片描述

    Component 是一个接口,或者是一个抽象类,这就是定义我们最核心的对象,也就是最原始的对象。

    ConreteComponent这是最核心、最原始、最基本的接口或者抽象方法,它里面可不一定有抽象方法呀,

    在它的属性里必然有一个private属性指向Component。

    ConcreteDecoratorA和ConcreteDecoratorB 是两个具体的装饰类,你要把你最核心的、最原始的、最基本的东西装饰成什么。

    装饰模式是对继承的的补充,装饰模式可以解决继承膨胀的问题,继承是静态的给类增加新的功能,然而装饰模式是对类进行动态的增加新的功能。

    装饰模式还有一个有点就是很好的扩展,装饰模式通过封装一个类而不是通过继承来完成。

    简单点说,有三个继承关系 Father Son GrandSon 三个类,我要在Son类上添加新的功能?那么对GrandSon的影响呢,如果是多个GrandSon的时候,你评估就要做的很心累,所以我们可以新创建一个DectoratorSon来封装Son这个类。这样在增强Son的时候对GrandSon就不会产生影响了。

    模板方法

    定义:

    ​ 定义一个模板结构,将具体的内容延迟到子类中去实现。

    主要的作用:

    ​ 在不改变模板结构的前提下在子类中重新定义模板中的内容

    ​ 模板方法的模式是基于继承的。

    优点:

    • 提高代码的复用性
    • 将相同部分的代码放在抽象的父类中,而将不同的代码放入不同的子类中。
    • 实现反向的控制
    • 通过父类调用子类的操作,通过对子类具体实现扩展出不同的行为,实现了反向控制、符合开闭原则

    缺点:

    • 引入抽象类,每一个不同的实现都需要一个子类来实现,导致类的个数增加,从而增加了系统实现的复杂程度。

    应用场景:

    • 一次性实现一个算法的不变部分,并将可变的行为留给子类来实现。
    • 各子类中公共的行为应被提取出来并集中到一个公共的父类中避免代码重复
    • 控制子类的扩展

    在这里插入图片描述


    适配器模式(Adapter Pattern)

    定义

    • 将一个类的接口转换成用户希望的另一个接口。

    • 适配器模式剋让那些接口不兼容的类可以一起工作。

    • 通常情况下,客户端可以通过目标类的接口访问它所提供的服务。有时,现有的类可以满足客户类的功能需要,但是它所提供的接口不一定是客户类所期望的,这可能是因为现有类中方法名与目标类中定义的方法名不一致等原因所导致的。

    • 在适配器模式中,可以定义一个包装类,包装不兼容接口对象,这个包装类指的就是适配器,它所包装的对象就是适配者,就是被适配的类。

    • 适配器提供用户类所需要的接口,适配器的实现就是把客户类的请求转化为对适配者响应接口的调用。简单来说,当客户类调用适配器方法的时候,在适配器内部将调用适配者类的方法,而这个过程对客户类是透明的,客户类并不直接访问适配者类,因此,适配器可以使由于接口不兼容而不能相互工作的类一起工作。

    类适配器

    在这里插入图片描述

    public class Adapter extends Adaptee implements Target {
    	public void request() {
    		specificRequest();
    	}
    }
    

    对象适配器

    在这里插入图片描述

    public class Adapter extends Target{
        
    	private Adaptee adaptee;
    	public Adapter(Adaptee adaptee){
    		this.adaptee=adaptee;
    	}
    	public void request(){
    		adaptee.specificRequest();
    	}
    }
    

    优点

    • 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。
    • 增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性。
    • 灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合“开闭原则”。

    类适配器优缺点

    • 由于适配器类是适配者类的子类,因此可以在适配器类中置换一些适配者的方法,使得适配器的灵活性更强。
    • Java不支持多重继承的语言,一次最多只能适配一个适配者类,而且目标抽象类只能为抽象类,不能为具体类,其使用有一定的局限性,不能将一个适配者类和它的子类都适配到目标接口。

    对象适配器优缺点

    • 一个对象适配器可以把多个不同的适配者适配到同一个目标,也就是说,同一个适配器可以把适配者类和它的子类都适配到目标接口。
    • 与类适配器模式相比,要想置换适配者类的方法就不容易。如果一定要置换掉适配者类的一个或多个方法,就只好先做一个适配者类的子类,将适配者类的方法置换掉,然后再把适配者类的子类当做真正的适配者进行适配,实现过程较为复杂。

    适用环境

    • 系统需要使用现有的类,而这些类的接口不符合系统的需要。
    • 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。

    职责链模式

    • 职责链可以是一条直线、一个环或者一个树形结构,最常见的职责链是直线型,即沿着一条单向的链来传递请求。
    • 链上的每一个对象都是请求处理者,职责链模式可以将请求的处理者组织成一条链,并使请求沿着链传递,由链上的处理者对请求进行相应的处理,客户端无须关心请求的处理细节以及请求的传递,只需将请求发送到链上即可,将请求的发送者和请求的处理者解耦。这就是职责链模式的模式动机。
    • 避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。

    分析

    • 在职责链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。
    • 请求在这条链上传递,直到链上的某一个对象处理此请求为止。
    • 发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织链和分配责任。

    在这里插入图片描述

    public abstract class Handler{
    	protected Handler successor;
        
    	public void setSuccessor(Handler successor){
    		this.successor=successor;
    	}
    	
    	public abstract void handleRequest(String request);
    } 
    
    
    public class ConcreteHandler extends Handler {
        
    	public void handleRequest(String request) {
    		if(请求request满足条件) {
    			......  //处理请求;
    		} else {
    			this.successor.handleRequest(request); //转发请求
    		}
    	}
    } 
    
    

    实例

    审批假条

    某OA系统需要提供一个假条审批的模块,如果员工请假天数小于3天,主任可以审批该假条;如果员工请假天数大于等于3天,小于10天,经理可以审批;如果员工请假天数大于等于10天,小于30天,总经理可以审批;如果超过30天,总经理也不能审批,提示相应的拒绝信息。

    职责链模式的优点

    • 降低耦合度
    • 可简化对象的相互连接
    • 增强给对象指派职责的灵活性
    • 增加新的请求处理类很方便

    职责链模式的缺点

    • 不能保证请求一定被接收。
    • 系统性能将受到一定影响,而且在进行代码调试时不太方便;可能会造成循环调用。

    纯与不纯的职责链模式

    • 一个纯的职责链模式要求一个具体处理者对象只能在两个行为中选择一个:一个是承担责任,另一个是把责任推给下家。不允许出现某一个具体处理者对象在承担了一部分责任后又将责任向下传的情况。

    • 在一个纯的职责链模式里面,一个请求必须被某一个处理者对象所接收;在一个不纯的职责链模式里面,一个请求可以最终不被任何接收端对象所接收。


    代理模式

    在某些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个称之为“代理”的第三者来实现间接引用。代理对象可以在客户端和目标对象之间起到中介的作用,并且可以通过代理对象去掉客户不能看到的内容和服务或者添加客户需要的额外服务。

    动机

    通过引入一个新的对象来实现对真实对象的操作或者将新的对象作为真实对象的一个替身,这种实现机制即为代理模式,通过引入代理对象来间接访问一个对象,这就是代理模式的模式动机。

    在这里插入图片描述

    public class Proxy implements Subject {
        // 创建真实对象
        private RealSubject realSubject = new RealSubject();
        
        public void preRequest(){...}
        public void request(){
            preRequest();
            realSubject.request();
            postRequest();
        }
        public void afterRequest(){...}
    } 
    
    

    优点

    • 代理模式能够协调调用者和被调用者,在一定程度上降低了系统的耦合度。
    • 远程代理使得客户端可以访问在远程机器上的对象,远程机器可能具有更好的计算性能与处理速度,可以快速响应并处理客户端请求。
    • 虚拟代理通过使用一个小对象来代表一个大对象,可以减少系统资源的消耗,对系统进行优化并提高运行速度。
    • 保护代理可以控制对真实对象的使用权限。

    缺点

    • 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。

    • 实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

    适用环境

    • 远程(Remote)代理:为一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以是在同一台主机中,也可是在另一台主机中,远程代理又叫做大使(Ambassador)。
    • 虚拟(Virtual)代理:如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。
    • Copy-on-Write代理:它是虚拟代理的一种,把复制(克隆)操作延迟到只有在客户端真正需要时才执行。一般来说,对象的深克隆是一个开销较大的操作,Copy-on-Write代理可以让这个操作延迟,只有对象被用到的时候才被克隆。
    • 保护(Protect or Access)代理:控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限。
    • 缓冲(Cache)代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。
    • 防火墙(Firewall)代理:保护目标不让恶意用户接近。
    • 同步化(Synchronization)代理:使几个用户能够同时使用一个对象而没有冲突。
    • 智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,如将此对象被调用的次数记录下来等。

    应用

    • pring 框架中的AOP技术也是代理模式的应用,在Spring AOP中应用了动态代理(Dynamic Proxy)技术。
    • RMI (Remote Method Invocation,远程方法调用)
    展开全文
  • 23 种设计模式详解(全23

    万次阅读 多人点赞 2019-06-09 00:21:59
    创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 行为型模式,共十一种:...
  • 如何理解这6种常见设计模式

    千次阅读 2020-09-10 14:06:17
    有哪些常见设计模式?如何合理运用?本文分享作者对工厂模式、单例模式、装饰模式、策略模式、代理模式和观察者模式的理解,介绍每模式的模式结构、优缺点、适用场景、注意实现及代码实现。一 前言最近在改造...
  • 23种设计模式常用模式

    万次阅读 多人点赞 2018-08-08 09:14:41
    设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段...
  • java常见的六种设计模式-入门

    万次阅读 多人点赞 2018-07-12 16:26:17
    在这里不得不提的就是框架与设计模式的区别.简单的说(又简单的说,你都不会复杂点?):一栋高楼,钢筋混泥土组成的架构就是框架,而室内装修摆放的针对性的解决方案就是设计模式(墙角线路要用单例模式,天花板的灯具摆放要...
  • 前端开发中常用的几种设计模式

    万次阅读 多人点赞 2021-08-17 15:05:54
    设计模式更多的是指导思想和方法论,而不是现成的代码,当然每种设计模式都有每语言中的具体实现方式。学习设计模式更多的是理解各种模式的内在思想和解决的问题,毕竟这是前人无数经验总结成的最佳实践,而代码...
  • js的几种设计模式

    千次阅读 2021-01-11 15:52:40
    demo:卖手机,颜色和数量判断加入购物车按钮是否可用 11、装饰者模式 动态的给类或对象增加职责的设计模式。 装饰器模式并不去深入依赖于对象是如何创建的,而是专注于扩展它们的功能这一问题上。装饰器模式相比...
  • 设计模式的几个重要原则 单一职责原则 开闭原则 依赖倒转原则 里氏代换原则 合成聚合复用原则:尽量使用组合/聚合代替继承 迪米特原则:降低耦合性 设计模式 类图 优点 缺点 ...
  • Java常见设计模式面试题及答案

    千次阅读 2021-03-29 06:12:47
    设计模式是什么?你是否在代码中使用过?2. JDK 中常用的设计模式有哪些?3.单例模式是什么?请用 Java 写出线程安全的单例模式4.在 Java 中,什么叫观察者模式(observer design pattern)?5.使用工厂模式有哪些...
  • 快速梳理23常用的设计模式

    千次阅读 多人点赞 2018-11-17 22:54:34
    本文旨在快速梳理常用的设计模式,了解每个模式主要针对的是哪些情况以及其基础特征,每个模式前都有列举出一个或多个可以深入阅读的参考网页,以供读者详细了解其实现。 快速回忆 一、创建型 单例(Singleton...
  • 常见设计模式—单例模式(Singleton)

    千次阅读 多人点赞 2020-03-15 20:14:59
    对于常用的23种设计模式,这里笔者会根据自己学习和出现频率、重要程度进行学习记录吧。 单例模式 单例模式(Singleton Pattern)是设计模式中最简单的模式之一,属于创建型模式。这种设计模式主要是类的对象只有一...
  • 微服务六种设计模式

    千次阅读 2021-10-25 10:24:46
    1、聚合设计模式 聚合设计模式常用于报表服务,在微服务系统中报表服务是肯定存在的。 2、代理设计模式 在微服务架构中代理服务是必然存在的,常用的代理服务是网关服务。 微服务的各个服务是没有状态的...
  • C++常用的11种设计模式

    千次阅读 2021-03-08 01:42:15
    这里写目录标题工厂模式单例模式(懒汉式、饿汉式)适配器模式外观模式代理模式包装模式(装饰器模式)桥接模式模板方法模式策略模式观察者模式责任链模式 工厂模式 定义:将工厂变成一个抽象类,在里面定义一个纯虚...
  • 单例模式 虚拟机中这个类只有一个实例; 方法一:饿汉式单例(一开始就创建好实例) public class SingleInstance { //让构造器私有,别的类就无法创建这个类的对象 private SingleInstance() { } //...
  • 软件设计常见的23种设计模式

    千次阅读 2018-11-14 18:09:01
    在现代软件开发当中,设计模式起到至关重要的作用。尤其是自从面向对象的语言普遍使用以后,促成了团队合作设计的热潮,而在此时,没有一个好的设计模式,软件... 常见23模式概述:  1) 抽象工厂模式(Abstrac...
  • 常见设计模式的解析和实现(C++),真的很经典,我也在学 常见设计模式的解析和实现(C++)之一-Factory模式 常见设计模式的解析和实现(C++)之二-Abstract ...常见设计模式的解析和实现(C++)之-Singleton模式 .........
  • iOS常见设计模式:工厂设计模式

    千次阅读 2022-03-14 16:34:10
    iOS常见设计模式:工厂设计模式 简单工厂模式: 简单工厂模式(Simple Factory Pattern):专门定义一个类(工厂类)来负责创建其他类的实例。可以根据创建方法的参数来返回不同类的实例,被创建的实例通常都具有...
  • 五种常见设计模式

    万次阅读 2017-01-22 22:37:03
    设计模式 一书将设计模式引入软件社区,该书的作者是 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides Design(俗称 “四人帮”)。所介绍的设计模式背后的核心概念非常简单。经过多年的软件开发实践...
  • 常见的六种设计模式以及应用场景

    万次阅读 多人点赞 2018-01-21 20:55:26
    单例模式是一常用的软件设计模式。 在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。
  • 常见设计模式和应用场景

    千次阅读 2020-11-20 14:01:39
    常见设计模式和应用场景单例模式原型模式命令模式六大设计原则1. 单一职责原则2. 开闭原则3. 里氏替换原则4. 依赖倒置原则5. 接口隔离原则6. 迪米特法则 设计模式从大的维度来说,可以分为三大类:创建型模式、...
  • 种常见设计模式(含C++代码)

    万次阅读 多人点赞 2018-07-09 13:46:30
    本文部分转载于https://blog.csdn.net/hechao3225/article/details/71366058本文介绍几常用的设计模式并给出C++实现。1.单例模式作用:保证一个类只有一个实例,并提供一个访问它的全局访问点,使得系统中只有唯一...
  • 23种设计模式UML图

    千次阅读 2020-06-19 19:33:02
    设计模式UML图 创建型模式(5):工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 结构型模式(7):适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 行为型...
  • Java企业级常见设计模式

    万次阅读 2020-08-06 09:02:28
    创建型模式 工厂模式:创建工厂接口类(规范),子类(工厂)实现业务。 抽象工厂模式:工厂的创建由子类决定,其子类的子类实现业务。(也称为超级工厂模式) 单例模式:系统中保持一个实例,实例方法私有,公开全局...
  • 设计模式概述(Design pattern): 设计模式:代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员...
  • java常见设计模式及其代码实现

    千次阅读 2018-11-26 17:16:03
    常见设计模式 单例设计模式设计模式要求在程序运行中,同一对象只能在JVM中存在一个实例。 其实这一点很简单实现,只要我们创建类的时候,将构造方法私有,外界无法创建对象。(不保证特殊情况下破坏单例的...
  • 简要的概述了常见设计模式
  • 常见的23种设计模式,你知道多少?

    千次阅读 2015-03-17 22:59:12
    这几天一直很忙,没有时间发表帖子和对...这是关于设计模式发布的第一贴,而这个Say(http://say.sentsin.com/)其实按理来说是比较偏向于前端的东西的,但是摒弃这个不说,我仅仅想表达一个语言是相通的一个思

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 496,815
精华内容 198,726
关键字:

常见的五种设计模式