设计模式一
1、简单工厂模式(simplefactory)
-
引入问题:面向接口编程?
- example1 案例 使客户端知道了接口和实现类,违背了接口的思想;
- example2 使用简单工厂模式进行封装隔离;
- example3 是对exam1的重构;
- 简单的一步使实现类对客户端隐藏了起来,但是却实现的内部组件化,对客户端隐藏具体实现;
- 简单工厂可以创建接口类,抽象类,具体类的实现等;
- example5 根据配置文件装载,实现可配置的简单工厂;
-
接口的思想就是“封装隔离”;
-
简单工厂的本质是:“选择实现”;
-
接口是一种特殊的抽象类,接口与抽象类的选择:
- 优先使用接口
- 在既要定义子类的行为,又要为子类提供公共的功能时,应使用抽象类
模式详解
- 优点:帮助封装(使组件外部能够真正的面向接口编程),解耦(客户端和具体实现的解耦)
- 缺点:增加了客户端的复杂度,不方便扩展子工厂(私有化简单工厂的构造方法使用了静态方法来创建接口,也就是不能写简单工厂的子工厂来改变创建接口的行为)
- 何时使用简单工厂:
- 封装隔离具体实现,只让外部通过接口来操作封装体;
- 把对外创建对象的 职责进行集中管理和控制;
- 相关模式(简单工厂、抽象工厂、工厂模式)
- 简单工厂通过选择实现,抽象工厂通过选择产品蔟实现;
- 简单工厂和工厂都是选择实现,工厂模式是将选择的时机延迟到子类去实现;
- 简单工厂是选择实现,可与其他创建对象的模式共同使用,如单例、原型、生成器模式等;
2、 外观模式(Facade)
- 引入问题:代码(service,dao等)生成器?
- 让子系统外部的客户端在使用子系统的时候,既能简单地使用这些子系统内部的模块功能,而又不用去与系统的多个模块交互
- 外观模式的定义:为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高级接口,这个接口使得这一子系统更加容易使用。
- 界面:从一个组件外部来看这个组件,能看到什么,就是这个界面的组件(例如 一个模块外部来看这个模块,这个模块的对外接口就是这个模块的外观)
- 接口: 这是是指外部与内部交互的一个通道。(通常是一些方法,或接口);
- 例如 代码生成器。
模式详解
- 外观模式的目的不是给子系统添加新的功能接口,而是为了让外部系统减少与子系统内多个模块的交互,松散耦合,从而让外部能够更简单的使用子系统。
- 外观模式主要是包装已有的功能,负责已有功能来实现客户需要,而不是添加新的功能。
- 优点 :松散耦合、简单易用、更好地划分访问的层次
- 缺点:过多或者不合理的Facade让人迷惑
- 外观模式的本质是:封装交互,简化调用;
- 外观模式体现了最少知识原则,客户端只需要与外观类交互,不用关心子模块内部的变动情况;
- 何时选用外观模式
- 1、为一个复杂系统提供一个简单接口,简化客户的使用;
- 2、客户程序和抽象类的实现部分松耦合;使用外观对象将子系统和他的客户分离开来,提升子系统的独立性;
- 3、构建多层结构系统;
- 相关模式
- 外观模式和中介者模式
- 中介者模式主要用来封装多个对象之间相互的交互,外观模式是单向的交互(客户端访问系统)
- 中介者模式的主要目的是松散多个模块的耦合,外观模式的目的是简化客户端的调用
- 外观模式和中介者模式
- 外观模式和单例模式
- Facade类实现为单例,可组合使用 - 外观模式和抽象工厂
- 外观类通常需要和系统内部的多个模块交互,每个模块一般都有自己的接口,所以在外观类的具体实现类里面,需要获取这些接口。
- 外观就可以和抽象工厂在一起使用。
3、适配器模式
- 引入问题:同时支持数据库和文件的日志管理
- 定义:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原来由于接口不兼容而不能一起工作的那些类可以一起工作。
模式讲解
- 适配器模式的主要功能是进行转换匹配,目的是复用已有的功能。本质是:转换匹配,复用功能;
- 适配器的实现方式其实是依靠对象组合的方式。
- 适配器通常是一个类,一般会让适配器类去实现Target接口,然后在适配器的具体实现里面调用Adaptee。(Adaptee:被适配的接口;Target:适配成为的接口;)
- 双向适配器: 适配器同时实现了Target和Adaptee的接口,使得双向适配器可以在Target或Adaptee被使用的地方使用;
- 对象适配器、类适配器
- 对象适配器的实现:依赖对象组合;
- 类适配器的实现:采用多重继承对一个接口与另外一个接口进行匹配;(Java不支持多重继承,Java 采取实现一个Target的接口,继承Adaptee的实现)
- 类适配器使用对象继承的方式,是静态方式,对象适配器使用对象组合的方式,是动态组合的方式;
- 对于类适配器,适配器继承了Adaptee后,就不可能去处理Adaptee的子类了;对象适配器就无所谓了
- 类适配器,可重定义Adaptee的部分行为;相当于子类覆盖父类的部分实现方法;
- 建议使用对象适配器的实现方法;
- 优点:复用性、扩展性;
- 缺点:会让系统非常零乱,不容易整体进行把握;
- 何时使用适配器模式
- 一个已经存在的类,接口不符合需求;
- 想使用一个已经存在的类,但是不可能对每一个子类进行适配,使用对象适配器,直接适配这些子类的父类;
- 创建一个可复用的类,这个类可能和一些不兼容的类一起工作;
- 相关模式
- 适配器模式与桥接模式
- 适配器是进行匹配转换,桥接是接口和实现相互分离,使它们可以相对独立地变化
- 适配器模式与装饰模式
- 适配器能模拟实现装饰模式的功能;两者都是使用的对象组合,但其目的和本质都是不一样的;
- 适配器模式与代理模式
- 适配器可以和代理模式组合使用(通过代理调用Adaptee);
- 适配器模式与抽象工厂模式
- 在适配器实现的时候,通常需要得到被适配的对象,如果被适配的是一个接口,可以结合一下创造对象实例的设计模式;
- 适配器模式与桥接模式
4、单例模式(Singleton)
- 引入问题:一个类只需要一个实例;
- 单例模式的本质:控释实例数目;
- 单例模式的定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点;
模式讲解
- 懒汉式、饿汉式、利用缓存方式
- 优缺点
- 懒汉式是时间换空间、饿汉式是空间换时间;
- 不加同步的懒汉式是线程不安全的、饿汉式是线程安全的;
- 利用双重检查加锁方式实现,既可以实现线程安全、又能使性能不受到很大的影响;volatile会屏蔽掉虚拟机中的一些代码优化,性能不是很高,因此一般建议,没有特别的需要,不要使用;
- Java中一个更好的单例实现方式
- 类级内部类
- 类级内部类:有static修饰的成员内部类,没有static修饰的是对象级内部类;
- 类级内部类相当于其外部类的static成分,它的对象与外部对象不存在依附关系,可直接进行创建;
- 类级内部类中,可定义静态的方法,静态方法中只能够引用外部类的 成员方法或者成员变量;
- 类级内部类相当于其外部类的成员,只有在第一次被使用的时候装载
- 多线程缺省
- 由静态初始化器(在静态字段或static{}块中的初始化)初始化数据时;
- 访问final字段时;
- 在创建线程之前创建对象时;
- 线程可以看见它将要处理的对象时
- 解决思路:类装载的时候不去初始化对象(采用类级内部类,在这个类级内部类里面创建对象实例),这样,只要不使用这个内部类,就不会创建对象实例,从而实现延迟加载和线程安全;
- 类级内部类
public class Singleton {
/**
* 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例没有绑定关系,
* 而且只有被调用到才会装载,从而实现了延迟加载
*/
private static class SingletonHolder{
/**
* 静态初始化器,由JVM来保证线程安全
*/
private static Singleton instance = new Singleton();
}
/**
* 私有化构造方法
*/
private Singleton(){
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}
5、工厂方法模式(Factory Method)
- 导出数据的应用框架,导出文本格式、excel、xml、数据库等格式
- 工厂方法模式的定义:定义一个用来创建对象的接口,让子类决定实例化哪一个类,Factory Method使一个类的实例化延迟到其子类;
- 工厂方法模式的解决思路就是不解决,采取无为而治的方式;
模式讲解
- 工厂方法模式的主要功能是让父类在不知道具体实现的情况下,完成自身的功能调用;而具体的实现延迟到子类来实现。这样、设计的时候不用去考虑具体实现,需要某个对象,把它通过工厂方法返回就好了,在使用这些对象实现功能的时候还是通过接口来操作。类似IOC/DId的思想;
- 实现成抽象类:工厂方法的实现中,通常父类是一个抽象类,里面包含创建所需对象的抽象方法,这些抽象方法就是工厂方法;
- 实现成具体的类:父类作为一个具体的类,在父类中提供所需对象的默认实现方法,这样即使没有具体的子类,也能够运行;
- 工厂方法的参数和返回
- 参数可进行选择
- 一般工厂方法返回的是被创建对象的接口对象,也可以是一个抽象类或者具体类的实现
- 谁来使用工厂方法创建的对象?
- 在工厂方法模式里面,客户端要么使用Creator对象,要么使用Creater创建的对象,一般客户端不直接使用工厂方法,当然也可以把工厂方法暴露给客户端操作,但一般不这么做;
- 通过给工厂方法传递参数,让工厂方法根据参数的不同来创建不同的产品对象;
- 工厂方法的优点:
- 可以在不知具体实现的情况下编程;
- 更容易扩展对象的新版本,工厂方法给子类提供一个挂钩,使得扩展新的对象版本变得非常容易;
- 工厂方法模式来连接平行的类层次
- 工厂方法模式很好体现了“依赖倒置原则”,即依赖抽象,不要依赖具体实现
- 何时选用工厂方法模式
- 如果一个类需要创建某个接口的对象,但又不知道具体实现
- 如果一个类本身就希望由它的子类来创建所需的对象的时候,应该使用工厂方法模式
- 相关模式
- 工厂方法模式和抽象工厂模式可组合使用
- 工厂方法模式和模板方法模式
- 都有一个抽象类,然后由子类提供一些实现,但工厂方法模式的子类专注于创建产品对象,而模板方法模式的子类专注为固定的算法股价提供某些步骤的实现;
6、抽象工厂模式(Abstract Factory)
-
引入问题:装机、DAO(数据访问对象)等
-
抽象工厂模式的定义:提供一个创建一些了相关或依赖对象的接口。而无需指定他们具体的类
-
抽象工程方法与工厂方法或简单工厂方法有很大不同的,工厂或简单工厂关注的是单个产品对象的创建,抽象工厂则是这一系列被创建的对象相互之间是有约束的。
-
抽象工厂的功能是为一系列相关对象或相互依赖的对象创建一个接口;
-
AbstractFactory在Java中通常实现为接口,定义了创建产品的接口,具体的实现是在实现类中,
装机问题结构示意图
-
抽象工厂定义了一个产品簇,切换一个产品簇的时候,只要提供不同的抽象工厂实现就可以了;
-
如果要在产品簇中增加一个产品,定义可扩展的工厂;(比较灵活的方式:抽象工厂方法顶一个一个方法 ,给这个方法设置一个参数,参考example4)
-
优点:分解接口和实现、使得切换产品簇容易;
-
缺点:不太容易扩展新的产品、容易造成类层次复杂;
-
抽象工厂模式的本质:选择产品簇的实现;
-
何时选用抽象工厂模式:
- 希望一个系统只是知道产品的接口,而不关心它的实现;
- 一个系统要多个产品系列中的一个来配置的时候;
- 要强调一系列相关产品的接口,以便联合使用他们的时候;
-
相关模式:
- 抽象工厂和工厂
- 既有区别,又有联系
- 工厂一般针对单个产品,抽象工厂一般针对产品簇
- 抽象工厂和单例
- 可组合使用,具体的工厂实现成为单例;
- 抽象工厂和工厂
7、生成器模式(Builder)
- 上例工厂模式每种格式的数据文件处理过程,应该和具体的步骤实现分开,这样就能够复用处理,而且很容易地切换不同地输出格式;
- 生成器模式的定义:将一个复杂对象的构建和它的表示分离,使得同样的构建过程可以创建不同的表示;
- 生成器模式主要功能是构建复杂的产品,一步一步解决构造复杂的对象的问题。
- 构建过程是统一的,固定不变的,变化的部分放到生成器部分,只要配置不同的生成器,那么同样的构建过程,就能构建出不同的产品来。
- 两个构成 (Builder都存在这两个部分,一个部分是部件构造和产品装配,另一个部件负责整体的构造算法);
- Builder接口,顶一个如何构建各个部件;
- Director, 整体的构建算法,而且通常是分步骤来执行;
- 生成器模式的实现
- 生成器的实现(builder接口,定义各个部件);
- 指导者实现,指导者只知道整体的构建算法;
- 指导者通过委托的方式 把功能交给生成器去完成;
- 实现一个返回装配好的产品的方法;
- 最后被构建的产品千差万别,没有必要提供统一接口;
- 使用生成器模式实现构复杂的构建对象
- 先不考虑带约束
- 其次考虑约束
- 把构建对象和被构建的对象合并(将类内联【私有化构造方法,提供静态内部类构建】)
- 生成器模式的优点
- 松散耦合
- 可以很容易地改变产品内部表示(产品内部隐藏实现)
- 更好的复用性(构建算法和具体产品相分离)
- 生成器模式的本质是:分离整体构建算法和部件构造;
- 生成器模式的中心还是在于分离整体构建算法和部件构造,而分步骤构建对象不过是整体构建算法的一个简单表现,或者说一个附带产物;
- 何时选用:同一个构建过程有着不同地表示;创建对象的算法,应该独立于该对象的组成部分以及它们的装配模式
- 相关模式:
- 生成器和工厂:可组合使用
- 生成器和抽象工厂:相似又区别,可组合使用,抽象工厂主要用来创建产品簇,生成器模式主要按照构建算法,一步一步构建一个复杂的对象;
- 生成器和模板:(类似)
- 模板模式主要用来定义算法的骨架,把算法中的某些步骤延迟到子类实现
- 生成器采用委托,模板采用继承
- 生成器模式和组合模式;可组合使用
- 谁来复制、复制谁的问题?
- 复制谁呢? 当然复制这个对象实例,复制实例就是连着数据一块复制;
- 谁来复制呢?应该让这个类的实例自己去复制自己;
- 如何克隆?
- new一个对象的实例,把自己实例的数据取出来,设置到新的对象实例中。
- 使用克隆方法? 客户端或方法等;
8、原型模式(Prototype)
- 抽象问题:已经有了某个对象实例后,如何能够快速简单地创建出更多的这个对象?
- 问题:订单拆分(一个人下了2560件商品,进行订单拆分(1000拆分一次),)。
- 原型模式的定义:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
- 原型模式会要求对象实现一个可以“克隆”自身的接口,这样就可以通过克隆或者拷贝一个实例对象本身创建一个新的实例。
- 原型模式的功能实际上包含两个方面:
- 一个是通过克隆来创建新的对象实例;
- 另一个是为克隆出来的新的对象实例复制原型实例属性的值;
- 原型实例和克隆出来的实例,本质上是不同的实例。克隆完成之后,它们之间是没有关联的。
- 浅度克隆和深度克隆
- 浅克隆:只负责克隆按值传递的数据(比如基本数据类型、String类型)
- 深克隆:除了浅克隆,还负责克隆引用类型(会递归)的数据。
模式讲解
- 认识原型模式:
- 一个通过克隆来创建新的对象实例;
- 另一个是为了克隆出来新的对象实例复制原型实例属性的值;
- 原型模式从某种意义上来说就是new 模式,原型与克隆出来的对象实质上是不同的实例。
- Java中深度克隆的实现
- 1、实现Cloneable接口
- 2、重写clone() ,使用super.clone()【开辟一块内存空间,把实例的值原样拷贝过去,基本类型没有问题,但是引用类型拷贝的是内存地址,所以需要进行重写设置】
- 3、手工对引用类型进行 setObj((Obj)this.obj.clone()) 方法。
- 在系统中维护一个当前可用的原型的注册表,这个注册表就被称为原型管理器。
- 原型模式优缺点:
- 优点:
- 对客户端隐藏具体的实现;
- 在运行时动态改变具体的实现类型;
- 缺点:
- 每个子类都必须实现clone操作,尤其在包含引用类型的对象的时候;
- 优点:
- 原型模式的本质:克隆生成对象。
- 何时选用原型模式:
- 一个系统想要独立于它想要使用的对象时,可使用原型模式
- 如果需要实例化的类是在运行时刻动态指定时,可以使用原型模式,通过克隆原型来得到需要的实例;
- 相关模式:
- 原型模式和抽象工厂模式有些相似;原型通过克隆,抽象工厂通过产品簇;
- 原型模式和生成器模式:生成器模式关注的是构建的过程,而在构建的过程中,很可能需要某i个部件的实例,可通过原型模式;
9、中介者模式(Mediator)
- 电脑中主板和CPU、内存、显卡等的关系
- 中介者模式的定义:用一个中介对象来封装一些列的对象交互。中介者使得对象不需要显示地互相引用,从而使其耦合松散,而且可以独立地改变它们之间的交互;
- 中介者模式通过引入一个中介对象,让其他的对象都只与中介对象交互,而中介对象知道如何和其他对象交互;
模式讲解
- 中介者模式的功能:封装对象之间的交互;
- 需要Mediator接口吗?看情况,这个接口用来封装中介者对象的;
- 同事关系:使用中介者对象来交互的那些对象称为同事类;
- 同时和中介者的关系:中介者对象和同时对象是相互依赖的;
- 实际开发中,经常简化中介者模式,来让开发变得简单
- 通常去掉同时对象的父类;
- 通常不定义Mediator接口,把具体的中介者对象实现为单例;
- 同事对象不再持有中介者,而是需要的时候直接获取中介者调用,中介者也不再持有同事对象,而是在具体处理方法里面去创建,或者获取,或者从参数传入需要的同事对象;
- 中介者模式的优缺点:
- 松散耦合、集中控制交互、多对多变成一对一
- 潜在缺点,过度集中化
- 中介者模式的本质:封装交互
- 何时选择中介者模式:
- 一组对象之间的通信方式比较复制,导致相互依赖;
- 一个对象引用很多对象,并直接与这些对象交互;
- 相关模式:
- 中介者模式和外观模式:
- 外观模式用来封装一个子系统内部的多个模块,即向子系统外部提供简单易用的接口;
- 中介者模式是提供多个平等的同事对象之间交互关系的封装;
- 中介者模式和观察者模式:
- 可组合使用,当同事对象改变时,通过通知中介对象,让中介对象与其他相关对象交互;
- 中介者模式和外观模式:
10、代理模式(Proxy)
- 抽象问题:当一次性访问的数据条数过多,而且每条描述的数据量又很大的话,将会消耗较多的额你存。
- 代理模式的定义:为其他对象提供一种代理以控制这个对象的访问。
模式讲解
- 代理模式的功能
- 通过创建一个代理对象,用这个代理对象去代表真实的对象;
- 代理的分类
-
![在这里插入图片描述](https://img-blog.csdnimg.cn/eb35ba3a00cc4482a270c82782293802.PNG?#pic_center)
- 最常见的是虚代理、保护代理、远程代理、智能指引这几种;
- Java中的代理:静态代理(上诉的代理)、动态代理(代理接口,使用反射机制 ; 代理类使用cglib)
- 代理模式的本质:控制访问对象;
- 何时选用代理模式:
- 需要为一个对象在不同的地址空间提供局部代表的时候,可以使用远程代理;
- 需要按照需要创建开销很大的对象的时候,可以使用虚代理;
- 需要控制对原始对象的访问的时候,可以使用保护代理;
- 需要在访问对象执行一些附加操作们可以使用智能指引代理;
- 相关模式:
- 代理模式和适配器模式(都为另一个对象提供间接性的访问):适配器主要用来接口之间不匹配的问题,而代理模式会实现和目标对象相同的接口;
- 代理模式和装饰模式(都是在转调其他对象的前后执行一定的功能):装饰器模式的目的是为了让你不生产子类就可以给对象添加职责,也就是为了动态地增加功能,代理模式的主要目的就是控制对象的访问;
11、观察者(订阅)模式(Observer)
- 抽象问题:当一个对象的状态发送改变的时候,如何让依赖于它的所有对象得到通知,并进行相应的梳理?
- 观察者模式:定义对象间的一种一对多的依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
模式讲解
- 目标和观察者模式:目标和观察者模式是典型的一对多的关系;观察者和目标是单向依赖的,只有观察者依赖于目标,而目标是不会依赖观察者的;
- 基本的实现说明:
- 具体的目标实现对象要能维护观察者的注册信息、维护引起通知的状态;
- 具体的观察者实例要能接收目标的通知
- 命名建议:
- 目标接口的定义,建议后跟Subject;
- 观察者接口的定义,建议后跟Observer;
- 观察者接口的更新方法,建议名称为update
- 触发通知的时机:一般情况下,一般是在完成了状态维护后触发。
- 相互观察:避免出现死循环;
- 通知的顺序:绝对不要依赖于通知的顺序,多个观察者之间的功能是平行的,相互不应该有先后的依赖关系;
- 观察者模式又分为推模式和拉模式;
- Java中的观察者模式:
- 新的目标类的实现,继承java.util.Obserable 类
- 新的观察者的实现,实现java.util.Observer 类,重写update方法
- 在目标类中状态改变之后,
//注意在用Java中的Observer模式的时候,这句话不可少 this.setChanged(); //然后主动通知,这里用的是推的方式 this.notifyObservers(this.content); //如果用拉的方式,这么调用 this.notifyObservers();
- 观察者模式的优缺点:
- 优点:
- 实现了观察者和目标之间的抽象耦合
- 动态联动
- 广播通信
- 缺点
- 引起无谓的操作
- 优点:
- 观察者模式的本质:触发联动
- 当修改目标对象的状态的时候,就会触发相应的通知,然后会循环调用所有注册的观察者对象的相应方法;
- 何时选用观察者模式
- 一个抽象模型有两个方面,一个方面的操作依赖另一个方面的变化;
- 更改一个对象的时候,需要同时连带改变其他的对象;
- 当一个对象必须通知其他的对象,但是又希望这个对象和其他被它通知的对象是松散耦合的;
- 相关模式
- 观察者模式和状态模式
- 观察者模式的重心在于触发联动;但是决定哪些观察者会被联动,就需要采用状态模式了;
- 观察者模式和中介者模式可组合使用;
- 观察者模式和状态模式
12、命令模式(Command)
- 命令模式的定义:将一个请求封装成一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作;
模式讲解
- 参考(Example3)
- 命令模式的关键之处就是把请求封装成对象,也就是命令对象,并定义了统一的执行操作的接口。Command接口
- 命令模式的组装和调用
- 命令模式的接收者可以是任意的类;
- 发起请求的对象和真正实现的对象是解耦的;
- 参数化配置:可以用不同的命令对象,去参数化配置客户的请求;
- 命令模式的优点:更松散的耦合、更动态的控制、很自然的复合命令、更好的扩展性
- 命令模式的本质:封装请求;
- 何时选用命令模式
- 如果需要抽象出需要执行的动作,并参数化这些对象;
- 如果需要在不同的时刻指定、排列和执行请求;
- 如果需要支持取消操作;
- 如果需要支持系统崩溃时,能将系统的操作重新执行一遍(实现日志命令,通过日志重写执行);
- 命令模式提供了事务进行建模的方法等;
- 相关模式:
- 命令模式和组合模式:可组合使用;
- 命令模式和备忘录模式:可组合使用;
- 命令模式和模板方法:命令模式可作为模板方法的一种替代模式;
13、迭代器模式(Iterator)
- 如何能够以一个统一的方式来访问内部实现不同的聚合对象;
- 迭代器模式的定义:提供一种方法顺序访问一个聚合对象中的各个元素,而又不需暴露该对象的内部表示。
- 参考example3
模式讲解
- 迭代器模式的功能:主要功能在于提供对聚合对象的迭代访问;
- 以不同的方式遍历整个迭代器(向前或向后);
- 对同一个聚合同时进行多个遍历;
- 以不同的遍历策略来遍历聚合;(比如是否需要过滤)
- 多态迭代;通过同一个迭代接口可以访问不同的聚合结构;
- 迭代器的关键思想:把聚合对象的遍历和访问从聚合对象中分离出来,放入单独的迭代器中;
- 内部迭代器和外部迭代器
- 内部迭代器是由迭代器自身来控制迭代下一个元素的步骤;
- 外部迭代器是由客户端显式调用next来迭代下一个元素;
- Java中的迭代器:例如 list.iterator();
- 带有策略策略的迭代器(过滤等,将目标的值过滤后放入迭代器中)
- 双向迭代器:同时向前和向后遍历数据的迭代器;
- 迭代器的优缺点:
- 更好的封装性
- 访问一个聚合对象的内容,无需暴露该聚合对象的内部表示;
- 不同的遍历方式来遍历一个聚合;
- 聚合对象和迭代算法相分离;
- 每一个迭代器保持它自己的遍历状态;
- 同一个聚合上可以有多个遍历;
- 迭代器模式的本质:控制访问聚合对象中的元素;
- 何时使用迭代器模式:
- 希望访问一个聚合对象的内容,又不想暴露它的内部表示;
- 希望有多种方式访问聚合对象;
- 为遍历不同的聚合对象提供一个统一的接口;
- 相关模式
- 迭代器模式和组合模式
- 在枚举某个组合对象的子对象的时候,通常使用迭代器模式;
- 迭代器模式和工厂方法模式
- 通过工厂方法实例化相应的迭代器
参考:
[1]: 《研磨设计模式》
- 通过工厂方法实例化相应的迭代器
- 迭代器模式和组合模式