本文为博主原创,允许转载,但请声明原文地址:http://www.coselding.cn/blog/4/4-116.html
创建型模式
- 工厂模式:(建议使用泛型工厂——优雅)
步骤:
- 工厂单例;
- 配置文件只读一遍,静态代码块或私有构造方法;
- 通过配置文件获取对应加载类限定名,加载类并创建实例;
- 一个对外方法返回实例,达成工厂模式;
注:三层架构层与层之间使用工厂模式进行解耦;
- 抽象工厂模式(Abstract Factory)
对工厂也提取接口,增加一个产品时,也相应增加一个生产该产品的实现了工厂接口工厂,避免了增加产品后要对原工厂代码进行修改的问题。缺点:增加产品也增加了一个工厂,类数量增长较快。
- 单例模式:
步骤:A、构造方法私有;
B、在类中构造一个静态私有的唯一实例;
C、提供一个公有的静态方法返回该唯一实例
注:实例化方式有饿汉加载和懒汉加载两种方式,若工厂占用内存较大,考虑用懒汉式提升性能。
单例模式的几种情形:
- 线程不安全懒汉式;
- 线程安全懒汉式,在初始化单例的代码处加synchronized;
- 饿汉式,线程安全;
- 双重校验锁,volatile和synchronized;
- 内部静态类维护单例,类似于饿汉式。
- 建造者模式:
用于创建复杂类对象,该对象中的模块是固定的,比如各种汉堡,饮料来组合成各种套餐。步骤:
- 复杂类,成员属性包括多个固定的子模块类,可以实现相同接口方便维护;
- Builder中实现了建造各种类型的复杂类对象的相应建造方法,相当于建造各种套餐的对应方法;
- 在建造方法中对应该套餐对复杂类对象进行初始化,并进行返回,完成复杂对象的构建。
- 原型模式:
当一个类创建一个对象的构造方法执行时需要繁琐的数据库操作或者消耗资源的操作时,可以使用原型模式,在创建一个实例之后,后面需要创建的实例直接通过clone进行对象复制。浅拷贝和深拷贝:
浅拷贝指实例中的基本数据类型进行复制,但是其中的引用类型指向的内存空间不进行拷贝,直接使用Cloneable接口的clone方法即可实现;
深拷贝这是整个实例的整个内存空间全部拷贝,要用ByteArrayOutputStream,ObjectOutputStream,ByteArrayInputStream,ObjectInputStream对原型占用的内存块进行全复制。
步骤:
- 构造存放原型的Map,用来存放所有创建的原型;
- 创建一个初始化方法,用户实例化每个原型,并存放到Map中;
- 创建一个根据Map的key得到实例的方法,从Map中查询到相应的原型,再根据原型复制一份进行返回。
结构型模式
- 适配器模式:
当一个A类的接口不满足需要用他的B类的接口时,需要一个适配器C来将A类中的数据适配到B类的各个接口中,实现将A类使用到原本不认识他的B类中,比如Android中ListView的适配器。
- 分类:类的适配器模式、对象的适配器模式、接口的适配器模式
- Adapter类继承Source类,实现Targetable接口;
- Adapter中维护Source的实例,并实现Targetable接口,在接口方法中使用Source对象进行相应操作;
- 接口的适配器模式:Source的接口编写Adapter的抽象类,实现所有方法(空方法),再编写Adapter的子类覆盖需要覆盖的方法即可。(相当于写了一个接口的默认实现类);
应用场景:
(1)类的适配器模式:当希望将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。
(2)对象的适配器模式:当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个Wrapper类,持有原类的一个实例,在Wrapper类的方法中,调用实例的方法就行。
(3)接口的适配器模式:当不希望实现一个接口中所有的方法时,可以创建一个抽象类Wrapper,实现所有方法,我们写别的类的时候,继承抽象类即可。
弊端:适配器模式使用太多会使代码的可维护性降低。
- 包装设计模式——对某个对象进行增强
步骤:- 写一个类,实现与被增强对象的相同的接口
- 定义一个变量,接收被增强对象
- 定义一个构造方法,接收被增强对象
- 覆盖想增强的方法
- 对于不想增强的方法,直接调用被增强对象的方法
缺点:产生过多相似的对象,不易排错!
- 代理模式:
对一个类的功能加以拓展或者进行访问控制。步骤:
- 写一个类,实现与被代理对象的相同的接口
- 定义一个变量,接收被代理对象
- 定义一个构造方法,接收被代理对象
- 覆盖想代理的方法
- 对于不想代理的方法,直接调用被代理对象的方法
以上和包装设计模式雷同,为静态代理方式。
动态代理参考Java的动态代理相关技术知识点。
- 外观模式:
屏蔽调用者和复杂系统之间的交互,在复杂系统外面加一层外观类,在该类中处理好复杂系统的调用关系、调用顺序和依赖关系,只对外面的调用者提供一个简易的调用接口,实际即是封装! - 桥接模式:(将抽象化和实现化解耦)
对一个相同接口I的多个不同实现,利用桥接模式来有条不紊地控制对不同实现类的调用。比如JDBC的DriverManager就桥接了多个不同的数据库驱动,在访问不同的数据库之间进行驱动切换不出现错误。步骤:
- 编写抽象桥接类Bridge ,维护一个相同接口I的引用;
- 实现该相同接口I引用的set和get方法;
- 编写其他相关方法对相同接口I进行执行调用,此处常用抽象方法,再去继承Bridge以实现具体的执行过程;
- 使用Bridge执行时,先调用set方法设置接口引用,再调用相关执行方法执行,即可正确选择接口的实现类来进行执行。
- 组合模式:
处理部分和整体关系,实现将处理简单元素和复杂元素的处理统一性,比如二叉树的数据结构。步骤:
- 设置一个类的节点属性,构造方法,set和get方法;
- 维护一个该节点的下级节点集合,并维护集合的增删方法,集合的获取方法;
- 这样通过根节点去找其子节点,以此类推可遍历所有节点,树的结构和遍历。
- 享元模式:
FlyWeightFactory(维护一个享元单元集合)负责创建和管理享元单元,当一个客户端请求时,工厂需要检查当前对象池中是否有符合条件的对象,如果有,就返回已经存在的对象,如果没有,则创建一个新对象,加入对象池中。这样就节省了空间,减少了实例的数量。举例:JDBC连接池。
- 过滤器模式:
使用过滤器模式形成类对象的过滤策略。步骤:
- 过滤器接口,实现过滤的抽象方法;
- 实现过滤器接口,覆盖具体该过滤器的过滤代码和相应的构造方法,可以包括And和Or过滤器;
- 调用过滤器的过滤方法对对象集合进行过滤。
行为型模式
父类与子类
- 策略模式:
将实现一个抽象类的功能的具体算法写在一个抽象方法中,类内部的执行流程不变,对算法的调用过程不变,再由他的子类来具体实现算法的抽象方法的具体过程,保证了系统内部的逻辑不变,但是可以改变算法策略。(例如Java的事件监听机制)
简单讲即是:一个方法是在一个策略类中实现的,但是调用由执行类去调用。
步骤:
- 设计一个抽象方法或者接口方法;
- 在执行类中维护一个抽象接口引用;
- 在执行类中抽象地调用接口抽象方法执行系统流程;
- 继承抽象类,复写抽象方法,实现算法策略的具体过程;
- 用继承的子类去赋值给执行类中的接口引用。
注:系统中可对算法进行多种具体实现,从而在实现过程中可以动态地替换算法策略。
- 模板方法模式:
和策略模式类似,只是策略模式的执行类中维护了一个策略接口的引用,通过对这个引用的不同赋值实现策略替换;模板模式指的是执行类就是一个抽象类,定义一个抽象方法,而类中的其他主流程抽象地调用抽象方法来实现自己的功能,接着编写执行类的子类,在子类中才具体实现抽象方法的具体过程(例如JavaIO流中的读写抽象方法)。简单讲即是:一个方法是在子类中写的,但是调用由父类去调用。
步骤:
- 设计一个抽象类和抽象方法;
- 在类中抽象地调用抽象方法执行系统流程;
- 继承抽象类,复写抽象方法,实现算法的具体过程;
- 该继承的子类就是实现了完整功能的具体实现类。
注:(1)模板模式延迟了一个类的其中一个具体实现过程,封装了类功能的逻辑流程,将其中的子功能的实现交给子类,实现了子功能的多样化,保证了该类的主流程的不变性和代码重用性。
(2)父类中的主流程方法一般为final。
(3)封装不变部分,拓展可变部分,行为由父类控制,子类实现。
两个类之间
- 观察者设计模式(Observer):
将一个主对象和多个观察者对象关联起来,对主对象进行某些操作时,观察者对象可以收到主对象的执行信息,来进行相关操作。(类似广播操作,Android内容观察者)
步骤:
- 编写观察者抽象类和接收执行抽象方法;
- 主对象类中维护一个观察者集合,增删观察者方法;
- 编写遍历观察者集合进行通知的notify方法;
- 在主对象需要监视的方法中,调用notify方法,通知所有观察者。
优点:观察者与被观察者抽象耦合;
缺点:(1)被观察者执行时需要通知多个观察者,影响效率;
(2)观察者和被观察者如果存在互相循环依赖的话,循环调用,堆栈崩溃。
- 迭代器模式(Iterator):
顺序访问集合中的对象,不需要知道集合对象的底层表示。(Java容器的Iterator迭代器)Iterator迭代器接口一般有的方法:hasNext,next,previous,first
场景:不暴露集合的内部结构,又能对集合进行透明地访问。
- 责任链模式:
事件发出者发出一个事件交给处理者处理,不需要考虑给哪个处理者才能正确处理,各个处理者持有下一个处理者的引用,连成一个处理者责任链,接收到事件时判断当前处理者是否是正确处理者,若是,则进行处理,若不是则交给下一个处理者。步骤:
- 编写一个处理接口和处理方法,是正确处理者才执行;
- 编写一个处理者抽象类,维护一个处理接口引用,指向下一个处理者;
- 编写处理者抽象类的子类,并实现处理接口,在接口处理方法中实现处理者的选择判断、选中处理过程、不选中交给下一个处理者。
优点:发出者和处理者解耦;增删处理者和发出者很方便。
缺点:不一定被接收到;影响性能。
注:链接上的请求可以是一条链,可以是一个树,还可以是一个环,模式本身不约束这个,需要我们自己去实现,同时,在一个时刻,命令只允许由一个对象传给另一个对象,而不允许传给多个对象。
- 命令模式:
将一个动作的发出者和执行者进行解耦,中间使用命令将发出者和执行者隔开实现解耦。(Struts)步骤:
- 编写执行类Receiver和接口,编写一个接口执行方法;
- 编写命令类Command和接口,维护一个执行类接口引用和命令执行接口方法;
- 编写发出者类Invoker,维护一个Command集合(增删),以及对命令的调用执行。
优点:降低系统耦合度,分离了发出者和执行者的耦合;
很方便添加命令类和执行者类,便于拓展;
请求和执行分开。
类的状态
- 备忘录模式:
用来保存某个对象的状态,并能在必要的时候恢复这个状态。(游戏存档,事务回滚)
步骤:
- 编写一个备忘录条目类Memento,用来存储待备份对象中需要存储的属性;
- 编写一个存储类Storage,维护Memento的引用或集合,达到保存对象状态的目的;
- 待备份对象中添加一个生成Memento的方法和一个通过Memento恢复状态的方法。
- 状态模式:
核心思想就是:当对象的状态改变时,同时改变其行为。(QQ在线状态)步骤:
- 编写状态接口State,和具体的状态切换方法、状态对应的执行方法;
- 实现状态接口,编写该状态具体的执行行为;
- 编写执行类Context,执行方法依赖State来执行,通过切换不同的State,来控制执行不同的行为。
优点:封装转换原则,避免大量的if…else语句;
方便增加新的状态。
通过中间类
- 访问者模式:
访问者模式把数据结构和作用于结构上的操作解耦合,使得操作集合可相对自由地演化。访问者模式适用于数据结构相对稳定算法又易变化的系统。因为访问者模式使得算法操作增加变得容易。
步骤:
- 被访问的数据结构实现一个接收访问者的方法,向访问者传入自身引用;
- 访问者接口有接收数据结构的接口方法;
- 访问者接口实现类实现具体的访问接口方法,执行具体的操作算法。
优点:实现了稳定的数据结构和易变的操作的解耦;
很方便为数据结构添加新的操作,拓展性强。
- 中介者模式:
当系统中有多个对象之间有复杂的关联关系时,每个对象内部都需要维护其他与之关联对象的引用,耦合度太高。使用中介者模式,由中介者维护对象间的引用和对象之间的具体操作流程,当一个对象改变时,只需要维护好该对象和中介者之间的关系即可,不需要考虑和其他关联对象之间的关系。步骤:
- 创建一个中介者类,维护有关联关系的所有对象的引用;
- 实现一个执行方法,对这些对象根据逻辑关联关系进行正确的处理。
优点:将网状的关系网变成星形关系网,降低代码改变引起的修改代价,增强可维护性;
降低复杂度,各类之间解耦。
- 解释器模式:(不常用)
用于一些规律性的语言解析,如正则表达式,SQL语句解析。步骤:
- 编写解释器接口,和一个解释方法;
- 实现解释器接口,完成该解释器的相应的解释过程和构造方法;
- 根据构造方法构造出解释器,并传参执行相应的解释过程。
优点:拓展性好,易于实现;
能够简单实现规律性文法的解释。
- 空对象模式:
设计一个表示空null的对象,在各种需要检查空值的地方使用该对象进行使用。步骤:
- 提取正常对象和空对象的公有接口,并提供一个判断空对象的抽象方法;
- 空对象实现和正常对象相同的接口,并在相应的方法返回空对象相应的参数值。
优点:统一化了正常对象和空对象的操作方法,并且用户交互信息可以直接封装在空对象中,调用和正常对象相同的方法便可在相应的界面处显示。
本文为博主原创,允许转载,但请声明原文地址:http://www.coselding.cn/blog/4/4-116.html