访问者模式(十八)

相信自己,请一定要相信自己

上一章简单介绍了命令模式(十七), 如果没有看过, 请观看上一章

一. 访问者模式

引用 菜鸟教程里面访问者模式介绍: https://www.runoob.com/design-pattern/visitor-pattern.html

在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。

通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。

根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作

一.一 介绍

意图: 主要将数据结构与数据操作分离。

主要解决: 稳定的数据结构和易变的操作耦合问题。

何时使用: 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,使用访问者模式将这些封装到类中。

如何解决: 在被访问的类里面加一个对外提供接待访问者的接口。

关键代码: 在数据基础类里面有一个方法接受访问者,将自身引用传入访问者。

应用实例: 您在朋友家做客,您是访问者,朋友接受您的访问,您通过朋友的描述,然后对朋友的描述做出一个判断,这就是访问者模式。

优点: 1、符合单一职责原则。 2、优秀的扩展性。 3、灵活性。

缺点: 1、具体元素对访问者公布细节,违反了迪米特原则。 2、具体元素变更比较困难。 3、违反了依赖倒置原则,依赖了具体类,没有依赖抽象。

使用场景: 1、对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。 2、需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类。

注意事项: 访问者可以对功能进行统一,可以做报表、UI、拦截器与过滤器。


组成角色 具体 关系
抽象访问者(Visitor)角色 Action 一个访问具体元素的接口,为每个具体元素类对应一个访问操作 visit() ,该操作中的参数类型标识了被访问的具体元素
具体访问者(ConcreteVisitor)角色 FailAction, SuccessAction 实现抽象访问者角色中声明的各个访问操作,确定访问者访问一个元素时该做什么
抽象元素(Element)角色 Person 声明一个包含接受操作 accept() 的接口,被接受的访问者对象作为 accept() 方法的参数
具体元素(ConcreteElement)角色 Man WoMan 实现抽象元素角色提供的 accept() 操作,其方法体通常都是 visitor.visit(this) ,另外具体元素中可能还包含本身业务逻辑的相关操作
对象结构(Object Structure)角色 ObjectStructure 是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由 List、Set、Map 等聚合类实现

image-20230615171102299

二. 访问者实例

二. 一 抽象访问者 Action

public abstract class Action {
    
    

    public abstract void getManResult (Man man);

    public abstract void getWomanResult(WoMan woMan);
}

二.二 具体访问者实现

二.二.一 差

@Slf4j
public class FailAction extends Action{
    
    

    @Override
    public void getManResult(Man man) {
    
    
        log.info("男生{}评价差",man.getName());
    }

    @Override
    public void getWomanResult(WoMan woMan) {
    
    
        log.info("女生评价{}差",woMan.getName());
    }
}

二.二.二 优

@Slf4j
public class SuccessAction extends Action{
    
    

    @Override
    public void getManResult(Man man) {
    
    
        log.info("男生{}评价优秀",man.getName());
    }

    @Override
    public void getWomanResult(WoMan woMan) {
    
    
        log.info("女生评价{}优秀",woMan.getName());
    }
}

二.二.三 待评价

@Slf4j
public class WaitAction extends Action{
    
    

    @Override
    public void getManResult(Man man) {
    
    
        log.info("男生{} 待评价",man.getName());
    }

    @Override
    public void getWomanResult(WoMan woMan) {
    
    
        log.info("女生{}待评价",woMan.getName());
    }
}

二.三 抽象元素 Person

@EqualsAndHashCode(of = {
    
    "name"})
public abstract class Person {
    
    
    private String name;

    public abstract  void accept(Action action);

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }
}

二.四 具体元素

二.四.一 男人

public class Man extends Person{
    
    
    public Man (String name) {
    
    
        super.setName(name);
    }
    @Override
    public void accept(Action action) {
    
    
        action.getManResult(this);
    }
}

二.四.二 女人

public class WoMan extends Person{
    
    
    public WoMan (String name) {
    
    
       super.setName(name);
    }
    @Override
    public void accept(Action action) {
    
    
        action.getWomanResult(this);
    }
}

二.五 对象结构 ObjectStructure

public class ObjectStructure {
    
    

    private List<Person> personList = new ArrayList<>();

    public void accept( Person person) {
    
    
        personList.add(person);
    }

    public void remove(Person person) {
    
    
        personList.remove(person);
    }

    public void display (Action action) {
    
    
        for (Person person : personList) {
    
    
            person.accept(action);
        }
    }
}

二.六 测试

@Test
    public void oneTest() {
    
    
        ObjectStructure objectStructure = new ObjectStructure();
        objectStructure.accept(new Man("张三"));
        // 是成功的
        objectStructure.display(new SuccessAction());

        objectStructure.remove(new Man("张三"));
        objectStructure.accept(new Man("李四"));

        objectStructure.display(new FailAction());

        objectStructure.remove(new Man("李四"));
        objectStructure.accept(new WoMan("王二"));
        objectStructure.accept(new WoMan("麻子"));

        objectStructure.display(new WaitAction());

    }

image-20230615171718905

优点:

  1. 访问者模式符合单一职责原则、让程序具有优秀的扩展性、灵活性非常高

  2. 访问者模式可以对功能进行统一,可以做报表、UI、拦截器与过滤器,适用于数据结构相对稳定的系统

缺点:

  1. 具体元素对访问者公布细节,也就是说访问者关注了其他类的内部细节,这是迪米特法则所不建议的, 这样造 成了具体元素变更比较困难

  2. 违背了依赖倒转原则。访问者依赖的是具体元素,而不是抽象元素

  3. 因此,如果一个系统有比较稳定的数据结构,又有经常变化的功能需求,那么访问者模式就是比较合适的.


本章节的代码放置在 github 上:


https://github.com/yuejianli/DesignPattern/tree/develop/Visitor


谢谢您的观看,如果喜欢,请关注我,再次感谢 !!!

猜你喜欢

转载自blog.csdn.net/yjltx1234csdn/article/details/131232360