设计模式

创建模式

单例模式

什么是设计模式

  1. 设计模式:一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。
  2. 目的:可重用代码,让代码更容易被他人理解、保证代码可靠性。
  3. Java中的设计模式:23种:
  • [x] 创建型模式:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式;
  • [x] 结构型模式:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式;
  • [x] 行为型模式:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式;
  • [x] 其它模式:并发型模式和线程池模式。
    单例模式:保证整个应用中某个实例有且只有一个。
    举例:配置文件、工具类、线程池、缓存、日志对象等

单利模式实现

  1. 应用场合: 有些对象只需要一个就足够了.
  2. 作用: 保证整个应用程序中某个实例有且只有一个.

(1) 饿汉式
懒汉模式,先只是进行声明,当存在该实例的时候直接返回,不存在的时候再去新建

/*
 * 单例模式Singleton
 * 应用场合:有些对象只需要一个就足够了,如古代皇帝、老婆
 * 作用:保证整个应用程序中某个实例有且只有一个
 * 类型:饿汉模式、懒汉模式
 */
public class Singleton {
    //1.将构造方法私有化,不允许外部直接创建对象
    private Singleton(){
    }
    //2.创建类的唯一实例,使用private static修饰
    private static Singleton instance=new Singleton();
    //3.提供一个用于获取实例的方法,使用public static修饰
    public static Singleton getInstance(){
        return instance;
    }
}

(2) 懒汉式
饿汉模式特点之一就是在类加载是这个类的实例就被加载了,无论之后是否用到这个实例

/*
 * 懒汉模式
 */
public class Singleton2 {
    //1.将构造方法私有化,不允许外边直接创建对象
    private Singleton2(){

    }
    //2.声明类的唯一实例,使用private static修饰
    private static Singleton2 instance;
    //3.提供一个用于获取实例的方法,使用public static修饰
    public static Singleton2 getInstance(){
        if(instance == null){
            instance = new Singleton2();
        }
        return instance;
    }

}

饿汉式、懒汉式区别

饿汉模式:在加载类的时候就加载了实例,因此加载慢,但运行快,线程安全
懒汉模式:在加载类时没有加载实例,加载快,运行时加载实例,运行慢,线程不安全

工厂模式

工厂模式的概念、意图、应用场景、动机

  1. 工厂模式的概念


  2. 工厂模式的意图


  3. 工厂模式的应用场景


  4. 工厂模式的动机


  5. 工厂模式类图


  6. 抽象工厂模式类图


工厂模式的应用

  1. 常见的应用
    (1) JDBC的工作流程



    (2) spring beanfactory


  1. 对比:


  2. 实现了


  3. 适用场景


结构型模式

代理模式

1. 概念

  • [x] 为其他对象提供一种代理,以控制对这个对象的访问(例如火车站代售处)。代理对象起到中介作用,可去掉功能服务或增加额外的服务。

2. 代理模式的分类:

  • [ ] 远程代理模式: 为不同地理的对象提供局域网代表对象(例子:通过远程代理可以监控各个店铺,使之可以直观的了解店里的情况)
  • [ ] 虚拟代理: 根据需要将资源消耗很大的对象进行延迟,真正需要的时候进行创建
  • [ ] 保护代理: 控制用户的访问权限
  • [ ] 智能引用代理: 提供对目标对象提供额外的服务(火车票代售处)
智能引用代理:
静态代理
  1. 静态代理:代理和被代理对象在【代理之前】都是【确定】的。他们都实现【相同的接口或者继承相同的抽象类】
  2. 代理实现方法:
    (1)继承法:代理类直接【继承】被代理类,实现其原有方法,并添加一些额外功能
    (2)聚合方法:代理类实现【相同的功能接口:很重要,事项相同接口,不同代理也可以进行相互代理】,并在内声明一个被代理类的对象(类似封装),通过内部对象实现其原有方法,并添加额外功能

3、静态代理的实现
(1)聚合代理优于继承代理。因为实现功能叠加的情况下,聚合代理通过相互代理可以实现功能重用,而继承代理必须写多个类来实现多功能叠加。
(2)静态代理只能代理一种类型的被代理类,换个类型的就不行了,这需要动态代理

4、静态代理的两种实现方式对比(继承方式和聚合方式)
案例--代理类功能的叠加
(1) 继承的方式:如果使用继承的方式来实现我们代理功能的叠加,我们的代理类会无限的膨胀下去。
(2) 聚合的方式:由于代理类和被代理类都实现了相同的接口,那么代理类的构造参数就可以传入该相同的接口,这样在后面功能叠加的时候就可以传入其他功能的代理类,因为他们都实现了相同的父接口。从而达到功能叠加的作用。

动态代理
  1. JDK动态代理
    (1) 目的:动态产生代理,实现对【不同类】,【不同方法】的代理
    (2) java动态代理类,位于java.lang.reflect包下,一般涉及两个类:

(1)Interface InvocationHandler:该接口中仅定义了一个方法public object invoke(Object obj,Method method,Object[] args)
参数:
obj:被代理类的对象
method:被代理的方法
args:被代理方法参数数组
返回值:
Object:方法返回值

(2)Proxy:该类即为动态代理类:
static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)
参数:
loader:被代理类的类加载器,通过被代理类.getClass().getClassLoader()得到
interfaces:实现的接口,通过getClass().getInterfaces()得到
h:invocationHandler
返回值:
返回代理类的一个实例

  1. 动态代理实现步骤:
    (1)创建一个实现接口InvocationHandler的类,它必须实现invoke方法。
    (2)创建被代理的类以及接口。
    (3)调用Proxy的静态方法,创建一个代理类。
    newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)
    (4)通过代理调用方法。
CGLIB动态代理
  1. JDK动态代理与CGLIB动态代理之间的区别


  2. CGLIB:是一个强大的开源项目,可以在运行期扩展Java类与实现Java接口
  3. JDK动态代理实现思路
    实现功能:通过Proxy的newProxyInstance返回代理对象
    (1)声明一段源码(动态产生代理)
    (2)编译源码(JDK Compiler API),产生新的类(代理类)
    (3)将这个类load到内存当中,产生一个新的对象(代理对象)
    (4)return 代理对象

3. 总结

1、代理概念、分类及应用场景
为其他对象设置总代理,以控制对这个对象的访问;
代理对象起到了中介的作用,去掉了某些功能,或增加了些额外的服务。
四类:
Remote Proxy -- 客户端服务器的模式
Virtual Proxy -- 资源消耗很大,或复杂的对象,需要延迟,需要时创建,
Protect Proxy -- 保护和控制权限
Smart Reference Proxy -- 提供额外服务。

为什么只讲智能引用代理?
使用得多:日志处理、权限管理、事务处理...
静态代理(继承、聚合)
JDK动态代理实现日志处理的功能
模拟JDK动态代理实现:在代理类Proxy和被代理类RealSubject之间,加入了invocationHandler。
调用jar包中某个类的方法,不能改源码,AOP面向切面,增加额外事务逻辑。

适配器模式

适配器模式定义:

将一个类的接口,转换成期望的另外一个借口,使得由于接口不兼容而不能一起工作的那些类可以一起工作。

适配器模式: 构成

构成:客户端、目标接口、原本接口、具体请求


适配器模式分类

  1. 组合
  1. 继承


比较

作用

行为型模式

观察者模式

1. 认识观察者模式

(1)定义:
定义对象件的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会得到通知并且自动更新,
(2)流程图:


2. 实现的两种方式:推模型和拉模型

  1. 结构
  1. 观察者模式通用代码
    步骤:
    (1)目标对象的定义
    (2)具体的目标对象的定义
    (3)观察者接口的定义
    (4)观察者的具体实现

3. 利用Java提供的观察者实现

1. 认识观察者模式

(1)目标与观察者之间的关系:一对一、一对多、多对一等。
(2)单向依赖:观察者依赖目标,而不是目标依赖观察者,观察者是被动的,目标是主动的。
(3)命名建议:
1、目标接口的定义,建议在名称后面跟Subject;
2、观察者接口的定义,建议在名称后面跟Observer;
3、观察者接口的更新方法,建议名称为update,参数的个数及类型不受限制。
(4)触发通知的时机:目标对象的状态发生维护之后触发。(比如:先赋值内容再通知是对的,而反过来就会出现问题)
(5)观察者模式调用时序:见观察者模式调用时序图I、II。
(6)通知的顺序:不确定,平行的,没有相互依赖关系。

  1. 准备阶段


  2. 运行阶段


2. 实现的两种方式:推模型和拉模型

观察者模式两种模式:

  1. 推模型:目标对象主动向观察者推送目标的详细信息 ; 推送的信息通常是目标信息的全部或部分信息。


  2. 拉模型:目标对象在通知观察者的时候,只传递少量信息 ;如果观察者需要更具体的信息,由观察者主动到目标对象中获取,相当于是观察者从目标对象中拉数据;一般这种模型的实现中,会把目标对象自身通过update方法传递给观察者。



    两种模型的比较:

推模型是假定目标对象知道观察着需要的数据。
拉模型是目标对象不知道观察着具体需要什么数据,因此把自身传给观察者,由观察者来取值。
推模型会使观察者对象难于复用。
拉模型下,update方法的参数是目标对象本身,基本上可以适应于各种情况的需要。

Java 实现 VS 自己实现的对比四点:
(1)不需要再定义观察者和目标接口(JDK已经定义)。
(2)具体的目标实现里面不需要再维护观察者的注册信息,Java中的Observable类里面已经实现。
(3)触发通知的方式有一点变化,要先调用setChanged方法,这个是Java为了帮助实现更精确的触发控制而提供的功能。
(4)具体观察者的实现里面,update方法其实能同时支持推模型和拉模型,这个Java在定义的时候,已经考虑。

4. 简述观察者优缺点

优点: 缺点点:
1. 观察者模式实现了观察者和目标之间的抽象耦合 2. 观察者模式实现了动态联动 3. 观察者模式支持广播通信 可能会引起无谓的操作。

5. 何时使用观察者模式

使用观察者模式的场景 --- 触发联动(本质)
1、当一个抽象模型有两个方面,其中一个方面的操作依赖于另一个方面的状态变化
2、如果更改一个对象的时候,需要同时连带改变其他的对象,而且不知道究竟应该有多少对象需要被连带改变
3、当一个对象必须通知其他的对象,但是你又希望这个对象和其他被通知的对象是松散耦合的

6. 观察者模式的衍生

观察者模式——区别对待观察者场景问题
  1. 需求总结
  1. 解决思路
    (1)情况之一:如果天气是晴天,按照黄明的女朋友需要下雨的条件,黄明的老妈需要下雨或下雪的条件,则她们俩就都不需要通知了。
    (2)情况之二:如果天气是下雨,则黄明的女朋友需要通知,而黄明的老妈也需要通知。
    (3)情况之三:如果天气是下雪,则只需要通知黄明的老妈。
  2. 实现步骤:
    区别对待观察者模式中,目标父类不实现通知方法,在子类中实现有区别的通知方法。
    状态变更调用通知方法,通知方法调用观察者,同时回调目标对象


责任链模式

1. 什么是责任链模式

将接收者对象连成一条链,并在该链上传递请求,直到有一个接收者对象处理它。通过让更多对象有机会处理请求,避免了请求发送者和接收者之间的耦合。

2. 如何实现责任链模式

流程是 顾客申请折扣,触发priceHandler对请求价格的处理,在处理价格之前通过工厂方法创建了一个priceHandler的实例,如果实例处理不了折扣,触发后继,然后调用工厂设置后继并创建新的PriceHandler来处理折扣,还是处理不了继续申请,直到成功。

3. 责任链模式如何解耦

加入了新的能够折扣处理的成员lead类继承了PriceHandler
对工厂方法进行了改动 添加了lead的实例,以及给lead设置了后继Successor

1、OO的一些原则:
2、如 单一职责原则 : 设置一个接口时,应该只将与这个接口业务相关的方法放在接口之中。
3、工场方法的实质在用返回返回的是一个接口,而不是一个实例对象。
4、用到责任链,总会用到工厂

将指定的方法移到某个文件中的快捷键操作方式:
选中方法名——Refactor——Move——选择需要移动到的目标文件——确定


责任链模式:使用了自身对象后继



解耦---


责任链模式真的好吗
  1. 开闭原则(OO中的一个基本原则):

对扩展开放,对变更关闭,即是如果有一个业务变更,希望新增一个类,而非修改原有代码来满足业务需求.

  1. 责任链模式的执行性能:

当有请求到达时会从责任链头部开始遍历整条责任链,直到有一个处理器处理了请求,或者是整个链条遍历完成,在这过程中性能的损耗体现在两个方面.

(1)是时间,相对于单个Handler处理请求的时间而言,整个链条的遍历过程会消耗更多的时间.

(2) 是内存,使用责任链模式创建了大量对象来表示处理器对象,但仅仅使用了其中的少部分,剩余的大部分处理器都仅仅作为一个过客.

4. 责任链模式的应用

责任链模式在日常编码中可能不是经常用到的模式,但不管是前端还是后端工程师都可能天天接接触到责任链模式.

后端:Java中的异常处理;
前端:JavaScript Event Model;
Java Web:FilterChain in Web(不纯的COR)

1. JAVA中的异常处理机制是使用责任链模式
2. JavaScript的事件模式也是责任链模式
3. JAVAEE中的Filter

(1)JAVAEE中的Filter经常可以在请求到达核心代码之前对它进行拦截并作出一些操作,当多个Filter存在的时候就共同构成了一个FilterChain,FilterChain不是一个存的责任链,责任链模式中只能有一个对象来处理请求,而FilterChain中可以有多个对象同时处理请求.

5. 各个模式间的联系

设计模式的学习一定要结合OO的基本原则
面向对象的五大原则:

  1. 单一职责原则
  2. 开放封闭原则(对扩展开放,对变更封闭)
    1. 依赖倒置原则(核心是依赖抽象)
    1. 接口隔离原则
    1. Liskov替换原则(里氏替换原则)

策略模式

1. 什么是策略模式

策略模式将可变的部分从程序中抽象分离成算法接口,在该接口下分别封装一系列算法实现。
并使他们可以互相替换。
从而导致客户端程序独立于算法的改变。

2. 策略模式如何实现

鸭子应用的更新需求


鸭子飞行
方案一:继承



方案二:抽象方法



方案三:组合

1.Favor composition over inheritance:复合(组合)优先于继承。多用组合,少用继承。



2.组合定义:在类中增加一个私有域,引用另一个已有的类的实例,通过调用引用实例的方法从而获得新的功能,这种设计被称作组合(复合)(意思就是:得到其他类的对象,使用这个对象的方法。)


3. 策略模式总结

一、策略模式设计原则:
  1. 找出应用中需要变化的部分,把他们独立出来,不要和那些不需要变化的代码混在一起;
    将不变的东西抽象为接口,而变化的部分交给实现去做,具体而言,鸭子飞行的行为是千变万化的,但是鸭子具有飞行行为本身是不变的,我们将不变的部分抽象为飞行策略接口,而将具体的飞行行为交给实现去处理。
  2. 面向接口编程,而不是面向实现编程。
  3. 多用组合,少用继承。
二、策略模式的实现:
  1. 通过分离变化得出策略接口Strategy。
  2. 编写Strategy的实现类。
  3. 客户端程序“有一个”Strategy。
  4. 在客户程序中选择/组装正确的Strategy实现。
三、策略模式的优点:
  1. 使用了组合,使架构更加灵活。
  2. 富有弹性,可以较好的应对变化(开闭原则)。
  3. 更好的代码复用性(相对于继承)。
  4. 消除了大量的条件语句。
四、策略模式的缺点:
  1. 客户代码需要了解每个策略实现的细节,不然就会使得实现有可能有不正确的行为。
  2. 随着时间的推移,策略接口会急剧膨胀,增加了对象的数目。
五、策略模式的适用场景:
  1. 许多相关的类仅仅是行为差异,将差异的共享分离出来成为一个策略接口,而这些相关的类便成为其算法家族的成员。
  2. 运行时选取不同的算法变体。
  3. 通过条件语句在多个分支中选取一个,使用策略模式使得代码更加简洁。

4. 实际案例分享

模板方法模式

1. 什么是模板方法模式

(1) 模板模式

定义了一个操作中的算法骨架,而将一些步骤延迟到子类中实现,使得子类在不改变一个算法结构的同时,就重新定义该算法的特定步骤.


=>


(2) 生活案例——饮料的调制方法


=>


2. 如何实现模板方法模式

  1. 定义抽象基类
    (1)实现方法(通用共同属性)
    (2)抽象方法(延迟方法)
    (3)钩子方法(扩展点)
    (4)模板方法(一定要用final因为要禁止子类对方法框架的覆写)
  2. 子类

模板方法的基本实现

思想
1、一份算法框架,大家共同遵守
2、 算法框架中分离出变与不变的部分
3、将变化的算法,延迟实现(交由具体的子类实现)
基本实现
1、用一个抽象基类,一个public final方法定义好算法框架
2、不变的部分,用private方法加以实现。(基本方法)
3、变化的部分,用protected abstract加以定义(抽象方法)
使用
1、面向接口编程
2、传入实际的实现子类给接口变量
3、接口变量调用框架方法

用钩子(Hook)函数实现子类对算法框架个性化的扩展

1、思想
框架通过提供一个个的钩子,使框架具备了更大的灵活性。不想执行算法框架中的某些个步骤,我们可以脱钩,如果想执行的话,我们可以挂钩。
2、实现
在抽象类中,提供protected钩子方法。这是个实现的或空的方法。这样子类就可以选择覆写-持钩,也可以选择不覆写-脱勾。
3、使用
提供一个isXXX类型的钩子方法。用该方法控制算法框架中
4、某个步骤是否执行
子类不覆写这个方法,就是脱钩,仍按框架逻辑执行,一旦覆写,就是挂钩,将改变框架算法方向,按子类逻辑执行。

3. 模板方法模式的特点

一、模板方法模式的实现要素:

准备一个抽象类,将部分逻辑以具体方法的形式实现,然后声明一些抽象方法交由子类实现剩余逻辑,用钩子方法给予子类更大的灵活性。最后将方法汇总构成一个不可改变的模板方法。

二、从类的角度看:

(1)抽象基类
1、基本方法。
2、抽象方法【只知道具体原则,而不知道实现细节,需要将其延迟到子类中实现的一些步骤】。
3、可选钩子(Hook,钩子函数,提供一个默认或空的实现。具体的子类可以自行决定是否挂钩以及如何挂钩)。
4、Template方法(final 使其不能被子类所覆写 模板方法模式要遵循的原则:子类可以替换掉父类中的可变逻辑,但不能改变整体逻辑结构))。
(2)具体子类
1、实现基类中的抽象方法。
2、覆盖钩子方法。

三、模板方法的优点:

(1)封装性好。(2)复用性好。(3)屏蔽细节。(4)便于维护。

四、模板方法的缺点:

(1)继承限制(Java语言是单继承语言),单继承会使得更多情况不可用,新类引入困难。

五、模板方法模式的适用场景:

(1)算法或操作遵循相似的逻辑。
(2)重构时(把相同的代码抽取到父类中)。
(3)重要、复杂的算法,核心算法设计为模板方法。

4. 模板方法模式在项目中的应用

电信联通移动三大运营商日志需求分析
解决方案1
解决方案1.2 提供扩展点,使用钩子函数实现
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 设计模式汇总 一、基础知识 1. 设计模式概述 定义:设计模式(Design Pattern)是一套被反复使用、多...
    MinoyJet阅读 3,894评论 1 15
  • 工厂模式类似于现实生活中的工厂可以产生大量相似的商品,去做同样的事情,实现同样的效果;这时候需要使用工厂模式。简单...
    舟渔行舟阅读 7,716评论 2 17
  • 一、设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者...
    RamboLI阅读 742评论 0 1
  • 设计模式基本原则 开放-封闭原则(OCP),是说软件实体(类、模块、函数等等)应该可以拓展,但是不可修改。开-闭原...
    西山薄凉阅读 3,748评论 3 13
  • 原文链接:http://blog.csdn.net/zhangerqing http://www.cnblogs....
    孤独杂货铺阅读 1,507评论 0 3