注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

东东的博客

江南烟雨,同大家一起分享

 
 
 

日志

 
 

设计模式之访问者模式(Visitor)  

2010-07-13 17:57:58|  分类: 设计模式相关 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

访问者模式:在不改变一个已存在的类的层次结构的情况下,为这个层次结构中的某些类定义一个新的操作,这个新的操作作用于(操作)已存在的类对象,也即新的操作需要访问被作用的对象。

一句话: 为一个稳定的类结构增加操作. 也即把易变化的类的行为搬到访问者中.

特点:

1 访问者角色(Visitor)作用于具体的元素执行相关的操作;

2 元素角色(Element)定义了accept方法接受一个访问者,并通过调用Visitor的方法执行操作;

3 对象结构角色(Object structure)容许访问者访问每个元素。

基本代码:

  1. //访问者接口  
  2. package designpattern.visitor;  
  3.   
  4. public interface IVisitor {  
  5.     public void visitElement1(ConcreteElement1 e);  
  6.     public void visitElement2(ConcreteElement2 e);  
  7. }  
  8. //具体访问者1  
  9. package designpattern.visitor;  
  10.   
  11. public class ConcreteVisitor1 implements IVisitor{  
  12.     public void visitElement1(ConcreteElement1 e) {  
  13.         System.out.println("ConcreteVisitor1 visit ConcreteElement1.");  
  14.     }  
  15.   
  16.     public void visitElement2(ConcreteElement2 e) {  
  17.         System.out.println("ConcreteVisitor1 visit ConcreteElement2.");  
  18.     }  
  19. }  
  20. //具体访问者2  
  21. package designpattern.visitor;  
  22.   
  23. public class ConcreteVisitor2 implements IVisitor{  
  24.     public void visitElement1(ConcreteElement1 e) {  
  25.         System.out.println("ConcreteVisitor2 visit ConcreteElement1.");  
  26.     }  
  27.   
  28.     public void visitElement2(ConcreteElement2 e) {  
  29.         System.out.println("ConcreteVisitor2 visit ConcreteElement2.");  
  30.     }  
  31. }  
  32. //类结构借口   
  33. package designpattern.visitor;  
  34.   
  35. public interface Element {  
  36.     public void accept(IVisitor v);  
  37. }  
  38. //实体类1  
  39. package designpattern.visitor;  
  40.   
  41. public class ConcreteElement1 implements Element{  
  42.     public void accept(IVisitor v) {  
  43.         v.visitElement1(this);  
  44.     }  
  45. }  
  46. //实体类2  
  47. package designpattern.visitor;  
  48.   
  49. public class ConcreteElement2 implements Element{  
  50.     public void accept(IVisitor v) {  
  51.         v.visitElement2(this);  
  52.     }  
  53. }  
  54.   
  55. //对象结构  
  56. package designpattern.visitor;  
  57. import java.util.*;  
  58.   
  59. public class ObjectsStructure {  
  60.     List<Element> list = new ArrayList();  
  61.       
  62.     public ObjectsStructure(){  
  63.         list.add(new ConcreteElement1());  
  64.         list.add(new ConcreteElement2());  
  65.     }  
  66.     public void process(IVisitor v){  
  67.         for(Element e : list){  
  68.             e.accept(v);  
  69.         }  
  70.     }  
  71.     public static void main(String[] args){  
  72.         ObjectsStructure o = new ObjectsStructure();  
  73.         o.process(new ConcreteVisitor1());  
  74.         o.process(new ConcreteVisitor2());  
  75.     }  

再举一个例子,例子的来源于《大话设计模式》,作者试图从如下的几句话中抽象几个角色:


当男人成功时,背后多半有一个伟大的女人

当女人成功时,背后大多有一个不成功的男人

当男人失败时,闷头喝酒,谁也不用劝

当女人失败时,眼泪汪汪,谁劝也没用

当男人恋爱时,凡事不懂也装懂

当女人恋爱时,遇事懂也装不懂

。。。。

我们很容易写出这样的代码:

view plaincopy to clipboardprint?
public class Woman {  
    public void getBehavior(String status){  
        if("成功".equals(status)){  
            System.out.println("背后大多有一个不成功的男人");  
        }  
        else if("失败".equals(status)){  
            System.out.println("眼泪汪汪,谁劝也没用");  
        }  
        else if("恋爱".equals(status)){  
            System.out.println("遇事懂也装不懂");  
        }  
        else if("结婚".equals(status)){  
            //......  
        }  
    }  
}  
//  
public class Man {  
    public void getBehavior(String status){  
        if("成功".equals(status)){  
            System.out.println("背后多半有一个伟大的女人");  
        }  
        else if("失败".equals(status)){  
            System.out.println("闷头喝酒,谁也不用劝");  
        }  
        else if("恋爱".equals(status)){  
            System.out.println("凡事不懂也装懂");  
        }  
        else if("结婚".equals(status)){  
            //......  
        }  
    }  

但是这样写出现了两个问题:

1 代码中有坏味道, if else充斥着整个方法体;

2 外部状态(成功,失败,恋爱,结婚....)是非稳定的因素, 他们可能随时会改变, 可能随时会增加, 如果增加了新的状态, 比如生病,升迁,当官等, 我们就得修改代码, 这就违背了开放封闭原则(关于开放封闭原则, 将在后面写blog解释).

因为人分两种, 男人, 女人, 这种类结构几乎不会发生变化, 而外在的状态(成功,失败,恋爱,结婚....)却可以随时改变, 所以我们用访问者模式来改进上面的代码:

  1. //  
  2. package designpattern.visitor;  
  3.   
  4. public interface Person {  
  5.     public void accept(Visitor v);  
  6. }  
  7. //  
  8. package designpattern.visitor;  
  9.   
  10. public class Man implements Person{  
  11.     public void accept(Visitor v) {  
  12.         v.visit(this);  
  13.     }  
  14. }  
  15. //  
  16. package designpattern.visitor;  
  17.   
  18. public class Woman implements Person{  
  19.     public void accept(Visitor v) {  
  20.         v.visit(this);  
  21.     }  
  22. }  
  23. //  
  24. package designpattern.visitor;  
  25.   
  26. public interface Visitor {  
  27.     public void visit(Man m);  
  28.     public void visit (Woman w);  
  29. }  
  30. //  
  31. package designpattern.visitor;  
  32.   
  33. public class Success implements Visitor {  
  34.     public void visit(Man m) {  
  35.         System.out.println("当男人成功时,背后多半有一个伟大的女人");  
  36.     }  
  37.     public void visit(Woman w) {  
  38.         System.out.println("当女人成功时,背后大多有一个不成功的男人");  
  39.     }  
  40.   
  41. }  
  42. //  
  43. package designpattern.visitor;  
  44.   
  45. public class Love implements Visitor{  
  46.     public void visit(Man m) {  
  47.         System.out.println("当男人恋爱时,凡事不懂也装懂");  
  48.     }  
  49.   
  50.     public void visit(Woman w) {  
  51.         System.out.println("当女人恋爱时,遇事懂也装不懂");  
  52.     }  
  53.   
  54. }  
  55. //  
  56. package designpattern.visitor;  
  57.   
  58. public class Failure implements Visitor{  
  59.     public void visit(Man m) {  
  60.         System.out.println("当男人失败时,闷头喝酒,谁也不用劝");  
  61.     }  
  62.   
  63.     public void visit(Woman w) {  
  64.         System.out.println("当女人失败时,眼泪汪汪,谁劝也没用");  
  65.     }  

再举一例,我们假设银行只有两种经典业务:存款,取款,这两种业务种类自从有银行 开始都没有变过, 所以他们是稳定因素,然而随着时代的变迁,银行的客户却在逐渐细分,增加。过去有普通存款,取款类型, 公司存款取款类型,现在有了一些新的客户群,比如股票第三方存取款客户,代理基金业务客户等。而且银行在不断的开辟新的客户。 可以认为,银行的服务结构没有变,变的是外在的客户,可以用访问者模式。

  1. //服务接口  
  2. package designpattern.visitor.bank;  
  3. public abstract class Service {  
  4.     public abstract void accept(Visitor v);  
  5.     public int getCounterNum(){  
  6.         //得到可用的服务柜台,现实中的算法可以是通过看哪个柜台空闲就到哪个柜台,或者是按照一定的规则排序。  
  7.         //这里为了简化,就用随机数。  
  8.         return (int) Math.floor((Math.random()*4));  
  9.     }  
  10. }  
  11. //访问者接口  
  12. package designpattern.visitor.bank;  
  13. public interface Visitor {  
  14.     public void visit(DrawService s);  
  15.     public void visit(SavingService s);  
  16. }  
  17. //  
  18. package designpattern.visitor.bank;  
  19. public class DrawService extends Service {  
  20.     public void accept(Visitor v) {  
  21.         v.visit(this);  
  22.     }  
  23. }  
  24. //  
  25. package designpattern.visitor.bank;  
  26. public class SavingService extends Service {  
  27.     public void accept(Visitor v) {  
  28.         v.visit(this);  
  29.     }  
  30. }  
  31. //  
  32. //普通存款取款访问者  
  33. package designpattern.visitor.bank;  
  34. public class CommonVisitor implements Visitor {  
  35.     public void visit(DrawService s) {  
  36.         System.out.println("您办理的是普通取款业务。" + "请到 " + s.getCounterNum() + " 窗口。");  
  37.     }  
  38.   
  39.     public void visit(SavingService s) {  
  40.         System.out.println("您办理的是普通存款业务。"  + "请到 " + s.getCounterNum() + " 窗口。");  
  41.     }  
  42.   
  43. }  
  44. //  
  45. //公司业务办理者  
  46. package designpattern.visitor.bank;  
  47. public class CompanyVisitor implements Visitor{  
  48.     public void visit(DrawService s) {  
  49.         System.out.println("您办理的是公司取款业务。" + "请到 " + s.getCounterNum() + " 窗口。");  
  50.     }  
  51.   
  52.     public void visit(SavingService s) {  
  53.         System.out.println("您办理的是公司存款业务。" + "请到 " + s.getCounterNum() + " 窗口。");  
  54.     }  
  55.   
  56. }  
  57. //  
  58. //股票第三方存款业务办理者  
  59. package designpattern.visitor.bank;  
  60. public class StockVisitor implements Visitor {  
  61.     public void visit(DrawService s) {  
  62.         System.out.println("您办理的是股票交易第三方取款业务。" + "请到 " + s.getCounterNum() + " 窗口。");  
  63.     }  
  64.   
  65.     public void visit(SavingService s) {  
  66.         System.out.println("您办理的是股票交易第三方存款业务。" + "请到 " + s.getCounterNum() + " 窗口。");  
  67.     }  
  68. }  
  69. //  
  70. //基金买卖委托业务办理者  
  71. package designpattern.visitor.bank;  
  72. public class FundVisitor implements Visitor {  
  73.     public void visit(DrawService s) {  
  74.         System.out.println("您办理的是基金委托买入业务。" + "请到 " + s.getCounterNum() + " 窗口。");  
  75.     }  
  76.   
  77.     public void visit(SavingService s) {  
  78.         System.out.println("您办理的是基金委托卖出业务。" + "请到 " + s.getCounterNum() + " 窗口。");  
  79.     }  

优点:

对类结构增加新的操作很容易,只需要增加一个新的访问者。

缺点:

1 复杂

2 当数据结构或类发生变化的时候改动太大。

经典案例:

找ing。。。

转自:http://blog.csdn.net/sunxing007/archive/2010/03/22/5404863.aspx

  评论这张
 
阅读(365)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017