Java设计模式之访问者模式

1. 访问者模式

1.1 定义、优缺点、适用场景

定义:访问者模式(Visitor Pattern),封装一些作用于某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。基本工作原理是:在被访问的类里面加一个对外提供接待访问者的接口

优点

  • 可以很方便的添加新的访问者,保证了开闭原则,利于维护
  • 将数据结构与数据操作分离,解决数据结构和操作耦合性问题
  • 符合单一职责原则、让程序具有优秀的扩展性、灵活性非常高
  • 可以对功能进行统一,可以做报表、UI、拦截器与过滤器,适用于数据结构相对稳定的系统

缺点

  • 不能方便的添加新的元素者
  • 具体元素对访问者公布细节,也就是说访问者关注了其他类的内部细节,这是迪米特法则所不建议的, 这样造成了具体元素变更比较困难
  • 违背了依赖倒转原则。访问者依赖的是具体元素,而不是抽象元素

适用场景

  • 需要对一个对象结构中的对象进行很多不同操作(这些操作彼此没有关联),同时需要避免让这些操作"污染"这些对象的类,可以用访问者模式解决
  • 不同的访问者对被访问者的关注点不一样。且想很方便的添加访问者,不添加新的被访问者
  • 一个系统有比较稳定的数据结构,又有经常变化的功能需求,那么访问者模式就比较合适

1.2 模式的结构与实现

结构

  • 抽象元素类(Element):定义一个accept 方法,接收一个访问者对象
  • 具体元素类(ConcreteElement):实现了accept方法
  • 抽象访问类(Visitor):为该对象结构中的ConcreteElement的每一个类声明一个visit操作
  • 具体访问类(ConcreteVisitor):实现Visitor声明的操作,是每个操作实现的部分
  • 对象结构(ObjectStructure):对象结构是一个抽象表述,它内部管理了元素集合,并且可以迭代这些元素提供访问者访问

实现
公司年终考核项目:CEO和CTO对工程师和销售员考核时,CEO关注的重点和CTO关注的重点是不一样的。而且可以很方便的添加其它领导对员工进行考核

import java.util.ArrayList;
import java.util.List;

public class VisitorTest {

    public static void main(String[] args) {

        ObjectStructure objectStructure = new ObjectStructure();
        // 添加员工,进行统一管理
        objectStructure.add(new Engineer());
        objectStructure.add(new Saler());

        // CEO对所有员工进行考核
        System.out.println("======CEO开始进行考核=======");
        Visitor ceoVisitor = new CeoVisitor();
        objectStructure.leaderCheckStaff(ceoVisitor);

        // CTO对所有员工进行考核
        System.out.println("======CTO开始进行考核=======");
        Visitor ctoVisitor = new CtoVisitor();
        objectStructure.leaderCheckStaff(ctoVisitor);
    }

}

// 抽象元素类-员工
abstract class Staff {

    // 员工接受领导的考核
    public abstract void accept(Visitor visitor);
}


// 这里用到了双分派。不管类怎么变化,我们都能找到期望的方法运行。意味着得到执行的操作取决于请求的种类和接收者的类型
// 第一次分派:VisitorTest客户端中,将visitor作为参数传递给engineer的accept方法
// 第二次分派:engineer类对象将自身作为参数传递给visitor的checkEngineer方法

// 具体元素类-工程师
class Engineer extends Staff {

    @Override
    public void accept(Visitor visitor) {
        // 领导对工程师的考核,不同的领导考核点不一样
        visitor.checkEngineer(this);
    }

}


// 具体元素类-销售员
class Saler extends Staff {

    @Override
    public void accept(Visitor visitor) {
        // 领导对销售员的考核,不同的领导考核点不一样
        visitor.checkSaler(this);
    }

}


// 抽象访问类
abstract class Visitor {

    // 领导对工程师的考核
    public abstract void checkEngineer(Engineer engineer);

    // 领导对销售员的考核
    public abstract void checkSaler(Saler saler);
}

// 具体访问类-CEO
class CeoVisitor extends Visitor {

    @Override
    public void checkEngineer(Engineer engineer) {
        System.out.println("CEO关注的是工程师给公司研发的新产品");
    }

    @Override
    public void checkSaler(Saler saler) {
        System.out.println("CEO关注的是销售员给公司带来的业绩");
    }

}


// 具体访问类-CTO
class CtoVisitor extends Visitor {

    @Override
    public void checkEngineer(Engineer engineer) {
        System.out.println("CTO关注的是工程师的技术深度和广度");
    }

    @Override
    public void checkSaler(Saler saler) {
        System.out.println("CTO关注的是销售员的销售技巧");
    }


}


//数据结构:用集合对员工进行统一管理
class ObjectStructure {

    private List<Staff> staffs = new ArrayList<Staff>();

    public void add(Staff staff) {
        this.staffs.add(staff);
    }

    public void remove(Staff staff) {
        this.staffs.remove(staff);
    }

    // 接收一个领导,对所有员工进行考核
    public void leaderCheckStaff(Visitor visitor) {
        for (Staff staff : this.staffs) {
            staff.accept(visitor);
        }
    }
}

运行程序,结果如下:

======CEO开始进行考核=======
CEO关注的是工程师给公司研发的新产品
CEO关注的是销售员给公司带来的业绩
======CTO开始进行考核=======
CTO关注的是工程师的技术深度和广度
CTO关注的是销售员的销售技巧
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值