设计模式(十九)访问者模式

版权声明:本文为博主原创文章,未经博主允许不得转载。转载请注明出处,并告知本人 https://blog.csdn.net/the_conquer_zzy/article/details/83628285

访问者模式

访问者模式的场景:

公司老板要看报表, 公司有销售,财务,研发,每个员工有自己独特的信息,最常见的做法是: 定义抽象员工,并定义模板方法,每一个员工实现自己角色的个性化方法,通过模板方法report来访问。
比如是这样的,

 public abstract Employee{
 private String name;
 private String telephone;
 public String getBasicInfo(){
	return name+"tel: "+telephone;
}
public abstract String getSpecialInfo();
	public void report(){
		System.out.println(getBasicInfo());
		System.out.println(getSpecialInfo());
	}
}

这样每个员工继承基类,各自实现自己的特殊信息就可以了。

但是这样有一个问题,报表的输出格式全由report() 方法控制, 如果有一天老板想换种报表格式,比如不想看员工姓名了怎么办?
是不是要修改基类的report方法了, 开闭原则指导要对修改关闭对扩展开放, 如果直接改基类report也会出现问题,比如今天一个格式出报表,改下基类,明天又换个格式改报表,又要改基类,还想同时出两份格式不同的报表怎么办?
所以就引出本文中提到的访问者模式。
首先分析,要为每一个角色个性化自己的报表方法,可以把角色作为参数传给一个单独的访问者对象Visitor, 由Visitor利用多态来实现个性化输出。并且由Visitor 去负责产生报表格式。 对象和Visitor是弱耦合的,不是继承关系。 这种实现方式便于扩展,需要产生不同格式的报表,多添加一个Visitor完成这个特殊的功能就可以了。

在这里插入图片描述

访问者模式的角色

  • Visitor 抽象访问者。 声明哪些元素可以访问

  • ConcreteVisitor 具体访问者。 访问到一个类后,具体怎么做,做什么

  • Element 抽象元素。 接口或者抽象类,声明接受哪一类访问者访问。程序中通过accept方法中的参数来定义

  • ConcreteElement 具体元素,实现accept方法

  • ObjectStructure 结构对象。 元素产生者

    public abstract class  Element {
          
          public abstract void doSomething();
          public abstract void accept(IVisitor visitor);
      }
      public class ConcreteElement1 extends Element{
          @Override
          public void doSomething() {
              //业务处理
          }
          //允许哪个访问者访问
          @Override
          public void accept(IVisitor visitor) {
              visitor.visit(this);
          }
      }
         public class ConcreteElement2 extends Element{
          @Override
          public void doSomething() {
              //业务处理
          }
          //允许哪个访问者访问
          @Override
          public void accept(IVisitor visitor) {
              visitor.visit(this);
          }
      }
    
    
     public interface  IVisitor{
          public void visit(ConcreteElement1 el1);
          public void visit(ConcreteElement2 el2);
      }
      public class Visitor implements IVisitor{
          @Override
          public void visit(ConcreteElement1 el1) {
              el1.doSomething();
          }
          @Override
          public void visit(ConcreteElement2 el2) {
              el2.doSomething();
          }
      }
      public class ObjectStructure{
          public static Element createElement(){
              Random rand=new Random();
              if(rand.nextInt(100)>50){
                  return new ConcreteElement1();
              }else{
                  return new ConcreteElement2();
              }
              
          }
      }
      public class  Client{
          public static void main(String[] args){
              for(int i=0;i<10;i++){
                  Element e=ObjectStructure.createElement();
                  e.accept(new Visitor());
              }
          }
      }
    

访问者模式优点

  • 符合单一原则。 Visitor负责报表的实现,Employee及其子类负责数据加载
  • 优秀的扩展性。 如果需要不同的格式报表,直接新增Visitor或者在Visitor新增方法就可以了。
  • 灵活性高。

访问者模式的缺点

  • 具体元素对访问者公布细节。 违反迪米特法则
  • 具体元素变更比较困难
  • 违背了依赖倒置原则。 放弃接口,依赖实现类,扩展比较困难。

访问者模式的使用场景

  • 需要遍历不同的对象, 迭代器模式只能访问同类或同接口的数据,访问者模式是对迭代器模式的 扩充,可以根据不同的对象,执行不同的操作。

java 静态多分派,动态单分派。 静态,动态是一对概念。 单分派和多分派是一个对概念。 根据宗量(参数)的多少分为多分派和单分派。

猜你喜欢

转载自blog.csdn.net/the_conquer_zzy/article/details/83628285