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

677 阅读3分钟

1、定义

封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作。

2、模式结构

访问者模式由五部分组成:

  • Vistor(抽象访问者):抽象访问者为对象结构中每一个具体元素类ConcreteElement声明一个访问操作,从这个操作的名称或参数类型可以清楚知道需要访问的具体元素的类型,具体访问者则需要实现这些操作方法,定义对这些元素的访问操作。
  • ConcreteVisiter(具体访问者):具体访问者实现了每个由抽象访问者声明的操作,每一个操作作用于访问对象结构中一种类型的元素。
  • Element(抽象元素):抽象元素一般是抽象类或者接口,它定义一个accept()方法,该方法通常从一个抽象访问者作为参数。
  • ConcreteElement(具体元素):具体元素实现了accept()方法,在accept()方法中调用访问者的访问方法以便完成对一个元素的操作。
  • ObjectStructure(对象结构):对象结构是一个元素的集合,它用于存放元素对象,并且提供了遍历其内部元素的方法,它可以结合组合模式来完成,也可以是一个简单的集合对象,如一个List对象或一个Set对象。

3、实例

3.1 Action(Vistor)

public interface Action {
    
    public void getManResult(Man man);
    
    public void getWomanResult(Woman woman);
}

3.2 Success 和 Fail(ConcreteVisiter)

public class Success implements Action {
    
    @Override
    public void getManResult(Man man) {
        System.out.println("男人给的评价是成功通过!!!");
    }
    
    @Override
    public void getWomanResult(Woman woman) {
        System.out.println("女人给的评价是成功通过!!!");
    }
}
public class Fail implements Action {
    
    @Override
    public void getManResult(Man man) {
        System.out.println("男人给的评价是不通过!!!");
    }
    
    @Override
    public void getWomanResult(Woman woman) {
        System.out.println("女人给的评价是不通过!!!");
    }
}

3.3 Person(Element)

public interface Person {
    
    public void accept(Action action);
}

3.4 Man 和 Woman(ConcreteElement)

public class Man implements Person {
    
    @Override
    public void accept(Action action) {
        action.getManResult(this);
    }
}
public class Woman implements Person {
    
    @Override
    public void accept(Action action) {
        action.getWomanResult(this);
    }
}

3.5 ObjectStructure

public class ObjectStructure {
    
    private List<Person> persons = new ArrayList<>();
    
    public void add(Person person) {
        persons.add(person);
    }
    
    public void remove(Person person) {
        persons.remove(person);
    }
    
    public void display(Action action) {
        for (Person person : person) {
            person.accept(action);
        }
    }
}

3.6 客户端调用

public class Client {
    
    public static void main(String[] args) {
        
        ObjectStructure objectStructure = new ObjectStructure();
        
        objectStructure.add(new Man());
        objectStructure.add(new Woman());
        
        Success success = new Success();
        objectStructure.display(success);
        System.out.println("---------------------------");
        
        Fail fail = new Fail();
        objectStructure.display(fail);
    }
}

4、适用场景

  • 对象结构中对象对于的类很少改变,但经常需要在此对象结构上定义新的操作。
  • 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作“污染”这些对象的类,也不希望在增加新操作时修改这些类。

5、优缺点

5.1 优点
  • 扩展性好,在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。
  • 复用性好,通过访问者来定义整个对象结构通用的功能,从而提高复用程度。
  • 将有关元素对象的访问行为集中到一个访问者对象,而不是分散在一个个的元素类中,类的职责更加清晰,符合单一职责原则。
5.2 缺点
  • 增加新的元素类很困难,需要在每一个访问者类增加相应访问操作代码,这违背了开闭原则。
  • 元素对象有时候必须暴露一些自己的内部操作和状态,否则无法供访问者访问,这破坏了元素的封装性。

源代码:github.com/freedom9/de…