【转】Java与模式: 代理(Proxy)模式、装饰(Decorator)模式

装饰模式使用被装饰类的一个子类的实例,把客户端的调用委派到被装饰类,装饰模式的关键在于这种扩展是完全透明的。

装饰模式在Java种使用也很广泛,比如我们在重新定义按钮、对话框等时候,实际上已经在使用装饰模式了。装饰模式最浅显的例子是相片-相框的例子。

一、原理图



其中类的职责如下:

抽象构件角色(Project):给出一个接口,以规范准备接收附加责任的对象
具体构件角色(Employe):定义一个将要接收附加责任的类
装饰角色(Manager):持有一个构件对象的实例,并定义一个与抽象构件接口一致的接口
具体装饰角色(ManagerA、ManagerB):负责给构件对象“贴上”附加的责任

二、下面通过一个软件项目例子来说明装饰模式的使用
过程是这样的:
项目经理接到一个项目,项目最终要完成编码。
项目经理接到项目后,先做些前期的工作(比如需求分析、设计),然后将编码工作委派给代码工人,代码工人干完后,项目经理做项目的收尾工作。

实现代码如下:

/** 
* Created by IntelliJ IDEA. 
* User: leizhimin 
* Date: 2008-8-3 12:51:06 
* 项目 
*/ 
public interface Project { 

/** 
 * 写代码 
 */ 
  void doCoding(); 
}


/** 
* Created by IntelliJ IDEA. 
* User: leizhimin 
* Date: 2008-8-3 12:52:12 
* 代码工人 
*/ 
public class Employe implements Project{ 
    /** 
     * 编码 
     */ 
    public void doCoding(){ 
        System.out.println("代码工人 在编写代码,加班编啊编啊,终于编完了!"); 
    } 
}


/** 
* Created by IntelliJ IDEA. 
* User: leizhimin 
* Date: 2008-8-3 12:51:26 
* 项目经理 
*/ 
public class Manager implements Project { 
    private Project project;        //实际上存放的是代码工人对象 

    public Manager(Project project) { 
        this.project = project; 
    } 

    /** 
     * 编码 
     */ 
    public void doCoding() { 
        //项目经理开始新的工作 
        startNewWork(); 
    } 

    /** 
     * 模板:定义项目经理自己的事情 
     */ 
    public void startNewWork() { 
        //项目经理在做早期工作 
        doEarlyWork(); 
        //项目经理很牛,做完需求和设计后,直接将编码委派给代码工人干 
        project.doCoding(); 
        //项目经理在做收尾工作 
        doEndWork(); 
    } 

    /** 
     * 项目经理自己的事情:做早期工作 
     */ 
    public void doEarlyWork() { 
    } 

    /** 
     * 项目经理做收尾工作 
     */ 
    public void doEndWork() { 
    } 
}


/** 
* Created by IntelliJ IDEA. 
* User: leizhimin 
* Date: 2008-8-3 13:45:18 
* 具体的项目经理A 
*/ 
public class ManagerA extends Manager{ 

    public ManagerA(Project project) { 
        super(project); 
    } 

    /** 
     * 项目经理自己的事情:做早期工作 
     */ 
    public void doEarlyWork() { 
        System.out.println("项目经理A 在做需求分析"); 
        System.out.println("项目经理A 在做架构设计"); 
        System.out.println("项目经理A 在做详细设计"); 
    } 
}


/** 
* Created by IntelliJ IDEA. 
* User: leizhimin 
* Date: 2008-8-3 13:45:27 
* 具体的项目经理B 
*/ 
public class ManagerB extends Manager { 

    public ManagerB(Project project) { 
        super(project); 
    } 

     /** 
     * 项目经理自己的事情:做早期工作 
     */ 
    public void doEarlyWork() { 
        System.out.println("项目经理B 在做需求分析"); 
        System.out.println("项目经理B 在做详细设计"); 
    } 

    /** 
     * 项目经理做收尾工作 
     */ 
    public void doEndWork() { 
        System.out.println("项目经理B 在做收尾工作"); 
    } 
}


/** 
* Created by IntelliJ IDEA. 
* User: leizhimin 
* Date: 2008-8-3 13:03:22 
* 客户端测试 
*/ 
public class Client { 
    public static void main(String args[]) { 
        Project employe = new Employe();        //代码工人 
        Project managerA = new ManagerA(employe); //项目经理 
        Project managerB = new ManagerB(employe); //项目经理 
        //以经理的名义将编码完成,功劳都是经理的,实际编码的是工人 
        managerA.doCoding(); 
        managerB.doCoding(); 
    } 
}



运行结果:


项目经理A 在做需求分析
项目经理A 在做架构设计
项目经理A 在做详细设计
代码工人 在编写代码,加班编啊编啊,终于编完了!
项目经理B 在做需求分析
项目经理B 在做详细设计
代码工人 在编写代码,加班编啊编啊,终于编完了!
项目经理B 在做收尾工作

Process finished with exit code 0


这是代理模式的一种实:不同级别的用户对同一对象拥有不同的访问权利或某个客户端不能直接操作到某个对象,但又必须和那个对象有所互动。

代理对象与被代理对象必须实现统一接口,在代理对象中可以实现通用的一些功能,并且在需要的时候再调用被代理的对象,如此被代理对象当中就可以仅保留与业务相关的职责。

装饰模式:装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案,提供比继承更多的灵活性。动态给一个对象增加功能,这些功能可以再动态的撤消。增加由一些基本功能的排列组合而产生的非常大量的功能。


装饰模式修改如下:

public class Project { 

  void doCoding(){
         System.out.println("项目来了...");
  } 
}


public class Employe extends Project{ 

    public void doCoding(){ 
        System.out.println("代码工人 在编写代码,加班编啊编啊,终于编完了!"); 
    } 
}


public class Manager extends Project { 
    private Project project;        //实际上存放的是代码工人对象 

    public Manager(Project project) { 
        this.project = project; 
    } 


    public void doCoding() { 
        //项目经理开始新的工作 
        startNewWork(); 
    } 


    public void startNewWork() { 
        //项目经理在做早期工作 
        doEarlyWork(); 
        //项目经理很牛,做完需求和设计后,直接将编码委派给代码工人干 
        project.doCoding(); 
        //项目经理在做收尾工作 
        doEndWork(); 
    } 


    public void doEarlyWork() { 
    } 


    public void doEndWork() { 
    } 
}

猜你喜欢

转载自jueforever.iteye.com/blog/1562706