设计模式-访问者模式

1、访问者模式被称为最复杂的设计模式。

访问者模式访问者模式( Visitor pattern)是一种将数据结构与数据操作分离的设计模式。是指封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。属于行为型模式。

访问者模式被称为最复杂的设计模式,并且使用频率不高,设计模式的作者也评价为:大多情况下,你不需要使用访问者模式,但是一旦需要使用它时,那就真的需要使用了。访问者模式的基本思想是,针对系统中拥有固定类型数的对象结构(元素),在其内提供一个 accept()方法用来接受访问者对象的访问。

不同的访问者对同一元素的访问内容不同,使得相同的元素集合可以产生不同的数据结果。 accept()方法可以接收不同的访问者对象然后在内部将自己(元素)转发到接收到的访问者对象的vsit()方法内。访问者内部对应类型的vst()方法就会得到回调执行,对元素进行操作。也就是通过两次动态分发(第一次是对访问者的分发aept()方法,第二次是对元素的分发ⅵsit()方法),才最终将一个具体的元素传递到一个具体的访问者。如此一来,就解耦了数据结构与操作,且数据操作不会改变元素状态。访问者模式的核心是,解耦数据结构与数据操作,使得对元素的操作具备优秀的扩展性。可以通过扩展不同的数据操作类型(访问者)实现对相同元素集的不同的操作。

利用访问者模式实现KP考核的场景为例:

package com.lx.designPattern.visitorpattern.kpi;

/**
 * @program: People
 * @description: 访问者接口
 * @author: liu wei ping
 * @create: 2022-05-22 13:51
 */
public interface IVisitor {

    void visit(Engineer engineer);

    void visit(Manager manager);
}


package com.lx.designPattern.visitorpattern.kpi;

/**
 * @program: People
 * @description: CEO访问者
 * @author: liu wei ping
 * @create: 2022-05-22 13:48
 */
public class CEOVistitor implements IVisitor{
    public void visit(Engineer engineer) {
        System.out.println("工程师" + engineer.name + ". KPI:" + engineer.kpi);

    }

    public void visit(Manager manager) {
        System.out.println("经理:" + manager.name + ",KPI:" + manager.kpi + ". 产品数量:" + manager.getProducts());
    }
}


package com.lx.designPattern.visitorpattern.kpi;

/**
 * @program: People
 * @description: CTO访问者
 * @author: liu wei ping
 * @create: 2022-05-22 13:49
 */
public class CTOVistitor implements IVisitor{
    @Override
    public void visit(Engineer engineer) {
        System.out.println("工程师" + engineer.name + ", 代码行数" + engineer.getCodeLines());
    }

    public void visit(Manager manager) {
        System.out.println("" + manager.name + ". 产品数量" + manager.getProducts());
    }
}
package com.lx.designPattern.visitorpattern.kpi;

import java.util.Random;

/**
 * @program: People
 * @description: 员工
 * @author: liu wei ping
 * @create: 2022-05-22 13:49
 */
public abstract   class Employee {
    public String name;
    public int kpi; //员工KPI

    public Employee(String name) {
        this.name = name;
        kpi = new Random().nextInt(10);
    }

    //接收访问者的访问
    public  abstract void accept(IVisitor visitor);
}


package com.lx.designPattern.visitorpattern.kpi;

import java.util.Random;

/**
 * @program: People
 * @description: 工程师
 * @author: liu wei ping
 * @create: 2022-05-22 13:50
 */
public class Engineer extends Employee{

    public Engineer(String name) {
        super(name);
    }

    @Override
    public void accept(IVisitor visitor) {
         visitor.visit(this);
    }

    public int getCodeLines(){
        return  new Random().nextInt(10*10000);
    }

}


package com.lx.designPattern.visitorpattern.kpi;

import java.util.Random;

/**
 * @program: People
 * @description: 经理
 * @author: liu wei ping
 * @create: 2022-05-22 13:51
 */
public class Manager extends Employee{

    public Manager(String name) {
        super(name);
    }

    @Override
    public void accept(IVisitor visitor) {
        visitor.visit(this);
    }

    //考核的是每年新产品研发数量
    public int  getProducts(){
        return new Random().nextInt(10);
    }

}
package com.lx.designPattern.visitorpattern.kpi;

import java.util.LinkedList;
import java.util.List;

/**
 * @program: People
 * @description: 业务报表数据
 * @author: liu wei ping
 * @create: 2022-05-22 13:48
 */
public class BusinessReport {
    private List<Employee> employees = new LinkedList<Employee>();

    public  BusinessReport(){
        employees.add(new Manager("产品经理A"));
        employees.add(new Engineer("程序员A"));
        employees.add(new Engineer("程序员B"));
        employees.add(new Engineer("程序员C"));
        employees.add(new Manager("产品经理B"));
        employees.add(new Engineer("程序员D"));
    }

    public  void showReport(IVisitor visitor){
        for (Employee employee : employees) {
            employee.accept(visitor);
        }
    }



}
package com.lx.designPattern.visitorpattern.kpi;

/**
 * @program: People
 * @description: 访问者模式测试类
 * @author: liu wei ping
 * @create: 2022-05-22 13:52
 */
public class Test {
    public static void main(String[] args) {
        BusinessReport report = new BusinessReport();
        System.out.println("===========CEO看报表=============");
        report.showReport(new CEOVistitor());
        System.out.println("===========CTO看报表=============");
        report.showReport(new CTOVistitor());

    }
}

测试结果如下图:

访问者模式的优缺点

优点:

1、解耦了数据结构与数据操作,使得操作集合可以独立变化;

2、扩展性好:可以通过扩展访问者角色,实现对数据集的不同操作;

3、元素具体类型并非单一,访问者均可操作

4、各角色职责分离,符合单一职责原则。

缺点:

1、无法增加元素类型:若系统数据结构对象易于变化,经常有新的数据对象增加进来,则访问者类必须增加对应元素类型的操作,违背了开闭原则;

2、具体元素变更困难∶具体元素增加属性,删除属性等操作会导致对应的访问者类需要进行相应的修改,尤其当有大量访问者类时,修改范围太大;

3、违背依赖倒置原则:为了达到”区别对待“,访问者依赖的是具体元素类型,而不是抽象。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值