欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

12-Decorator:too many classes

程序员文章站 2022-05-04 19:23:39
...

      呵,从翻译这个标题开始这个模式学习吧:

The use of layered objects to dynamically and transparently add responsibilities to individual objects is referred to as the decorator pattern.--利用多层对象动态、透明地给一个对象添加功能,称之为装饰模式(或者是:
Decorator模式指的是,利用通过层组织起来的多个对象,以动态、透明地方式,来给某单个对象增加新功能,我自己的翻译是:通过将对象分层,然后动态、透明地给一个对象添加功能的应用称之为Decorator模式。真是不好翻译,得好好学习语法了!)

        以下这个参考例子和教材中差不多,但是更形象一些!(图比较酷)
       
http://www.blogjava.net/sterning/archive/2008/01/21/176679.html

 

     实际上,装饰器模式我已经是学习过了,不过没有看懂,都不知道这个有什么作用,尤其是看过的一些例子,不是很有舒服里,尤其是什么打桩、挖坑、钉木板这个例子,很是让我迷惑,感觉和Proxy设计模式没有什么区别!

       仔细分析之后,感觉还是区别蛮大,但是需要实践的道理还是没有变,只有在实践当中,才能够发现应用的实际操作方式。只是一味的模仿、从概念和简单样例中是体会不到模式应用的精髓啊!

       找了一个很好的评论,所谓代理,就是说使用者并不知道被代理对象的存在,被 代理对象的创建和使用均由代理对象控制。Decorator模式下,使用者还是知道真实的被操作对象的,而且知道代理对象的存在。具体到实际的例子中,如 果真实的对象是由客户端显式创建的,则是Decorator模式,如果真实对象不是有客户端显式创建的,则是proxy模式。

 

        以下的评论也挺好的:

     <1> proxy模式指:客户端调用某个类的某个方法,其实是通过proxy来调用的,而客户本身并不知道。比如: 调用某个Shop.order()方法:
客户端的代码看起来如下:
IShop   shop   =   new   Proxy();   //   创建一个代理对象
shop.order();   //   调用代理的方法

Shop类和Proxy类继承自共同的接口IShop,因此客户端引用IShop不能区分是不是Proxy


接口IShop定义商业方法order(),   Shop类实现该方法,而Proxy类也实现该方法,不过实现方法为:

class   Proxy   implements   IShop   {
    public   void   order()   {
        //   先检查:
        if(check())   {
        //   再调用:
        this.shop.order();   //   Proxy对象保持一个Shop类的引用
        //   还可进行扫尾工作
        }
    }
}

这样在客户端根本不需要对每调用一个远程方法作用户权限,身份等检查,客户端针对Proxy编程,Proxy对象对每个方法调用前都可做检查,真正的商业类可以申明为非public,对客户端不可见。


实现Proxy模式需要:

一个接口Interface   定义必要的方法
一个实现类,实现真正的方法,但不做任何用户检查
一个代理类,包含一个实现类的引用,对每个方法调用可进行必要检查
客户端由   Interface   proxy   =   new   Proxy()得到Proxy的引用,却不能区分是 

    Proxy还是真正的实现类,然后对此引用操作。
    Proxy模式的典型应用就是EJB模型。客户端不与EJB对象(相当于实现类)直接作用,而是通过容器(相当于代理)调用EJB对象,容器会对用户调用作检查。

微软的DCOM模型也可看作Proxy模式,RPC可截获客户端对一个远程COM对象的调用,然后真正调用该远程对象并返回结果,客户端根本不知道自己调用的是一个远程对象,而以为是本地对象(因为DCOM调用代码和本地调用是一样的)。


     <2> Decorator 模式是为了增强某个类的功能,典型的应用如java的stream流:
例如java的FileInputStream有read()方法,但不提供缓冲,应用decorator模式将 

     FileInputStream装饰成有缓冲的stream:
    InputStream   in   =   new   BufferedInputStream(new   FileInputStream( "C:\\1.txt "));

     客户端调用in.read()不知道实际的read功能是由哪个类具体提供的,也分辨不出in的具体类型,因为只有对接口的引用。这种是透明的装饰模式。

      透明装饰模式的关键是客户端只针对接口编程(InputStream是抽象类也是BufferedInputStream和FileInputStream的超类)。

      不透明的装饰模式:装饰类可以提供额外的方法来增强某些功能,例如:

FileInputSteam没有readLine()而BufferedInputStream有readLine(),为了使用额外的功能,客户端不得不把in的类型申明为:
      BufferedInputStream   in   =   new   BufferedInputStream(new     

        FileInputStream( "C:\\1.txt "));
优点是可以使用新的额外方法:in.readLine()
缺点是客户端必须确切知道装饰类提供哪些额外的方法。


//实际的做法就是:好好看看源码...

以 java.io.InputStream 为例,下图是类结构图:


12-Decorator:too many classes
            
    
    博客分类: Thinking in patterns( 阅读笔记) Decorator装饰器模式 

    InputStream是一个抽象类,是所有数据形式为字节的输入流的父类,为基于字节的数据输入定义了基本操作方法。实际 上,InputStream的子类大部分都没有增加任何其他的接口函数(在上面的类结构图中就可以发现),因此在看InputStream子类的时候,我 们主要学习其构造函数。

    Java I/O中是如何采用Decorator(装饰)模式的呢?下面为大家详细说明,看到FilterInputStream类(也就前面说的过滤流,后面你会 发现更多的过滤流),你是否发现了?对,就是FilterInputStream类,她就相当于Decorator(装饰)模式中的Decorator 类,而且的BufferedInputStream、DataInputStream、PushbackInputStream则相当于是 ConcreateDecorator,如下图所示:

   
12-Decorator:too many classes
            
    
    博客分类: Thinking in patterns( 阅读笔记) Decorator装饰器模式 
    那么Java I/O中到底是如何使用的了?Decorator(装饰)模式的主要意图是:动态地给一个对象添加一些额外的职责,这句话很抽象,我们结合Java I/O举个具体的例子:比如说我们读取文件,首先打开文件获取到File,然后我们再创建一个FileInputStream,然后读取文件。读取文件是 一个很费时的操作,尤其是需要多次的读写文件。

    例如,BufferedInputStream实现了对数据读取的缓冲机制,通过FileInputStream来 读取数据,BufferedInputStream将已经读取的数据存储到缓冲区,BufferedInputStream相当于对 FileInputStream进行了“装饰”。

     File file = new File(“c:\\moandroid.txt”,true);
     InputStream is = new BufferedInputStream(new FileInputStream(file));

    如果没有应用Decorator模式的话,就只能应用:

     InputStream is =new FileInputStream(file);

    这样就失去了缓存处理操作,增加了I/O等待时间,没有获得很高的效率.....

 

更多解析可以查看:http://apps.hi.baidu.com/share/detail/51853225

 

      综合,自己学习的过程,用意去区别各种模式的不同是需要的,但是,更重要的是在实际应用中取提取这种模式案例,这个是学习的很好途径。具体到Decorator和Proxy的区别,<1>Decorator是需要功能上的增强,根据用户的具体应用需求来添加各种功能,这在客户端应用时很是方便。要是透明处理,直接就是返回了接口部分。 对于后者来说,完成的任务主要是在安全等方面,将具体逻辑模块和验证模块解耦。如果你非要在这里加上一些增强型功能(很多时候是不必要的),也是可以的。所以,更具不同应用场景来区分设计模式也是有道理的!<2>这个在上面的评论中也做了介绍。至于具体的应用内容,还需要后续的不断学习中逐步深入、熟悉!~


  • 12-Decorator:too many classes
            
    
    博客分类: Thinking in patterns( 阅读笔记) Decorator装饰器模式 
  • 大小: 112.5 KB
  • 12-Decorator:too many classes
            
    
    博客分类: Thinking in patterns( 阅读笔记) Decorator装饰器模式 
  • 大小: 39.2 KB