`

设计模式(Java 与模式-笔记 二)

阅读更多

一、创建模式

1、工厂模式

工厂模式专门负责将大量有共同接口的类实例化。工厂模式可以动态决定将哪一个类实例化,不必事先知道每次要实例化哪个类。

 

工厂模式有以下几种形态:

 

1)简单工厂(Simple Factory)模式:又称静态工厂方法模式(Static Factory Method Pattern

UML 图:




 
 简单工厂模式就是由一个工厂类(具体类)根据传入的参量决定创建哪一种产品类的实例。

源码实现:

(查看相关附件)

 

具体实现:

在真实的系统中,产品可以形成复杂的等级结构,比如下图所示的树形结构上就有许多抽象产品类和具体产品类。如下图:

 




 
 这个时候,简单工厂模式采取的是同一使用同一个工厂类,来处理同一产品类(抽象)。如下图:

 




 
 这样做的好处是设计简单,产品类的等级结构不过反映到工厂类中来,从而产品类的等级结构的变化也不会影响工厂类。但这样做的缺点是,增加新的产品必将导致工厂类的修改。

其他实现:

1.1)抽象产品角色的省略:

如果系统中仅有一个具体产品角色的话,可以省略掉抽象产品角色。如下图:

 




 
 (1.2)工厂角色与抽象角色合并

 




 
 代码实现如下:

 




 
 在factory()方法中,还可以做一些相关类的初始化工作

优点:

模式的核心是工厂类。这个类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例。而客户端则可以免除直接创建产品对象的责任,而仅仅负责“消费”产品。简单工厂模式通过这种做法实现了对责任的分割

缺点:

工厂类的责任过于集中,造成工厂类越来越臃肿,如果工厂类不能正常工作,则整个产品类的生成则受影响。当新增产品类时,总会涉及工厂类的修改,这使得系统在将来进行功能扩展时较为困难。

2)工厂方法(Factory Method)模式:又称多态性工厂(Polymorphic Factory)模式或虚拟构造子(Virtual Constructor)模式

工厂方法模式的用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中。(工厂方法模式在简单工厂模式的基础上对工厂类进行了抽象,每个具体工厂类生成相应的具体产品类,从而实现了工厂的责任的分割,如下图所示。)

 




 
 UML图:

 




 
 源码实现:

(查看相关附件)

 

3)抽象工厂(Abstract Factory)模式:又称为工具箱(Kit Toolkit)模式。

抽象工厂模式与工厂方法模式的最大区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构。(这里讲的产品等级用Java 的语言来解释就是一个抽象类,同一个产品等级的产品有相同的接口。)换句话说,就是抽象工厂模式能创建多个不同抽象的产品的类。

抽象工厂模式在工厂方法模式的基础上又新增了对创建多个不同产品等级类的支持。

UML实现:

 




 
 源码实现:

(查看相关附件)

 

2、单例(Singleton)模式

单例模式有以下的特点:单例类只能有一个实例;单例类必须自己创建自己的唯一实例;单例类必须给所有其他对象提供这一实例。

单例模式的几种类型实现:

2.1、饿汉式单例类

从下面的UML图可以看出,在这个类被加载时,静态变量就会被初始化,就是说在类被加载时就会为这个类分配内存了,实例化好了。

UML图:

 




 
 源码实现:

(参考附件)

 

2.2、懒汉式单例类

与饿汉式单例类不同的是,懒汉式单例类在第一次被引用时才将自己实例化的。

UML 图:

 




 
 源码实现:

(参考附件)

 

2.3、登记式单例类

登记式单例类时GoF 为了克服饿汉式单例及懒汉式单例类均不可继承的缺点而设计的。

UML图:

 




 
 它的子类需要弗雷的帮助才能实例化。



 

缺点:由于子类必须允许以构造子调用产生实例,因此,它的构造子必须是公开的。这样一来,就等于允许了以这样的方式产生实例而不在弗雷的登记中。这是登记式单例类的一个缺点。由于弗雷的实例必须存在才有可能有子类的实例,这在有些情况下是一个浪费。这是登记式单例类的另一个缺点。

 

2.4单例类的状态

有状态的单例类对象常常当做状态库使用。比如序列号生成器。没有状态的单例可以用做工具性函数的对象。

在多个JVM系统的分散式系统中EJB容器有能力将一个EJB的实例跨过几个JVM调用。由于单例对象不是EJB,因此,单例类局限于某一个JVM中。此时,如果单例有状态的话,那就会出现问题。所以在任何使用了EJBRMIJINI技术的分散式系统中,应当避免使用有状态的单例模式

在多个类加载器的情况下,同一个JVM中会有多个类加载器,当两个类加载器同时加载同一个类时,会出现两个实例。所以在这种情况下,除非系统有协调机制,不然应当尽量避免使用有状态的单例类。

 

2.5单例类中的双重检查成例的研究:

(请参考下面的链接:http://ajava.org/course/java/13502.html

 

3、建造(Builder)模式

建造模式可以将一个产品的内部表象与产品的生成过程分割开来,一步步进行创建,从而可以使一个建造过程生成具有不同的内部表象的产品对象。用户不用知道内部的具体构建过程。

 

UML图:



 

源码实现:

(查看附件)

 

导演者(Director)角色是与客户端打交道的角色。导演者角色将客户端创建产品的请求划分为对各个零件的建造请求,再将这些请求委派给具体建造者角色。具体建造者角色是做具体建造工作的,但是却不为客户端所知。

 

使用的情况:

1)需要生成的产品对象有复杂的内部接口。每一个内部成分本身可以是对象,也可以仅仅是一个对象(即产品对象)的一个组成成分。

2)需要生成的产品对象的属性相互依赖。建造模式可以强制实行一种分步骤进行的建造过程,因此,如果产品对象的一个属性必须在另一个属性被赋值之后才可以被赋值,使用建造模式便是一个很好的设计思想。

 

 

4、原始模型(Prototype)模式

原始模型模式的用意是通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的方法创建出更多同类型的对象。

 

4.1简单形式

 

UML图:



 

源码实现:

(查看附件)

 

4.2登记形式的原始模型模式

 

UML图:



 

 源码实现:

(查看附件)

 

两种形式的比较

简单形式和登记形式的原始模型模式各有其长处和短处。

如果需要创建的原型对象数目较少而且比较固定的话,可以采取第一种形式,也即简单形式的原始模型模式。在这种情况下,原型对象的引用可以由客户端自己保存

如果要创建的原型对象数目不固定的话,可以采取第二种形式,也即登记形式的原始模型模式。在这种情况下,客户端并不保存对原型对象的引用,这个任务交给管理员对象(保存)。在复制一个原型对象之前,客户端可以查看管理员对象是否已经有一个满足要求的原型对象,如果有,可以直接从管理员类取得这个对象引用;如果没有,客户端就需要自行复制此原型对象。

在这个原始模型模式中应该理解深复制和浅复制的概念,这个是非常容易出错的。

 

二、结构模式

1、适配器(Adapter)模式

适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

 

UML图:



 

源码实现:

(查看附件)

 

附加:

还有一个叫缺省适配器模式,它为一个借口提供缺省实现,这样子类型可以从这个缺省实现进行扩展,而不必从原有接口进行扩展,从而简化了子类的方法的对于接口不必要的实现。这个模式比较简单,就不做介绍了。

 

2、合成(Composite)模式

合成模式又叫做部分-整体模式,合成模式将对象组织到树结构中,可以用来描述整体与部分的关系。

2.1安全式的合成模式的结构

安全式的合成模式要求管理聚集的方法只出现在树枝构件类中,而不出现在树叶构件中。因此树叶类型的对象对于管理子类对象的方法是不透明的。

UML图:



 

源码实现:

(查看附件)

 

2.2透明式的合成模式(不推荐使用)

与安全式的合成模式不同的是,透明式的合成模式要求所有的具体构件类,不论树枝构件还是树叶构件,均符合一个固定的接口,但这样的实现将导致树叶节点中add等管理方法的空实现(因此个人不大推荐使用)。

UML图:



 

 

源码实现:

(查看附件)

 

3、装饰器(Decorator)模式

装饰器模式又名包装(Wrapper)模式。装饰器模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。

UML图:



 

源码实现:

(查看附件)

 

优点:

(1)装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。对于功能的添加只需用具体装饰器类包装下它就可以实现了。

2)通过使用不同的具体装饰类以及这些装饰类的排序组合,设计师可以创造出很多不同行为的组合。

缺点:

由于使用装饰器模式,可以比使用继承关系需要较少数目的类。使用较少的类,当然使设计比较易于进行,但是,在另一方面,使用装饰器模式会产生比使用继承关系更多的对象。更多的对象会使得差错变得困难,特别是这些对象看上去都很相像。

 

4、代理(Proxy)模式

代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。

 

UML图:



 

源码实现:

(查看附件)

 

代理模式按使用目的划分:

远程代理:为一个位于不同的地址空间的对象提供一个局域代表对象。这个不同的地址空间可以是本机器中,也可以是另外一台机器中。远程代理又叫做大使。

虚拟代理:根据需要创建一个资源消耗较大的对象,使得此对象只在需要时才会被真正创建。

Copy-on-Write代理:虚拟代理的一种。把复制(克隆)拖延到只有在客户端需要时,才真正采取行动。

保护代理:控制对一个对象的访问,如果需要,可以给不同的用户提供不同级别的使用权限。

Cache代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。

防火墙代理:保护目标,不让恶意用户接近。

同步化代理:使几个用户能够同时使用一个对象而没有冲突。

智能引用代理:当一个对象被引用时,提供一些额外的操作,比如将对此对象调用的次数记录下来等。

 

附加知识:

上面的源码实现的是静态代理(直接用继承或者实现接口来实现),而动态代理有Java 语言通过在java.lang.reflect库中提供了下面三个类直接支持代理模式:ProxyInvocationHandlerMethod,还有是通过CGLIB动态代理实现的。相关内容,查看相关文档。

 

5、享元(Flyweight)模式

享元模式能做东共享的关键是区分内蕴状态和外蕴状态。一个内蕴状态时存储在享元对象内部的,并且是不会随环境改变而有所不同的。因此,一个享元可以具有内蕴状态并可以共享。一个外蕴状态是随环境改变而改变的、不可以共享的状态。享元对象的外蕴状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候再传入到享元对象内部。外蕴状态不可以影响享元对象的内蕴状态,换句话说,它们是相互独立的。

上述的代码实现可在附件上下载。。不过图片现在上传排版不知道正确了没,代码是一年前写的,so,不知道有没问题。。 还没怎么核对下。。

 

ps:突然喜欢上了WPS了,哈。。在JE上用office word 复制到这,格式一团糟,但发现WPS复制的格式好像还不错。而且WPS可以直接转PDF格式,转的也很完美。hoho。。有点麻烦的就是图片,上传了N久,如果可以复制图片也可以用,那JE就神了。。哈哈。。。by zhxing

  • 大小: 12.7 KB
  • 大小: 45.7 KB
  • 大小: 46.3 KB
  • 大小: 17.3 KB
  • 大小: 12.1 KB
  • 大小: 19.3 KB
  • 大小: 40.4 KB
  • 大小: 35.7 KB
  • 大小: 110 KB
  • 大小: 17.1 KB
  • 大小: 9.6 KB
  • 大小: 14.8 KB
  • 大小: 26.3 KB
  • 大小: 40.5 KB
  • 大小: 23.4 KB
  • 大小: 35.2 KB
  • 大小: 25 KB
  • 大小: 32.8 KB
  • 大小: 37.1 KB
  • 大小: 24.9 KB
  • 大小: 29.3 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics