论坛首页 Java企业应用论坛

设计模式之--进行硬编码的静态装饰器模式和装饰器模式链化

浏览 2006 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-02-17  

动态代理的背后思想是在一个对象的周围插入动态的行为但不改变对象的已有代码和接口。装饰器模式提供一种不必改变对象代码就可以装饰一个对象(改变它的行为)并向其增加横切面的方法。现在就用静态的装饰来实现具体的业务功能

首先有一个简单业务接口:

public interface IMyBusinessObject { 
      public String doExecute(String in); 
} 

 这个接口有一个业务对象类的实现。

public class MyBusinessObject implements IMyBusinessObject { 
public String doExecute(String in) { 
System.out.println("Here in MyBusinessObject doExecute: input :" + in); 
return in; 
} 
} 

 

现在想要在这个业对象类的方法doExecute之前与之后增加一些行为,装饰器模式使我们十分容易增加这个功能。现在定义一个抽象类,这个抽象类实现上面的业务接口。

public abstract class ADecorator implements IMyBusinessObject { 
      protected IMyBusinessObject target; 
  
      public void setTarget(IMyBusinessObject target) { 
            this.target = target; 
      } 
  
public ADecorator(){}; 
  
      public ADecorator(IMyBusinessObject target_) { 
            setTarget(target_); 
      } 
} 

 

为什么要把设置业务对象的方法放到抽象类中呢,这也是重构的一种方法。就是把子类中设置业务对象的方法提到父类中。术语为方法上移。 现在定义一个从ADedorator扩展来的具体类DebugConcreteDecorator,目的是在我们业务对象被调用之前和之后加入一些调试信息:

public class DebugConcreteDecorator extends ADecorator { 
  
  
      public DebugConcreteDecorator(IMyBusinessObject target_) { 
            super(target_); 
      } 
  
      public String doExecute(String in) { 
            System.out 
                        .println("DebugConcreteDecorator: before method : doExecute "); 
            String ret = target.doExecute(in); 
            System.out.println("DebugConcreteDecorator: after method : doExecute "); 
            return ret; 
      } 
} 

 

现在在客户端,我们调用业务对象:

IMyBusinessObject aIMyBusinessObject = new MyBusinessObject(); 
IMyBusinessObject wrappedObject = new DebugConcreteDecorator( 
aIMyBusinessObject); 
wrappedObject.doExecute("Hello World"); 

 输出结果如下:

DebugConcreteDecorator: before method : doExecute 
Here in MyBusinessObject doExecute: input :Hello World 
DebugConcreteDecorator: after method : doExecute 

实际的业务方法调用之前链化装饰器----调用一个装饰器后再调用另一个装饰器。让我们再定义另一个装饰器去展示这个方法:

public class AnotherConcreteDecorator extends ADecorator { 
  
      public AnotherConcreteDecorator( 
                  IMyBusinessObject target_) { 
            super(target_); 
      } 
  
      public String doExecute(String in) { 
            System.out 
                        .println("AnotherConcreteDecorator: Going to execute method : doExecute"); 
            in = in + " Modified by AnotherConcreteDecorator"; 
            String ret = target.doExecute(in); 
            System.out 
                        .println("AnotherConcreteDecorator: After execute method : doExecute"); 
            return ret; 
      } 
  
} 

 

上面的代码片段通过在业务方法输入的字符参数后增加(" Modified by AnotherConcreteDecorator")字符串,从而实现对其进行了修改。如果我们想链化装饰器,在客户端,我们可以编写如下的代码:

 

IMyBusinessObject aIMyBusinessObject = new MyBusinessObject(); 
IMyBusinessObject wrappedObject = new AnotherConcreteDecorator( 
            new DebugConcreteDecorator(aIMyBusinessObject)); 
wrappedObject.doExecute("Hello World"); 

 

在上面的代码片段中,我在创建一个DebugConcreteDecorator实例时,向其传递了一个实际的业务对象实例。然后用一个刚才定义的notherConcreteDecorator实例去包装DebugConcreteDecorator实例。AntherConcreteDecorator首先在输入参数后增加字符串对其进行修改,然后调用DebugConcreteDecorator实例的doExecute()方法。这时,DebugConcreteDecorator会记录doExectute()方法的输出的条目,然后调用doExecute()去调用实际业务对象的doExecute()方法。
它的返回路径以相反的顺序。在从实际的业务对象(MyBusinessObject)doExecute()方法返回之后,DebugConcreteDecorator余下代码将被执行。于是,调用返回至AnotherConcreteDecorator实例并执行余下的部份代码。

输出结果如下:

AnotherConcreteDecorator: Going to execute method : doExecute 
DebugConcreteDecorator: before method : doExecute 
Here in MyBusinessObject doExecute: input :Hello World Modified by AnotherConcreteDecorator 
DebugConcreteDecorator: after method : doExecute 
AnotherConcreteDecorator: After execute method : doExecute 

 

静态装饰器有一个问题:不知大家注意到没有DebugConcreteDecorator 或 AnotherConcreteDecorator中doExecute()方法。它对目标对象doExecute()方法的调用进行了硬编码。并且,如果我们在IMyBusinessObject接口中定义另一个方法,我们必须改写所有装饰器并提供这个方法的实现。于是,在实践中,我们可能会因有许多装饰器和在每个装饰器中有大量的代码而止步。

下一篇博客用一个动态代理可以帮助我们去掉这些硬编码,此外,我们不必在每个装饰器去实现和改写业务接口中的每个方法。

论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics