设计模式-20-访问者模式 Visitor -[行为模式]

1.访问者模式的简介

    将作用于某种数据结构中的各[元素的操作]分离出来[封装成独立的类],使其在[不改变数据结构]的前提下可以[添加作用于这些元素的新的操作],为数据结构中的每个元素提供多种访问方式;
它将对数据的操作与数据结构进行分离,是行为类模式中最复杂的一种模式。

2.访问者模式的角色

  1. 抽象访问者(Visitor)-[访客]角色:定义一个访问具体元素的接口,为每个具体元素类(东家)对应一个访问操作(看人-不同的东家,不同的操作) ,该操作中的[参数类型]标识了被访问的具体元素(参数类型为东家的声明)。
  2. 抽象元素(Element)-[东家]角色:声明一个包含接受操作 accept(访客) 的接口,访客对象作为 accept() 方法的参数。
  3. 具体访问者(ConcreteVisitor)-[访客]角色:实现抽象访问者角色中声明的各个访问操作,确定访问者访问每一个元素时该做什么(多态)
  4. 具体元素(ConcreteElement)-[东家]角色:实现抽象元素角色提供的 accept() 操作,其方法体通常都是 visitor.visit(this) ,另外具体元素中可能还包含本身业务逻辑的相关操作。
  5. 对象结构(Object Structure)-[存放多个东家-可迭代(访客为入参)]角色:是一个包含元素角色的容器(多个东家的集合),提供让访问者对象遍历容器中的所有元素的方法,通常由 List、Set、Map 等聚合类实现。

3.访问者模式的简单示例

    一个公司的员工上班期间不能穿拖鞋,但是回到家可以;在这里公司、家都是两个不容易变动的部门,员工作为一个访客在不同的环境下有不同的行为;
抽象访问者(Visitor)-[访客]角色
/**
 * 抽象访问者(Visitor)-[访客]角色
 */
public interface A1_Visitor {

    /**
     * 定义访客的行为:在家里穿的鞋子
     */
    void putonShoe(B1_Element_Home element);

    /**
     * 定义访客的行为:在公司穿的鞋子
     */
    void putonShoe(B2_Element_Company element);
}
抽象元素(Element)-[东家]角色 : 这里指公司、家
/**
 * 抽象元素(Element)-[东家]角色 : 这里指公司、家
 */
public abstract class A2_Element {

    //声明接受哪一类访问者访问
    public abstract void accept(A1_Visitor visitor);
}
具体元素(ConcreteElement)-[东家]角色 : 这里指 家
/**
 * 具体元素(ConcreteElement)-[东家]角色 : 这里指 家
 */
public class B1_Element_Home extends A2_Element{
    @Override
    public void accept(A1_Visitor visitor) {
        visitor.putonShoe(this);
    }
}
具体元素(ConcreteElement)-[东家]角色 : 这里指 公司
/**
 * 具体元素(ConcreteElement)-[东家]角色 : 这里指 公司
 */
public class B2_Element_Company extends A2_Element{
    @Override
    public void accept(A1_Visitor visitor) {
        visitor.putonShoe(this);
    }
}
具体访问者(ConcreteVisitor)-[访客]角色 : 这里指员工在家里、公司 的表现
/**
 * 具体访问者(ConcreteVisitor)-[访客]角色 : 这里指员工在家里、公司 的表现
 */
public class C1_Visitor_Staff implements A1_Visitor {
    @Override
    public void putonShoe(B1_Element_Home element) {
        System.out.println("员工在家里:开心的穿着拖鞋");
    }

    @Override
    public void putonShoe(B2_Element_Company element) {
        System.out.println("员工在单位:优雅的穿着皮鞋");
    }
}
对象结构(Object Structure)-[存放多个东家-可迭代(访客为入参)]角色  : 这里存放 公司、家对象
/**
 * 对象结构(Object Structure)-[存放多个东家-可迭代(访客为入参)]角色  : 这里存放 公司、家对象
 */
public class D1_Structure {

    private List<A2_Element> elements = new ArrayList<>();

    public void elementPut(A2_Element element){
        elements.add(element);
    }


    public void elementRemove(A2_Element element){
        elements.remove(element);
    }

    public void accept(A1_Visitor visitor){
        for(A2_Element item : elements){
            item.accept(visitor);
        }
    }
}
客户端调用
/**
 * 客户端调用
 */
public class E1_Client {
    public static void main(String[] args) {
        //对象结构(Object Structure)-[存放多个东家-可迭代(访客为入参)]角色
        D1_Structure structure = new D1_Structure();
        A2_Element home = new B1_Element_Home();
        A2_Element company = new B2_Element_Company();
        structure.elementPut(home);
        structure.elementPut(company);

        //具体访问者(ConcreteVisitor)-[访客]角色
        A1_Visitor visitor = new C1_Visitor_Staff();

        //将对数据的操作与数据结构进行分离
        structure.accept(visitor);
    }
}

调用结果:

员工在家里:开心的穿着拖鞋
员工在单位:优雅的穿着皮鞋

4.访问者模式的优点

  • 扩展性好 : 能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能(集合添加的都是接口或抽象类)。
  • 复用性好 : 可以通过访问者来定义整个对象结构通用的功能,从而提高系统的复用程度。
  • 灵活性好 : 访问者模式将数据结构与作用于结构上的操作解耦,使得操作集合可相对自由地演化而不影响系统的数据结构。
  • 符合单一职责原则 : 访问者模式把相关的行为封装在一起,构成一个访问者,使每一个访问者的功能都比较单一。

5.访问者模式的缺点

  • 增加新的元素类很困难(东家类)。在访问者模式中,每增加一个新的元素类,都要在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则(增加一个东家,就需要在访客类中增加对该东家的处理方式)
  • 破坏封装。访问者模式中具体元素访问者公布细节,这破坏了对象的封装性。
  • 违反了依赖倒置原则。访问者模式依赖了具体类,而没有依赖抽象类。

6.访问者模式的应用场景

  • 1、一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
  • 2、需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。Visitor模式使得你可以将相关的操作集中起来定义在一个类中
  • 3、当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值