一)设计模式的准则:

一、单一职责原则

单一职责原则,用于控制类的粒度大小

单一职责原则: 通俗的讲就是一个类越专一越好,只负责一个功能、一个职责

一个类承担的职责越多,它被复用的可能性就越小;而且相当于将该类的职责们耦合在一起,当其中一个职责变化时,可能会影响其他职责的运作,因此要将这些职责进行分离,将不同的职责封装在不同的类中。

二、开闭原则

  1. 开闭原则: 一个软件实体应当对扩展开放,对修改关闭。

即,一个软件实体应尽量在不修改原有代码的情况下进行扩展。

当软件系统需要面对新的需求时,在扩展时无须修改原有代码,使得软件系统具备很好的延续性。

为了满足开闭原则,需要对系统进行抽象化设计,抽象化是开闭原则的关键

如果需要修改系统的行为,无须对抽象层进行任何改动,只需要增加新的实现类来完成新的业务功能即可
实现了在不修改原有代码的基础上扩展了系统的功能,达到了开闭原则的要求。

三,里氏替换原则

里氏替换原则主要阐述了有关继承的一些原则,也就是什么时候应该使用继承,什么时候不应该使用继承,以及其中蕴含的原理。

里氏替换反映了基类与子类之间的关系,是对开闭原则的补充;

里氏替换原则要求:一个软件实体如果使用的是一个父类的话,那么一定适用于子类,而它察觉不出父类对象和子类对象的区别。也就是,在软件里,子类必须可以替代他们的父类型。

里氏替换原则的作用:
它克服了继承中重写父类造成的可复用性变差的缺点。
它是动作正确性的保证。即类的扩展不会给已有的系统引入新的错误,降低了代码出错的可能性。
里氏替换原则的实现方法
里氏替换原则通俗来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。也就是说:子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。

如果通过重写父类的方法来完成新的功能,这样写起来虽然简单,但是整个继承体系的可复用性会比较差,特别是运用多态比较频繁时,程序运行出错的概率会非常大。

如果程序违背了里氏替换原则,则继承类的对象在基类出现的地方会出现运行错误(用继承类去代替基类运行的时候会出现运行错误)。这时其修正方法是:取消原来的继承关系,重新设计它们之间的关系。

里氏替换原则告诉我们:在软件中用一个父类类型声明它的子类对象,程序将不会产生任何错误和异常。

里氏代换原则是实现开闭原则的重要方式之一。

四,依赖倒置原则:

依赖倒置原则: 要针对接口编程,而不是针对实现类编程。

在程序中尽量使用父类类型 来对对象引用 进行声明而在运行时再使用具体的子类类型,来赋值给该父类类型的引用变量;

即:在程序代码中传递参数时:
尽量引用层次高的抽象层的类或接口,来进行变量类型声明、参数类型声明、方法返回类型声明,以及数据类型的转换等,

而不要用具体的实现类来做这些事情
 
在引入抽象层后,在程序中尽量使用抽象层进行编程
这样一来,如果系统行为发生变化,只需要对抽象层进行扩展即可,
无须修改原有的代码逻辑,在不修改的情况下来扩展系统的功能,满足开闭原则的要求。

五,接口隔离原则:

接口隔离原则 :使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口,

每一个接口应该承担一种相对独立的角色,不干不该干的事。

六,迪米特法则:

  1. 迪米特法则要求我们:应该尽量减少对象之间的交互,如果两个对象之间不必彼此直接通信,那么这两个对象就不应当发生任何直接的相互作用,如果其中的一个对象需要调用另一个对象的某一个方法的话,可以通过第三者转发这个调用。
  2. 简言之,就是通过引入一个合理的第三者来降低现有对象之间的耦合度。
  3. 在类的划分上,应当尽量创建松耦合的类,类之间的耦合度越低,就越有利于复用,一个处在松耦合中的类一旦被修改,不会对关联的类造成太大波及;
  4. 迪米特法则可以降低系统的耦合度,使类与类之间保持松散的耦合关系。

二)设计模式:

1)单例模式:

单例(Singleton)模式:指的是一个类只能有一个实例。

单例模式有 3 个特点:

  • 单例类只有一个实例对象;
  • 该实例对象必须由单例类自己创建;
  • 单例类对外提供一个访问实例对象的全局访问点;

—————- 应用场景: —————————-

1. Spring工厂生产bean的模式:
  1. 单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。 <br /> Spring工厂默认生产bean的方式即为singleton单例模式。<br /> 当然也可以通过scope=“prototype”来指定为多例/原型模式;

单例模式的实现:

详情请见:https://blog.csdn.net/qq_44750696/article/details/123174531

2)工厂模式

在软件开发中,做到软件对象的生产和使用相分离,即为工厂模式。

工厂模式的定义:
定义一个创建产品对象的工厂接口,将产品对象的实际创建工作由具体的工厂实现类来做。这就满足了“创建与使用相分离”的特点。
我们把被创建的对象称为“产品”,把创建产品的地方称为“工厂”。

工厂方法模式的主要优点有:
用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程;

应用场景:Spring工厂/容器 ———————————
  1. 以前由应用程序直接使用new创建新的对象;<br /> 为了将对象的创建和使用相分离,采用工厂模式,即,应用程序将对象的创建及初始化的职责交给Spring工厂/容器来进行。

3)代理模式:

代理模式的定义:
给某对象提供一个代理,以控制外界对该对象的访问。这时,访问者不能直接访问到目标对象,只能访问到代理对象。

应用场景:Spring中的AOP思想 —————————-
  1. AOP的实现原理:动态代理:1JDK动态代理。2CGLib动态代理。<br /> JDK动态代理通过反射来接收被代理的类,要求被代理的类必须实现一个InvocationHandler接口。 <br /> 如果被代理的类没有实现InvocationHandler接口,那么Spring AOP会选择使用CGLIB 动态代理。CGLIB是一个类库,可以在运行时动态生成 某个被代理的类 的子类,CGLIB是通过继承的方式做的动态代理。

4)适配器模式:

经常出现两个对象因接口不兼容而不能在一起工作的实例,这时需要第三者进行适配,使得原本由于接口不兼容而不能一起工作的那些类,能一起工作。

适配器模式 包含以下主要角色:
目标接口;
现有的接口;
适配器;

——————- 使用场景 ———————————————
适配器模式就是把一个类的接口变换成客户端所能接受的另一种接口,从而使两个接口不匹配而无法在一起工作的两个类能够在一起工作。

场景:

Java的IO流中,

比如:
InputStreamReader和OutputStreamWriter这两个转换流,就是适配器的典型体现。
InputStreamReader的作用就是:将InputStream字节流适配到Reader字符流。源角色就是InputStream的实例对象,目标角色就是Reader的实例对象。
OutputStreamWriter也是类似的方式。

5)装饰模式:

在软件开发过程中,有时一些组件可能只是完成了核心功能。
在不改变其原有代码的情况下,可以动态地扩展其功能。这些都可以釆用装饰模式来实现

装饰模式的定义:
使用 组合关系 创建一个 装饰对象 ,来装饰现有对象,在不改变现有对象结构的情况下,给该对象增加一些额外功能。

—————— 应用场景: —————————————————-

装饰模式是java IO流的一种基本模式。
  1. FileInputStream为例, <br /> **InputStream类是以抽象组件的形式**存在,**FileInputStream就是一个装饰类**,它实现了InputStream的所有方法;<br /> 而**BufferInputStream是这个装饰类的具体实现者,它给InputStream加入了新的功能**,使得InputStream读取的数据保存在内存中,从而提高了读取的性能。

6)享元模式:

享元模式的定义:
运用共享技术来支持对 对象的复用。
它通过共享已经存在的对象,来减少需要创建的对象数量、避免大量的重复性开销,从而提高资源的利用率。

应用场景:String的字符串常量池—————————————
  1. String类是由final修饰的,以字面量的形式创建String变量时(比如:String s1 = "hello"; ),jvm会在编译期间把该字面量“hello”放到字符串常量池中,由Java程序启动的时候就已经加载到内存中了。<br /> <br /> 这个字符串常量池的特点就是:常量池中有且只能有一份相同的字面量,如果要创建相同的字面量,则jvm会返回这个字面量的引用,如果没有相同的字面量,则在字符串常量池创建出这个字面量,并返回它的引用。

7)外观模式:

  1. 当一个系统的功能越来越强,子系统会越来越多,客户端对系统的访问也变得越来越复杂。<br /> <br /> 如果系统内部发生改变,客户端也要跟着改变,所以就有了外观模式,为多个子系统提供一个统一的访问入口。

外观模式的定义:
通过为多个复杂的子系统提供一个统一的访问入口,而使这些子系统更加容易被访问的模式,即为外观模式。

应用场景:
类似于现在流行的分布式或者微服务架构中的网关的角色;

8)责任链模式:

责任链模式的定义:
为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者 通过记住其下一个处理者的方式 来连成一条链;
当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。

应用场景:Tomcat容器 ——————————————-
Tomcat容器,就是责任链模式的完美体现;<br />    整个Tomcat容器就是一串Servlet链,这个链一直将客户端请求传递给最终处理该请求的那个Servlet。

9)观察者模式:

每当一个微信公众号发布一篇文章后,订阅的用户都能够及时接收到推送,然后进行阅读。这就是观察者模式。

观察者模式:
定义对象之间的一种 一对多的依赖关系, 每当一个对象的状态发生改变时,依赖它的相关对象,都会得到通知并自动更新数据。

应用场景:多路复用IO(Java的NIO)的主从模式 ————————————-
多路复用IO的主从模式,采取多Reactor模式,主Reactor只负责监听客户端的连接请求,如果有连接请求到来,会通知从Reactor,<br />然后从Reactor去与该客户端建立起真正的连接,再从线程池中取一个线程去进行处理。

这个主Reactor就是一个观察者,当监听到有事件发生时,主Reactor会通知从Reactor,并传过去一组SelectionKey,
从Reactor通过读取这些SelectionKey,就会知道是哪一个客户端有IO事件,然后,从Reactor与该客户端建立起真正的连接,然后进行相应的处理即可。

10)中介者模式:

在现实生活中,常常会出现好多对象之间存在复杂的交互关系,这种交互关系常常是“网状结构”,它要求每个对象都必须知道它需要交互的所有对象,非常复杂。<br />    这时只要找一个“中介者”就可以了。<br />    例如,你想租房,可以找“房屋中介”;或者,自己刚刚到一个陌生城市找工作,可以找“人才交流中心”帮忙。<br />    <br />在软件的开发过程中,这样的例子也很多,例如,在 MVC 框架中,控制器(C)就是模型(M)和视图(V)的中介者;<br />    <br />    所有这些,都可以采用“中介者模式”来实现,它将大大降低对象之间的耦合性,提高系统的灵活性。<br /> <br />中介者模式的定义:<br />    定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。<br />中介者模式它是迪米特法则的典型应用。

11)备忘录模式:

每个人都有犯错误的时候,都希望有种“后悔药”能弥补自己的过失,让自己重新开始。<br />    在计算机应用中,客户同样会常常犯错误,能否提供“后悔药”给他们呢?当然是可以的,而且是有必要的。这个功能由“备忘录模式”来实现。

比如很多应用软件都提供了这项功能,如 Word、记事本、Photoshop、Eclipse 等软件在编辑时按 Ctrl+Z 组合键时能撤销当前操作,使文档恢复到之前的状态;<br />还有数据库事务管理中的回滚操作、数据库与操作系统的备份操作、棋类游戏中的悔棋功能等都属于这类。

备忘录模式能记录一个对象的内部状态,当用户后悔时能撤销当前操作,使数据恢复到它原先的状态。<br /> <br />备忘录模式的定义:<br />    在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便日后有需要时,能将该对象恢复到原先保存的状态。

12)迭代器模式:

在现实生活以及程序设计中,经常要访问一个聚合对象中的各个元素,如“数据结构”中的链表遍历,通常的做法是将链表的创建和遍历都放在同一个类中,但这种方式不利于程序的扩展,如果要更换遍历方法就必须修改程序源代码,这违背了 “开闭原则”。

“迭代器模式”能较好地克服以上缺点,它在客户访问类与聚合类之间插入一个迭代器,这分离了聚合对象与其遍历行为,对客户也隐藏了其内部细节,且满足“单一职责原则”和“开闭原则”。<br />    <br />    如 Java 中的 Collection、List、Set、Map 等都包含了迭代器Iterator。<br /> <br />迭代器模式的定义:<br />    提供一个对象来顺序访问容器对象中的一系列数据,而不暴露容器的内部结构。<br />