设计模式

基础

1、抽象
父类为子类提供一些属性和行为,子类根据业务需求实现具体的行为。

抽象类使用abstract进行修饰,子类要实现所有的父类抽象方法否则子类也是抽象类。

2、封装
把对象的属性和行为(方法)结合为一个独立的整体,并尽可能隐藏对象的内部实现细节;

在java中,对于对象的内部属性一般用private来实现隐藏,并通过set和get方法对外提供访问接口。

3、继承
子类继承父类的属性和行为,并能根据自己的需求扩展出新的属性和行为,提高了代码的可复用性。

Java的继承通过extends关键字来实现,实现继承的类被称为子类,被继承的类称为父类(有的也称其为基类、超类),父类和子类的关系,是一种一般和特殊的关系;子类扩展父类,将可以获得父类的全部属性和方法。

overide:

当子父类中出现相同方法时,会先运行子类中的方法。

重写的特点:方法名一样,访问修饰符权限不小于父类,返回类型一致,参数列表一致。

4、多态
不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态;

具体的实现方式就是:接口实现,继承父类进行方法重写,同一个类中进行方法重载。

封装和继承都是为Java语言的多态提供了支撑;多态存在的三个必要条件:

要有继承; 要有重写; 父类引用指向子类对象。

设计原则

1、开闭原则(OCP)是面向对象设计中“可复用设计”的基石,是面向对象设计中最重要的原则之一,其它很多的设计原则都是实现开闭原则的一种手段。

开闭原则中“开”,是指对于组件功能的扩展是开放的,是允许对其进行功能扩展的;
开闭原则中“闭”,是指对于原有代码的修改是封闭的,即不应该修改原有的代码。

2、面向接口编程,不针对实现编程;

3、多用组合,少用继承;

4、为交互对象之间的松耦合设计而努力;

5、类应该对扩展开放,对修改关闭;

6、依赖抽象,不要依赖具体的实现类;

7、只和朋友交谈;

8、别找我,我会找你;

9、类应该只有一个改变的理由;

装饰者:包装另一个对象,并提供额外的行为。

外观:包装许多对象以简化它们的接口。

代理:包装另一个对象,并控制对它的访问。

适配器:包装另一个对象,并提供不同的接口。

1、根据完成什么工作来划分

这种方式可分为创建型模式、结构型模式和行为型模式3种。

创建型模式:用于描述“怎样创建对象”,它的主要特点是“将对象的创建与使用分离”。GoF 中提供了单例、原型、工厂方法、抽象工厂、建造者等5种创建型模式。

结构型模式:用于描述如何将类或对象按某种布局组成更大的结构,GoF 中提供了代理、适配器、桥接、装饰、外观、享元、组合等7种结构型模式。

行为型模式:用于描述类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,以及怎样分配职责。GoF 中提供了模板方法、策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录、解释器等11种行为型模式。

创建型模式

这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。

这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。

1、单例模式
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

注意:

1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。

意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

主要解决:一个全局使用的类频繁地创建与销毁。

何时使用:当您想控制实例数目,节省系统资源的时候。

如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。

关键代码:构造函数是私有的。

应用实例:

1、一个班级只有一个班主任。
2、一些设备管理器常常设计为单例模式,比如一个电脑有两台打印机,在输出的时候就要处理不能两台打印机打印同一个文件。

优点:
1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
2、避免对资源的多重占用(比如写文件操作)。

缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

使用场景:
1、要求生产唯一序列号。
2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。

注意事项:getInstance() 方法中需要使用同步锁 synchronized (Singleton.class) 防止多线程同时进入造成 instance 被多次实例化。

2、工厂模式
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

主要解决:主要解决接口选择的问题。

何时使用:我们明确地计划不同条件下创建不同实例时。

如何解决:让其子类实现工厂接口,返回的也是一个抽象的产品。

关键代码:创建过程在其子类执行。

应用实例: 1、您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。 2、Hibernate 换数据库只需换方言和驱动就可以。

优点: 1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口。

缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

使用场景:设计一个连接服务器的框架,需要三个协议,“POP3”、“IMAP”、“HTTP”,可以把这三个作为产品类,共同实现一个接口。

注意事项:作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。

3、原型模式
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。

意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

主要解决:在运行期建立和删除原型。

何时使用: 1、当一个系统应该独立于它的产品创建,构成和表示时。 2、当要实例化的类是在运行时刻指定时,例如,通过动态装载。 3、为了避免创建一个与产品类层次平行的工厂类层次时。 4、当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。

如何解决:利用已有的一个原型对象,快速地生成和原型对象一样的实例。

关键代码: 1、实现克隆操作,在 JAVA 继承 Cloneable,重写 clone(),在 .NET 中可以使用 Object 类的 MemberwiseClone() 方法来实现对象的浅拷贝或通过序列化的方式来实现深拷贝。 2、原型模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些"易变类"拥有稳定的接口。

应用实例: 1、细胞分裂。 2、JAVA 中的 Object clone() 方法。

优点: 1、性能提高。 2、逃避构造函数的约束。

缺点: 1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。 2、必须实现 Cloneable 接口。

使用场景: 1、资源优化场景。 2、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。 3、性能和安全要求的场景。 4、通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。 5、一个对象多个修改者的场景。 6、一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。 7、在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与 Java 融为浑然一体,大家可以随手拿来使用。

注意事项:与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。浅拷贝实现 Cloneable,重写,深拷贝是通过实现 Serializable 读取二进制流。

4、抽象工厂模式
抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

主要解决:主要解决接口选择的问题。

何时使用:系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。

如何解决:在一个产品族里面,定义多个产品。

关键代码:在一个工厂里聚合多个同类产品。

优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。

缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。

使用场景: 1、QQ 换皮肤,一整套一起换。 2、生成不同操作系统的程序。

注意事项:产品族难扩展,产品等级易扩展。

5、建造者模式
建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

一个Builder类会一步一步构造最终的对象。该Builder类是独立于其他对象的。

意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。

主要解决:主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。

何时使用:一些基本部件不会变,而其组合经常变化的时候。

如何解决:将变与不变分离开。

关键代码:建造者:创建和提供实例,导演:管理建造出来的实例的依赖关系。

应用实例: 1、去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"。 2、JAVA 中的 StringBuilder。

优点: 1、建造者独立,易扩展。 2、便于控制细节风险。

缺点: 1、产品必须有共同点,范围有限制。 2、如内部变化复杂,会有很多的建造类。

使用场景: 1、需要生成的对象具有复杂的内部结构。 2、需要生成的对象内部属性本身相互依赖。

注意事项:与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。

结构型模式

这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。

1、代理模式
代理的作用:控制和访问

代理(proxy):代表某个真实的对象。在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。

在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。

意图:为其他对象提供一种代理以控制对这个对象的访问。

主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。

何时使用:想在访问一个类时做一些控制。

如何解决:增加中间层。

关键代码:实现与被代理类组合。

应用实例: 1、Windows 里面的快捷方式。2、买火车票不一定在火车站买,也可以去代售点。3、spring aop。

优点:1、职责清晰。 2、高扩展性。 3、智能化。

缺点:1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

使用场景:按职责来划分,通常有以下使用场景: 1、远程代理。 2、虚拟代理。 3、Copy-on-Write 代理。 4、保护(Protect or Access)代理。 5、Cache代理。 6、防火墙(Firewall)代理。 7、同步化(Synchronization)代理。 8、智能引用(Smart Reference)代理。

适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。

装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。

远程代理控制访问远程对象;

虚拟代理控制访问创建开销大的资源;

保护代理基于权限控制对资源的访问;

2、适配模式
将接口转化成不同的接口

3、外观模式
将接口简化

4、装饰器模式
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

回想一下java当中的各种输入输出流,各种功能一层嵌套一层,就好像不断得给一个产品加功能,加完以后在消费者看来,原来是是什么产品现在还是什么产品,只不过用的时候功能增加了。

背景:

想要给这样的一个产品加功能,一开始的设想便是直接往产品的类中加方法,用的时候方法调方法,简单暴力。但是这样做有一个很大的缺点:如果某一天我们想把这个A功能卸下来,我们不得不把调用了A功能函数的代码注释,这样很麻烦,当代码量大的时候,很容易出问题。

目的:

实现不用改产品的源代码,也能实现产品功能的加减。

四大部件

1、抽象组件:需要装饰的抽象对象(接口或抽象父类)

2、具体组件:需要装饰的对象

3、抽象装饰类:包含了对抽象组件的引用以及装饰者共有的方法(draw()😉

4、具体装饰类:被装饰的对象

装饰设计模式的继承关系:

装饰设计模式的调用关系:

5、组合模式
组合模式(Composite Pattern)又叫做部分整体模式,是用于把一组相似的对象当作一个单一的对象,组合模式依据树形结构来组成对象,用来表示部分以及整体层次,这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。这种模式创建了一个包含自己对象组的类,该类提供了修改相同对象组的方式。

意图:将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

主要解决:它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。

何时使用:1、您想表示对象的部分-整体层次结构(树形结构)。2、您希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

如何解决:树枝和叶子实现统一接口,树枝内部组合该接口。

关键代码:树枝内部组合该接口,并且含有内部属性 List,里面放 Component。

应用实例:1、算术表达式包括操作数、操作符和另一个操作数,其中,另一个操作符也可以是操作数、操作符和另一个操作数。2、在JAVA AWT 和 SWING 中,对于 Button 和 Checkbox 是树叶,Container 是树枝。

优点: 1、高层模块调用简单。2、节点自由增加。

缺点:在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。

使用场景:部分、整体场景,如树形菜单,文件、文件夹的管理。

注意事项:定义时为具体类。

组合模式以单一责任设计原则换取透明性。透明性:通过让组件的接口同时包含一些管理子节点和叶节点的操作,用户可以将组合和叶节点一视同仁。也就是说,一个元素是组合还是叶节点对客户而言是透明的。

组合:当有数个对象的结合,它们彼此之间有“整体/部分“的关系,并且你想用一致的方法对待这些对象时,需要用到组合。组合对象:包含其他组件的组件。叶节点对象:没有包含其他组件的组件。

6、桥接模式
桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。

这种模式涉及到一个作为桥接的接口,使得实体类的功能独立于接口实现类。这两种类型的类可被结构化改变而互不影响。

我们通过下面的实例来演示桥接模式(Bridge Pattern)的用法。其中,可以使用相同的抽象类方法但是不同的桥接实现类,来画出不同颜色的圆。

意图:将抽象部分与实现部分分离,使它们都可以独立的变化。

主要解决:在有多种可能会变化的情况下,用继承会造成类爆炸问题,扩展起来不灵活。

何时使用:实现系统可能有多个角度分类,每一种角度都可能变化。

如何解决:把这种多角度分类分离出来,让它们独立变化,减少它们之间耦合。

关键代码:抽象类依赖实现类。

应用实例: 1、猪八戒从天蓬元帅转世投胎到猪,转世投胎的机制将尘世划分为两个等级,即:灵魂和肉体,前者相当于抽象化,后者相当于实现化。生灵通过功能的委派,调用肉体对象的功能,使得生灵可以动态地选择。 2、墙上的开关,可以看到的开关是抽象的,不用管里面具体怎么实现的。

优点: 1、抽象和实现的分离。 2、优秀的扩展能力。 3、实现细节对客户透明。

缺点:桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。

使用场景: 1、如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。 2、对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。 3、一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。

注意事项:对于两个独立变化的维度,使用桥接模式再适合不过了。

7、享元模式
享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。

享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。我们将通过创建 5 个对象来画出 20 个分布于不同位置的圆来演示这种模式。由于只有 5 种可用的颜色,所以 color 属性被用来检查现有的 Circle 对象。

意图:运用共享技术有效地支持大量细粒度的对象。

主要解决:在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。

何时使用: 1、系统中有大量对象。 2、这些对象消耗大量内存。 3、这些对象的状态大部分可以外部化。 4、这些对象可以按照内蕴状态分为很多组,当把外蕴对象从对象中剔除出来时,每一组对象都可以用一个对象来代替。 5、系统不依赖于这些对象身份,这些对象是不可分辨的。

如何解决:用唯一标识码判断,如果在内存中有,则返回这个唯一标识码所标识的对象。

关键代码:用 HashMap 存储这些对象。

应用实例: 1、JAVA 中的 String,如果有则返回,如果没有则创建一个字符串保存在字符串缓存池里面。 2、数据库的数据池。

优点:大大减少对象的创建,降低系统的内存,使效率提高。

缺点:提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,不应该随着内部状态的变化而变化,否则会造成系统的混乱。

使用场景: 1、系统有大量相似对象。 2、需要缓冲池的场景。

注意事项: 1、注意划分外部状态和内部状态,否则可能会引起线程安全问题。 2、这些类必须有一个工厂对象加以控制。

eg:我们将创建一个 Shape 接口和实现了 Shape 接口的实体类 Circle。下一步是定义工厂类 ShapeFactory。

ShapeFactory 有一个 Circle 的 HashMap,其中键名为 Circle 对象的颜色。无论何时接收到请求,都会创建一个特定颜色的圆。ShapeFactory 检查它的 HashMap 中的 circle 对象,如果找到 Circle 对象,则返回该对象,否则将创建一个存储在 hashmap 中以备后续使用的新对象,并把该对象返回到客户端。

8、拦截过滤器模式
拦截过滤器模式(Intercepting Filter Pattern)用于对应用程序的请求或响应做一些预处理/后处理。定义过滤器,并在把请求传给实际目标应用程序之前应用在请求上。过滤器可以做认证/授权/记录日志,或者跟踪请求,然后把请求传给相应的处理程序。以下是这种设计模式的实体。

过滤器(Filter) - 过滤器在请求处理程序执行请求之前或之后,执行某些任务。

过滤器链(Filter Chain) - 过滤器链带有多个过滤器,并在 Target 上按照定义的顺序执行这些过滤器。

Target - Target 对象是请求处理程序。

过滤管理器(Filter Manager) - 过滤管理器管理过滤器和过滤器链。

客户端(Client) - Client 是向 Target 对象发送请求的对象。

我们将创建 FilterChain、FilterManager、Target、Client 作为表示实体的各种对象。AuthenticationFilter 和 DebugFilter 表示实体过滤器。

InterceptingFilterDemo,我们的演示类使用 Client 来演示拦截过滤器设计模式。

行为型模式

这些设计模式特别关注对象之间的通信。

1、策略模式
多态

在策略模式中,一个行为可以在系统运行时动态修改。这种类型设计模式是行为型设计模式,策略模式中,会有代表各种策略的对象和执行策略的context上下文对象。策略对象改变context执行的算法。

eg:出门旅行,拥有很多出行策略,比如飞机,汽车,火车等;

支付系统中,有很多支付策略,比如支付宝,微信,银联。在支付时需要选择其中一种支付策略进行支付业务。

简要介绍

用途:定义一系列策略,他们实现自己的算法,使用策略模式实现在运行时动态替换各个策略。

解决难点:在有很多类似算法的实现中,使用 if … else 会造成难以维护和拓展。

使用场景:在一个系统中有很多类,它们之间唯一的区别只在与行为的不同,而且需要系统动态选择这些行为中的一种,如果不使用适当的设计模式,就会产生多重条件选择语句。

2、观察者模式
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。

意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

何时使用:一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。

如何解决:使用面向对象技术,可以将这种依赖关系弱化。

关键代码:在抽象类里有一个 ArrayList 存放观察者们。

应用实例: 1、拍卖的时候,拍卖师观察最高标价,然后通知给其他竞价者竞价。

优点: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。

缺点: 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

使用场景:

一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。

一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。

一个对象必须通知其他对象,而并不知道这些对象是谁。

需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。

注意事项: 1、JAVA 中已经有了对观察者模式的支持类。 2、避免循环引用。 3、如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。

其实就是发布订阅模式,发布者发布信息,订阅者获取信息,订阅了就能收到信息,没订阅就收不到信息。

3、命令模式
命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。

意图:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。

主要解决:在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。

何时使用:在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。

如何解决:通过调用者调用接受者执行命令,顺序:调用者→接受者→命令。

关键代码:定义三个角色:1、received 真正的命令执行对象 2、Command 3、invoker 使用命令对象的入口

应用实例:struts 1 中的 action 核心控制器 ActionServlet 只有一个,相当于 Invoker,而模型层的类会随着不同的应用有不同的模型类,相当于具体的 Command。

优点:1、降低了系统耦合度。2、新的命令可以很容易添加到系统中去。

缺点:使用命令模式可能会导致某些系统有过多的具体命令类。

使用场景:认为是命令的地方都可以使用命令模式,比如: 1、GUI 中每一个按钮都是一条命令。 2、模拟 CMD。

注意事项:系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作,也可以考虑使用命令模式,见命令模式的扩展。

包括三个核心对象:

1、调用者(Invoker):持有一个命令对象,并在某个时间点调用命令对象的execute()方法。
2、命令对象(Command):持有一个接收者,和一个execute()方法,在execute中执行接收者的动作。
3、接收者(Receiver):动作的执行者。

4、模板方法模式
在一个方法中定义一个算法的骨架,而将一写步骤延迟到子类中,模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

5、迭代器模式
作用:封装遍历

依赖于一个迭代器的接口,这个迭代器需要有hasNext()和next()两个方法;

集合Collection:指的是一群对象,其存储方式可以是多种多样的数据结构,例如:列表,数组,散列表,无论用什么方式存储,一律可以视为是集合,有时也可以称之为“聚合“。

迭代器定义:提供一个方法顺序访问一个聚合对象的各个元素,而不暴露其内部的表示;

这个模式提供了一种方法,可以顺序的访问一个聚合对象中的元素,而又不用知道内部是如何表示的。如果有一个统一的方法访问聚合中的每一个对象,就可以编写多态的代码和这些聚合类搭配,使方法更加简单易维护。

迭代器模式把元素之间游走的责任交给迭代器,而不是聚合对象。

内聚:它用来度量一个类或模块紧密地达到单一目的或责任。

6、状态模式
策略模式和状态模式。

如何对对象内的状态建模——通过创建一个实例对象来持有状态值,并在方法内书写条件代码来处理不同状态。

首先定义全局变量来设置几个状态值,然后通过state来表明当前持有的状态值。

Tips:

局部化每个状态的行为,这样如果针对某个状态做了改变,那么就不会把其他的代码给搞乱了。也就是遵循“封装”原则,如果将每个状态的行为都放在各组的类中,那么每个状态只要实现它自己的动作就可以了。糖果机只需要委托给代表当前状态的状态对象。

状态模式:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

使用组合通过简单引用不同的状态对象来造成类改变的假象。

在个别的状态类中封装状态行为,结果总是会增加这个设计中类的数目,这就是为了获取弹性而付出的代价。

7、职责链模式
责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。

在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。

意图:避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。

主要解决:职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。

何时使用:在处理消息的时候以过滤很多道。

如何解决:拦截的类都实现统一接口。

关键代码:Handler 里面聚合它自己,在 HandlerRequest 里判断是否合适,如果没达到条件则向下传递,向谁传递之前 set 进去。

应用实例: 1、红楼梦中的"击鼓传花"。 2、JS 中的事件冒泡。 3、JAVA WEB 中 Apache Tomcat 对 Encoding 的处理,Struts2 的拦截器,jsp servlet 的 Filter。

优点: 1、降低耦合度。它将请求的发送者和接收者解耦。 2、简化了对象。使得对象不需要知道链的结构。 3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。 4、增加新的请求处理类很方便。

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

使用场景: 1、有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。 2、在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。 3、可动态指定一组对象处理请求。

注意事项:在 JAVA WEB 中遇到很多应用。

8、中介者模式
中介者模式(Mediator Pattern)是用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护。中介者模式属于行为型模式。

意图:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

主要解决:对象与对象之间存在大量的关联关系,这样势必会导致系统的结构变得很复杂,同时若一个对象发生改变,我们也需要跟踪与之相关联的对象,同时做出相应的处理。

何时使用:多个类相互耦合,形成了网状结构。

如何解决:将上述网状结构分离为星型结构。

关键代码:对象 Colleague 之间的通信封装到一个类中单独处理。

应用实例: 1、中国加入 WTO 之前是各个国家相互贸易,结构复杂,现在是各个国家通过 WTO 来互相贸易。 2、机场调度系统。 3、MVC 框架,其中C(控制器)就是 M(模型)和 V(视图)的中介者。

优点: 1、降低了类的复杂度,将一对多转化成了一对一。 2、各个类之间的解耦。 3、符合迪米特原则。

缺点:中介者会庞大,变得复杂难以维护。

使用场景: 1、系统中对象之间存在比较复杂的引用关系,导致它们之间的依赖关系结构混乱而且难以复用该对象。 2、想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。

注意事项:不应当在职责混乱的时候使用。

9、访问者模式
访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。

意图:主要将数据结构与数据操作分离。

主要解决:稳定的数据结构和易变的操作耦合问题。

何时使用:需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,使用访问者模式将这些封装到类中。

如何解决:在被访问的类里面加一个对外提供接待访问者的接口。

关键代码:在数据基础类里面有一个方法接受访问者,将自身引用传入访问者。

应用实例:您在朋友家做客,您是访问者,朋友接受您的访问,您通过朋友的描述,然后对朋友的描述做出一个判断,这就是访问者模式。

优点: 1、符合单一职责原则。 2、优秀的扩展性。 3、灵活性。

缺点: 1、具体元素对访问者公布细节,违反了迪米特原则。 2、具体元素变更比较困难。 3、违反了依赖倒置原则,依赖了具体类,没有依赖抽象。

使用场景: 1、对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。 2、需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类。

注意事项:访问者可以对功能进行统一,可以做报表、UI、拦截器与过滤器。

10、备忘录模式
备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。

意图:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。

主要解决:所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。

何时使用:很多时候我们总是需要记录一个对象的内部状态,这样做的目的就是为了允许用户取消不确定或者错误的操作,能够恢复到他原先的状态,使得他有"后悔药"可吃。

如何解决:通过一个备忘录类专门存储对象状态。

关键代码:客户不与备忘录类耦合,与备忘录管理类耦合。

应用实例:1、打游戏时的存档。 2、Windows 里的 ctri + z。 3、IE 中的后退。 4、数据库的事务管理。

优点: 1、给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态。 2、实现了信息的封装,使得用户不需要关心状态的保存细节。

缺点:消耗资源。如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存。

使用场景: 1、需要保存/恢复数据的相关状态场景。 2、提供一个可回滚的操作。

注意事项: 1、为了符合迪米特原则,还要增加一个管理备忘录的类。 2、为了节约内存,可使用原型模式+备忘录模式。

备忘录模式使用三个类 Memento、Originator 和 CareTaker。Memento 包含了要被恢复的对象的状态。Originator 创建并在 Memento 对象中存储状态。Caretaker 对象负责从 Memento 中恢复对象的状态。

MementoPatternDemo,我们的演示类使用 CareTaker 和 Originator 对象来显示对象的状态恢复。

11、解释器模式
解释器模式(Interpreter Pattern)提供了评估语言的语法或表达式的方式,它属于行为型模式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文。这种模式被用在 SQL 解析、符号处理引擎等。

意图:给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子。

主要解决:对于一些固定文法构建一个解释句子的解释器。

何时使用:如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。

如何解决:构建语法树,定义终结符与非终结符。

关键代码:构建环境类,包含解释器之外的一些全局信息,一般是 HashMap。

应用实例:编译器、运算表达式计算。

优点: 1、可扩展性比较好,灵活。 2、增加了新的解释表达式的方式。 3、易于实现简单文法。

缺点: 1、可利用场景比较少。 2、对于复杂的文法比较难维护。 3、解释器模式会引起类膨胀。 4、解释器模式采用递归调用方法。

使用场景: 1、可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。 2、一些重复出现的问题可以用一种简单的语言来进行表达。 3、一个简单语法需要解释的场景。

注意事项:可利用场景比较少,JAVA 中如果碰到可以用 expression4J 代替。

eg:我们将创建一个接口 Expression 和实现了 Expression 接口的实体类。定义作为上下文中主要解释器的 TerminalExpression 类。其他的类 OrExpression、AndExpression 用于创建组合式表达式。

InterpreterPatternDemo,我们的演示类使用 Expression 类创建规则和演示表达式的解析。

12、空对象模式
空对象模式(Null Object Pattern)中,一个空对象取代 NULL 对象实例的检查。Null 对象不是检查空值,而是反应一个不做任何动作的关系。这样的 Null 对象也可以在数据不可用的时候提供默认的行为。

在空对象模式中,我们创建一个指定各种要执行的操作的抽象类和扩展该类的实体类,还创建一个未对该类做任何实现的空对象类,该空对象类将无缝地使用在需要检查空值的地方。

我们将创建一个定义操作(在这里,是客户的名称)的 AbstractCustomer 抽象类,和扩展了 AbstractCustomer 类的实体类。工厂类 CustomerFactory 基于客户传递的名字来返回 RealCustomer 或 NullCustomer 对象。

NullPatternDemo,我们的演示类使用 CustomerFactory 来演示空对象模式的用法。

其他新增模式

空对象模式

MVC 模式

业务代表模式

组合实体模式

数据访问对象模式

前端控制器模式

服务定位器模式

传输对象模式

复合模式:由多种模式构成的一种模式。复合模式必须够一般性,适合解决许多

复合模式的典型例子:MVC模式

组合和继承
组合(复合)概念:在类中增加一个私有域,引用另一个已有的类的实例,通过调用引用实例的方法从而获取新的功能,这种设计被称为组合(复合) EG:car类中有tire(轮胎)对象

组合:通过对现有对象进行拼装和组合使目前的对象具有更多复杂的功能;
继承:子类继承父类使子类具有跟父类相同的实例和方法;

继承与组合的区别与联系

继承:子类中extends父类。
组合:在一个类中声明另一个类的对象。

继承和组合都是面向对象中代码复用的方式。父类的内部细节对子类可见,其代码属于白盒式的复用,而组合中,对象之间的内部细节不可见,其代码属于黑盒式复用。继承在编码过程中就要指定具体的父类,其关系在编译期就确定,而组合的关系一般在运行时确定。继承强调的是is-a的关系,而组合强调的是has-a的关系。

对类功能的扩展为什么要多用组合,少用继承

1、子类对父类的继承是全部的public和protected的继承,有一些子类可能只需要继承父类的一部分方法。
2、继承的太多会造成类的无限膨胀,会使系统结构较复杂。
3、继承满足不了需要在运行时确定对象的情况,组合可以。

继承和组合的使用地方:
优点明显多于继承,再加上java中仅支持单继承,所以除非两个类之间是is-a的关系,否则尽量使用组合。

第二次记录

观察者模式
观察者模式的通用代码:

1、目标对象的定义;
2、具体的目标对象的定义;
3、观察者接口的定义;
4、观察者的具体实现;

观察者模式:目标者和订阅者,目标提供删除订阅者,添加订阅者和通知订阅者的方法(调用订阅者的update),并且有定义一个观察者列表属性用于存储订阅者,订阅者中定义一个update方法来更新消息。

六大方面:

1、目标与观察者直接的关系:一个观察者可以观察多个目标(观察者需要为每个目标写update函数),一个目标可以被多个观察者订阅。
2、单向依赖:观察者被动等待目标的通知;
3、命名建议:发布-订阅模式

(1)目标接口的定义,建议在名称后面跟Subject
(2)观察者接口的定义,建议在名称后面跟Observer
(3)观察者接口的更新方法,建议名称为update

4、触发通知的时机:先设置消息值,再通知

5、观察者模式的调用顺序示意图

6、通知的顺序:多个观察者之间的顺序是平行的,观察者之间不应该有依赖关系。

实现的两种方式

1、推模型:目标对象主动向观察者推送目标的详细信息,不管观察者是否需要,推送的信息通常是目标对象的全部或部分数据(直接将Msg信息发给观察者)。

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

两种模型的比较

1、推模式是假定目标对象知道观察者需要的数据,拉模式是目标对象不知道观察者具体需要什么数据,因此把自身传给观察者,具体的值由观察者来取。

2、推模型会使观察者对象难以复用,因为观察者的update是按需定制的,出现新的情况需要重新写update

3、拉模式的update的参数是目标对象本身,是可以传递的数据最大值,基本上可以适应各种情况的需要。

利用java提供的观察者实现

1、目标直接extends Observable

2、观察者实现implements Observer

3、在消息通知的时候,调用this.setChanged();

ATT:

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

观察者模式的优点

1、观察者模式实现了观察者和目标之前的抽象耦合
2、观察者模式实现了动态联动
3、观察者模式支持广播通信

观察者的缺点

1、引起无谓的操作(广播形式通知观察者)

什么时候需要用到观察者模式:触发联动

1、当一个抽象模型有两个方面,其中一个方面的操作依赖于另一个方面的状态变化。
2、如果在更改一个对象的时候,需要同时连带改变其他的对象,而且不知道究竟应该有多少对象需要被连带修改。
3、当一个对象必须通知其他的对象,但是你又希望这个对象和其他被通知的对象是松散耦合的。

区别对待观察者:在notifyObservers函数中对订阅对象和消息做判断,针对不同的Msg和observer判断再调用update()

策略模式
背景:对文本文档进行排版编辑,根据用户要求会有不同的布局结果。支付的时候,会有不同的支付策略。

策略模式:

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

make duck fly:

1、继承:会让所有的duck都有fly行为

2、抽象方法:工作量大

3、组合:写一个flyBehavior接口

策略模式中的设计原则:

1、找出应用中需要变化的行为,把他们独立出来,不要和那些不需要变化的代码混在一起。

2、面向接口编程,不要面向实现编程

3、多用组合少用继承

策略模式的实现:

1、通过分离变化得出策略接口Strategy(FlyBehavior)

2、Strategy的实现类(FlyWithWing,FlyWithRocket)

3、客户程序中有一个“Strategy”

4、客户程序中选择/组装正确的Strategy实现(MallardDuck、DubberDuck)

策略模式优点:

1、使用组合,架构更加灵活;

2、富有弹性,可以较好的应对变化(开-闭原则)

3、更好的代码复用性(相对于继承)

4、消除大量的条件语句

策略模式缺点:

1、客户代码需要了解每个策略实现的细节(需要知道有多少个策略模式)

model.setFlyBehavior(new FlyRocketPowered()); //多态的应用

2、增加了对象的数目(new了很多策略对象)

策略模式的使用场景:

1、许多相关的类仅仅只有行为差异

2、运行时选取不同的算法变体(支付时仅仅只能选择一种支付方式)

3、通过条件语句在多个分支中选取其中某个行为

装饰者模式
为什么要使用装饰者模式

如果子类继承父类,那么我们要写很多子类,这样无疑会增加程序的臃肿性,并不是很灵活。

装饰者模式的的概念

装饰者模式又成包装模式,可以动态的给一个对象添加一些额外的职责。就扩展功能而言,它比子类的方式更为灵活。

适应环境

1、以动态的方式给对象添加职责。

2、处理那些可以撤销的职责。

3、当采用生成子类的方法进行扩展时,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈现爆炸性增长。

装饰者模式的结构

抽象组件:给出一个抽象接口,以规范准备接受附加责任的对象。
被装饰者:Component的具体实现,也就是我们要装饰的具体对象。

抽象工厂模式和抽象工厂模式的区别

抽象工厂模式提供一个创建一系列相关或相互依赖的对象的接口,而无需指定它们具体的类。

这两种设计模式主要的区别在于产品,工厂模式是用来创建同一个产品的不同类型的,比如只卖包子。但是抽象工厂模式是用来创建不同类的产品,比如包子店还卖豆浆油条。一般来说,产品种类单一,适合用工厂模式;如果有多个种类,各种类型时,通过抽象工厂模式来进行创建是很合适的。

简单工厂模式

工厂模式

抽象工厂模式

推模式:Msg
拉模式:目标对象

单例模式:一个类仅仅只向外面提供一个对象(资源)
工厂模式:一个类提供很多创建各种对象的方法 各种产品

抽象:各种产品
策略模式:behavior 组合+多态
装饰者模式:给一个类添加新的额外的功能
原型模式:prototype,继承cloneable,实现clone方法,将不同的对象放在一个map里面,根据id调用相应对象的clone方法

有多种不同的产品,将这些产品的抽象再次的抽象出来,就是抽象工厂模式。

建造者模式
建造者:一步一步的创建一个对象,它对用户屏蔽了里面构建的细节,但是可以精细地控制对象的构造过程。

建造者模式

建造者模式跟抽象工厂模式的区别:建造者模式需要知道产品具体实现的细节,而抽象工厂模式不需要知道。

使用的场景:

1、产品对象内部具有复杂的结构,产品对象包括多个成员属性,适用建造者模式可以隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的对象。
2、相同的方法,不同的执行顺序,产生不同的事件结果。

桥接者模式
背景:当发现类有多层继承时就可以考虑使用桥接模式,用聚合代替继承。

桥接模式:将抽象部分与它的实现部分分离,使它们都可以独立地变化。

att:在Abstraction和Implementor之间架了一座桥(聚合线),这里体现了一个原则就是合成/聚合复用原则。

Abstraction:抽象化角色,定义出该角色地行为,同时保存一个对实现化角色的引用;
Implementor:实现化角色,是接口或者抽象类,定义角色必需的行为和属性;
RefinedAbstraction:修正抽象化角色,引用实现化角色对抽象化角色进行修正;
ConcreteImplementor:具体实现化角色,实现接口或抽象类定义的方法或属性;

何时使用:

1、系统可能有多个角度分类,每一种角度都可能变化时;
2、不希望或不适用使用继承的场景,当继承有N层很多时;
3、接口或抽象类不稳定的场景;
4、重用性要求较高的场景;

方法:把这种角度分类分离出来,让他们单独变化,减少它们之间的耦合(合成/聚合复用原则);

桥接模式是为了解决继承的缺点而提出的设计模式;

享元模式
享元技术是池技术(String常量池、数据库连接池、缓冲池)的重要实现方式。

背景:在创建字符串对象的时候,如果每次都创建一个新的字符串对象,内存的开销会非常大。所以第一次创建了字符串对象’A’,下次再创建字符串对象’A’时,只是把它的引用指向’A’,这样就实现了’A’字符串在内存中的共享。

享元模式需要:细粒度和共享对象。

因为要求细粒度对象,所以不可避免地会使对象数量多且性质相近,此时我们就将这些对象的信息分为两部分:内部状态和外部状态。

内部状态是对象共享出来的信息,存储在享元对象内部并且不会随着环境的变化而变化;外部状态指对象得以依赖的一个标记,是随着环境变化而改变的,不可共享的状态。

EG:比如说说围棋和跳棋,它们都有大量的棋子对象,围棋和五子棋只有黑白两色,跳棋颜色略多一点,但也是不太变化的,所以棋子颜色就是棋子的内部状态;而各个棋子之间的差别就是位置的不同,我们落子嘛,落子颜色是定的,但位置是变化的,所以方位坐标就是棋子的外部状态。

那么为什么这里要用享元模式呢?可以想象一下,上面提到的棋类游戏的例子,比如围棋,理论上有361个空位可以放棋子,常规情况下每盘棋都有可能有两三百个棋子对象产生,因为内存空间有限,一台服务器很难支持更多的玩家玩围棋游戏,如果用享元模式来处理棋子,那么棋子对象就可以减少到只有两个实例,这样就很好的解决了对象的开销问题。

何时使用:

1、系统中有大量对象时,且这些对象消耗大量内存,而且这些对象的状态大部分可以外部化时。
att:需要划分内部状态和外部状态,否则可能引起线程安全问题。

职责链模式
责任链模式的概念

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

工厂模式的实质不是参数,而是返回值。
开闭原则:对扩展开放,对修改关闭。

责任联模式的应用:

1、异常处理机制
2、Js事件模型

3、SpringSecurity通过很多filter中的处理机制(但是是不纯的COR,因为责任链模式只有一个处理类,springSecurity里面有多个处理类)

中介者模式
用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持耦合,使代码易于维护。中介者模式属于行为型模式。

应用场景:当有多个对象彼此间相互交互的时候,自然就会想到对象间的耦合度过高,解决办法就是封装对象间的交互行为。

应用到的设计原则:高内聚,低耦合,使用中介者明显降低了对象之间的耦合。

中介模式和代理模式的区别:

1、代理模式为其他对象提供一种代理以控制对这个对象的访问。中介者模式用一个中介者对象来封装一系列对象的交互。中介者使得各对象不需要显式地相互引用,从而解耦合,独立改变他们之间的交互。

访问者模式
将访问操作独立出来变成一个新的类,当我们需要增加访问操作的时候,直接增加新的类,原来的代码不需要任何的改变。访问者模式就是这样实现的,使得使用不同的访问方式都可以对某些元素进行访问。

目的:把处理从数据结构分离出来。

备忘录模式
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将对象恢复到原先保存的状态。

解释器模式
何时使用:当有一个语言需要解释执行,并且你可将该语言中的句子表示成一个抽象语法树时。

方法:构建语法树,定义终结符和非终结符。

优点:可扩展性好

缺点:

1、引起类的膨胀。
2、采用递归调用方法,将会导致调试非常复杂。
3、使用了大量的循环和递归,效率是一个不容忽视的问题。

应用实例:编译器;运算表达式计算;正则表达式

空对象模式
为对象设置一个空对象(NullBook),然后写一个工厂类,正常情况下返回Book,异常情况下返回NullBook,更加优雅的处理空指针异常。

1、它可以加强系统的稳固性,能有有效地防止空指针报错对整个系统的影响,使系统更加稳定。
2、它能够实现对空对象情况的定制化的控制,能够掌握处理空对象的主动权。
3、它并不依靠Client来保证整个系统的稳定运行。
4、它通过isNull对==null的替换,显得更加优雅,更加易懂。

思维导图
设计模式思维导图1

设计模式思维导图2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值