Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 285|回复: 0

[设计模式学习]装饰模式(Decorator Pattern)

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-10-29 23:58:52 | 显示全部楼层 |阅读模式
    装饰模式是在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
    装饰模式的特点; (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


      
      public class LoggerDecorator implements Logger {   
        Logger logger;   
        public LoggerDecorator(Logger inp_logger) {   
          logger = inp_logger;   
        }   
        public void log(String DataLine) {   
          /*   
           Default implementation   
           to be overriden by subclasses.   
          */   
          logger.log(DataLine);   
        }   
      }//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


      
      public class HTMLLogger extends LoggerDecorator {   
        public HTMLLogger(Logger inp_logger) {   
          super(inp_logger);   
        }   
        public void log(String DataLine) {   
         /*   
          Added functionality   
         */   
         DataLine = makeHTML(DataLine);   
         /*   
            Now forward the encrypted text to the FileLogger   
           for storage   
          */   
          logger.log(DataLine);   
        }   
        public String makeHTML(String DataLine) {   
          /*   
           Make it into an HTML document.   
          */   
          DataLine = "<HTML><BODY>" + "<b>" + DataLine +   
           "</b>" + "</BODY></HTML>";   
          return DataLine;   
        }   
      }//end of class   
      

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

    Listing 19.3: EncryptLogger Class


      
      public class EncryptLogger extends LoggerDecorator {   
        public EncryptLogger(Logger inp_logger) {   
          super(inp_logger);   
        }   
        public void log(String DataLine) {   
          /*   
           Added functionality   
          */   
          DataLine = encrypt(DataLine);   
          /*   
           Now forward the encrypted text to the FileLogger   
           for storage   
          */   
          logger.log(DataLine);   
        }   
        public String encrypt(String DataLine) {   
          /*   
           Apply simple encryption by Transposition…   
           Shift all characters by one position.   
          */   
          DataLine = DataLine.substring(DataLine.length() ? 1) +   
                     DataLine.substring(0, DataLine.length() ? 1);   
          return DataLine;   
        }   
       }//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


      
      class DecoratorClient {   
        public static void main(String[] args) {   
          LoggerFactory factory = new LoggerFactory();   
          Logger logger = factory.getLogger();   
          HTMLLogger hLogger = new HTMLLogger(logger);   
          //the decorator object provides the same interface.   
          hLogger.log("A Message to Log");   
          EncryptLogger eLogger = new EncryptLogger(logger);   
          eLogger.log("A Message to Log");   
        }   
      }//End of class   
      

    增加新的信息输出类型
         在Logging Utility实例中, 应用装饰模式对比使用继承不会因为类层次的增长而导致大量的子类,我们还可以有另外的Logger类型:DBLogger,它输出信息到数据库中。为了将信息转化为HTML格式或在输出到数据库以前对信息进行加密,客户端只需遵从上面提到的步骤,因为DBLogger是一种Logger类型,它可以作为构造函数的参数传递给HTMLLogger或EncryptLogger中任何一个类。
    增加新的装饰
         从例子中可以看到,LoggerDecorator实例包含了 一个Logger类型了对象实例,在转发请求给Logger对象实例以前或以后,增加新的功能。因为LoggerDecorator类实现了Logger 接口,LoggerDecorator实例或它的任何一个子类都可以作为一个Logger类型。因此LoggerDecortator包含它的任何子类的 一个实例,并且将请求转发给它。一般的一个装饰对象可以包含另一个装饰对象,并且可以向它转发请求。通过这种方式,新的装饰类,新的功能可以通过

      
      
       
       

         
       

         
       
      


    源码下载:http://www.hnzz3z.com:8103/zz3zcwb/cwb/dir2/no
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-5 14:10 , Processed in 0.434226 second(s), 50 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表