Java资源网

| JAVA基础 | 环境配置 | JDBC | 线程技术 | Socket编程 | JavaMail | JAVA与XML | 设计模式 | 技术新闻 | Java认证 | 程序人生 软件下载
| JSP&Servlet | Spring | Struts | Hibernate | JBuilder | Eclipse | WebService | EJB技术 | J2ME开发 | 应用服务器 | JXTA | Ajax
Articles search文章搜索
   关键字:
   类 别:
       
New download 最新下载
· [组件]HTML Parser 1.5
· [教程]WebSphere Studio应用教程
· [组件]JDom 1.0
· [工具]Junit3.8.1
· [教程]EJB编程及J2EE系统架构和设计
· [教程]EJB教程
· [教程]J2EE Tutorial中文版
· [教程]Java编程思想2(英文)
· [教程]java编程思想(完整版)
· [教程]Java网络编程
New articles 最新文章
· 设计移动 Web 服务
· 解析XML的时候完全忽略DTD
· 理解XML Schema XML Schema 初步
· 标签库的深入研究
· 提升JSP应用程序的七大绝招
· 如何使用JDOM对XML文件进行操作
· 处理XML字符串中特殊字符
· 利用Digester把XML转换成为Java对象
· 使用WebService 和RMI远程协作
· 使用Axis开发Web Service程序
Articles top 热门文章
· Eclipse基础--plugin插件安装(6644)
· eclipse+tomcat+lomboz的安装配置说明(4774)
· Java程序员就业前景(4584)
· Windows下JAVA环境变量的设置祥解(3788)
· Tomcat下JSP、Servlet和JavaBean环境的配置(3716)
· 使用links方式安装Eclipse插件(3698)
· 一个老程序员的心理话(3533)
· linux下jdk的安装与配置(3459)
· 初学者入门:Structs中基本配置入门(3334)
· Eclipse 运行命令行参数大全(3084)
您的位置:首页>>设计模式>>装饰模式(Decoratornbsp;Pattern)
装饰模式(Decoratornbsp;Pattern)
2007-04-13   来源:www.javaresearch.org  作者:未知

第19章    装饰模式(Decorator Pattern)

说明:


装饰模式是在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

装饰模式的特点;


(1)    装饰对象和真实对象有相同的接口。这样客户端对象就可以以和真实对象相同的方式和装饰对象交互。
(2)    装饰对象包含一个真实对象的索引(reference)
(3)    装饰对象接受所有的来自客户端的请求。它把这些请求转发给真实的对象。
(4)    装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。一下表格列举了装饰模式和继承的不同:

装饰模式 VS 继承


装饰模式    继承
用来扩展特定对象的功能    用来扩展一类对象的功能
不需要子类    需要子类
动态地    静态地
运行时分配职责    编译时分派职责
防止由于子类而导致的复杂和混乱    导致很多子类产生,在一些场合,报漏类的层次
更多的灵活性    缺乏灵活性
对于一个给定的对象,同时可能有不同的装饰对象,客户端可以通过它的需要选择合适的装饰对象发送消息。    对于所有可能的联合,客户期望
很容易增加任何的    困难
     

例子:


让我们重新返回我们在工厂方法和单例模式log实用工具上,我们的模式主要由Logger 接口和两个它的实现类??FileLogger和ConsoleLogger??分别把信息出力到一个文件和屏幕中。另外,还有包括工厂方法的LoggerFactory类。
    LoggerFactory没有出现在下图中,主要是因为它和现在讨论的例子没有直接联系。
  
Figure 19.1: Logging Utility 类层次
让我们想象一些客户端需要以超出Logger Utility现在所提供的新的方式出力信息,客户端需要下面两种特征;
(1)    把出力的信息传唤为HTML文档
(2)    对出力信息进行逻辑转化的简单加密,
在面向对象的设计中,不改变现存的类的代码,可以应用继承来增加新的功能。例如,子类化现在的类重载它的方法来增加所需要的新功能。
应用继承,我们要子类化FileLogger和ConsoleLogger类来增加新的功能,会有下面的一组新的子类:
子类    父类    功能
HTMLFileLogger    FileLogger    转化出力信息为HTML文档,并存入一个Log文件
HTMLConsLogger    ConsoleLogger    转化出力信息为HTML文档,并显示在屏幕上
EncFileLogger    FileLogger    加密出力信息,并存入一个Log文件
EncConsLogger    ConsoleLogger    加密出力信息,并显示在屏幕上
从类图可以看到,为了实现新的功能加入了一组新的子类。如果我们还有其他的Logger类型(例如:DBLogger出力信息到数据库中),这样会有更多子类。当一个新的特性需要被加入,子类的数量会有成倍数的增长,同时我们会有一个庞大的类层次。
  
Figure 19.2: The Resulting Class Hierarchy after Applying Inheritance to Add the New Functionality 
装饰模式使我们从这种情景中解脱出来,装饰模式推荐通过对象的合成而不是继承来包装一个对象扩展它的功能。
应用装饰模式,让我们为Logger Utility定义一个有下列特征的默认根装饰类LoggerDecorator:
(1)    LoggerDecorator包括一个Logger实例的引用。这个引用指向它包含的Logger对象。
(2)    LoggerDecorator实现Logger借口、提供Log方法的基本的默认实现,他只是简单的转发调用给它包含的Logger 对象。每一个LoggerDecorator子类保证定义log方法。
Listing 19.1: LoggerDecorator Class 
  1. public class LoggerDecorator implements Logger { 
  2.   Logger logger; 
  3.   public LoggerDecorator(Logger inp_logger) { 
  4.     logger = inp_logger; 
  5.   } 
  6.   public void log(String DataLine) { 
  7.     /* 
  8.      Default implementation 
  9.      to be overriden by subclasses. 
  10.     */ 
  11.     logger.log(DataLine); 
  12.   } 
  13. }//end of class 
    
     每一个logger的装饰定义log方法使很重要的,因为装饰对象必须提供和它包装的对象相同的借口。当客户端创建一个装饰类的实例,客户端以与装饰类交互方式和客户端与拥有相同接口原对象的交互方式是一致的。
    让我们定义LoggerDecorator的两个子类,HTMLLogger和EncryptLogger。
 ,
 
Figure 19.3: The Decorator Class Structure for the Logging Utility to Add the New Functionality 

具体的Logger 装饰类


    
HTMLLogger

HTMLLogger重载了log方法的默认实现。在log方法中,装饰类把出力信息转化为HTML文档,并且发送给可以出力的Logger实例。
Listing 19.2: HTMLLogger Class 
  1. public class HTMLLogger extends LoggerDecorator { 
  2.   public HTMLLogger(Logger inp_logger) { 
  3.     super(inp_logger); 
  4.   } 
  5.   public void log(String DataLine) { 
  6.    /* 
  7.     Added functionality 
  8.    */ 
  9.    DataLine = makeHTML(DataLine); 
  10.    /* 
  11.       Now forward the encrypted text to the FileLogger 
  12.      for storage 
  13.     */ 
  14.     logger.log(DataLine); 
  15.   } 
  16.   public String makeHTML(String DataLine) { 
  17.     /* 
  18.      Make it into an HTML document. 
  19.     */ 
  20.     DataLine = "<HTML><BODY>" + "<b>" + DataLine + 
  21.      "</b>" + "</BODY></HTML>"
  22.     return DataLine; 
  23.   } 
  24. }//end of class 

EncryptLogger

    与HTMLLogger相似,EncryptLogger重载了log方法,在log方法中,EncryptLogger通过简单的将字符位置向右转移一位实现了加密逻辑,并且发送给可以出力的Logger实例。

Listing 19.3: EncryptLogger Class 
  1. public class EncryptLogger extends LoggerDecorator { 
  2.   public EncryptLogger(Logger inp_logger) { 
  3.     super(inp_logger); 
  4.   } 
  5.   public void log(String DataLine) { 
  6.     /* 
  7.      Added functionality 
  8.     */ 
  9.     DataLine = encrypt(DataLine); 
  10.     /* 
  11.      Now forward the encrypted text to the FileLogger 
  12.      for storage 
  13.     */ 
  14.     logger.log(DataLine); 
  15.   } 
  16.   public String encrypt(String DataLine) { 
  17.     /* 
  18.      Apply simple encryption by Transposition… 
  19.      Shift all characters by one position. 
  20.     */ 
  21.     DataLine = DataLine.substring(DataLine.length() − 1) + 
  22.                DataLine.substring(0, DataLine.length() − 1); 
  23.     return DataLine; 
  24.   } 
  25.  }//end of class 

当应用装饰模式的类图:
 
 Figure 19.4: Association between Different Logger Classes and Logger Decorators
    

为了使用新设计装饰对象,客户端需要


(1)    使用LoggerFactory工厂方法创建一个合适的Logger实例(FileLogger/ConsoleLogger)。
(2)    把第一步中创建的Logger实例作为参数转递给新创建的合适的LoggerDecorator实例的构造函数。
(3)    调用LoggerDecorator实例上的方法,
Listing 19.4: Client DecoratorClient Class 
  1. class DecoratorClient { 
  2.   public static void main(String[] args) { 
  3.     LoggerFactory factory = new LoggerFactory(); 
  4.     Logger logger = factory.getLogger(); 
  5.     HTMLLogger hLogger = new HTMLLogger(logger); 
  6.     //the decorator object provides the same interface. 
  7.     hLogger.log("A Message to Log"); 
  8.     EncryptLogger eLogger = new EncryptLogger(logger); 
  9.     eLogger.log("A Message to Log"); 
  10.   } 
  11. }//End of class 

   下面是客户端对象使用HTMLLogger对象出力消息的顺序图:
 
  Figure 19.5: Message Flow When a Client Uses the HTMLLogger (Decorator) to Log a Message

增加新的信息出力类型


    在Logging Utility实例中,应用装饰模式对比使用继承不会因为类层次的增长而导致大量的子类,我们还有另外的Logger类型:DBLogger??出力信息到数据库中。为了将信息转化HTML格式或在出力到数据库以前对信息进行加密,客户端只需遵从上面提到的步骤,因为DBLogger是一种Logger类型,它可以作为构造函数的参数传递给HTMLLogger或EncryptLogger中任何一个类。

增加新的装饰


    从例子中可以看到,LoggerDecorator实例包含了一个Logger类型了对象实例,在转发请求给Logger对象实例以前或以后,增加新的功能。因为LoggerDecorator类实现了Logger接口,LoggerDecorator实例或它的任何一个子类都可以作为一个Logger类型。因此LoggerDecortator包含它的任何子类的一个实例,并且将请求转发给它/。一般的一个装饰对象可以包含另一个装饰对象,并且可以向它转发请求。通过这种方式,新的装饰类,新的功能可以通过包装现存的装饰类来实现。

以下附件文实例代码和原文!


附件:23.rar(9K) 附件:1130207322862.doc(173K) [img]

  --相关文章--
· 面向对象编程,我的思想 (2007-04-13)
· 面向对象的思维方式 (2007-04-13)
· 通过Javanbsp;Swing看透MVC设计模式 (2007-04-13)
· 适配器模式(Adapternbsp;Pattern) (2007-04-13)
· 追MM与Java的23种设计模式 (2007-04-13)
· 责任链模式(Chainnbsp;ofnbsp;Responsibility) (2007-04-13)

版权所有©2005-2006 JAVA资源网 渝ICP备05007591号 虚拟主机 | 关于我们 | 联系方式 | 广告业务 | 网站地图 | 友情链接