15.访问者模式

在被访问的类里添加一个接待外部访问者的接口,在对一个对象结构中的对象做多个复杂操作的时候,又 不想让操作污染这些对象,可以使用该模式

 

 UML类图介绍:

 

Bill接口,这个接口有一个accept方法去接受访问者

/**
 * @author wuyimin
 * @create 2021-07-28 15:57
 * @description 账单的接口
 */
public interface Bill {
    public void accept(Visitor visitor);
}

Visitor接口。这个Bill接口有两个方法接受Bill接口的两个实现类对象

/**
 * @author wuyimin
 * @create 2021-07-28 15:57
 * @description 访问者
 */
public interface Visitor {
    //查看收入
    public void visitInput(InputBill inputBill);
    //查看支出
    public void visitOutput(OutputBill outputBill);
}

Bill接口的两个实现类,其重点主要在于重写accpet方法分别去接受visitor对应自己的方法

/**
 * @author wuyimin
 * @create 2021-07-28 16:02
 * @description 收入的账单
 */
public class InputBill implements Bill{
    //项目
    private String item;
    //收入的钱数目
    private double money;

    public String getItem() {
        return item;
    }

    public void setItem(String item) {
        this.item = item;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    public InputBill(String item, double money) {
        this.item = item;
        this.money = money;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visitInput(this);
    }
}
/**
 * @author wuyimin
 * @create 2021-07-28 15:59
 * @description 支出的账单
 */
public class OutputBill implements Bill {
    //项目
    private String item;
    //支出的钱数目
    private double money;

    public String getItem() {
        return item;
    }

    public void setItem(String item) {
        this.item = item;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    public OutputBill(String item, double money) {
        this.item = item;
        this.money = money;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visitOutput(this);
    }
}

两个Visitor,分别是Boss和CPA

/**
 * @author wuyimin
 * @create 2021-07-28 16:04
 * @description 老板类,老板只关系总收入和总支出,所以在方法里只是统计就行了
 */
public class Boss implements Visitor {
    private double totalIncome;
    private double totalOutcome;

    @Override
    public void visitInput(InputBill inputBill) {
        totalIncome+=inputBill.getMoney();
    }

    @Override
    public void visitOutput(OutputBill outputBill) {
        totalOutcome+=outputBill.getMoney();
    }
    public double getTotalIncome(){
        System.out.println("老板查看总收入为:"+totalIncome);
        return totalIncome;
    }
    public double getTotalOutcome(){
        System.out.println("老板查看总支出为:"+totalOutcome);
        return totalOutcome;
    }
}
/**
 * @author wuyimin
 * @create 2021-07-28 16:10
 * @description 注册会计师类,每次添加一个项目都会检查
 */
public class CPA implements Visitor {

    @Override
    public void visitInput(InputBill inputBill) {
        System.out.println("查看收入是否交税了");
    }

    @Override
    public void visitOutput(OutputBill outputBill) {
        if(outputBill.getItem().equals("工资")){
            System.out.println("查看工资是否交税了");
        }
    }
}

对象结构类,也就是账本类,在show方法中调用bill的accept接口

/**
 * @author wuyimin
 * @create 2021-07-28 16:13
 * @description 账本类,对象结构
 */
public class AccountBook {
    public ArrayList<Bill> billList=new ArrayList<>();
    public void add(Bill bill){
        billList.add(bill);
    }
    //提供接口给账本的查看者查看账本
    public void show(Visitor visitor){
        for (Bill bill:billList) {
            bill.accept(visitor);
        }
    }

    //测试的客户端
    public static void main(String[] args) {
        AccountBook accountBook = new AccountBook();

        //添加两条收入
        accountBook.add(new InputBill("卖商品",10000));
        accountBook.add(new InputBill( "卖广告位",12000));
        //添加两条支出
        accountBook.add(new OutputBill( "工资",1000));
        accountBook.add(new OutputBill("材料费",2000));

        Boss boss = new Boss();
        CPA cpa = new CPA();

        //两个访问者分别访问账本
        accountBook.show(cpa);
        accountBook.show(boss);
        //老板查账
        boss.getTotalOutcome();
        boss.getTotalIncome();

    }
}

上面的代码中,可以这么理解,账本以及账本中的元素是非常稳定的,这些几乎不可能改变,而最容易改变的就是访问者这部分。

访问者模式最大的优点就是增加访问者非常容易,我们从代码上来看,如果要增加一个访问者,你只需要做一件事即可,那就是写一个类,实现AccountBookViewer接口,然后就可以直接调用AccountBook的show方法去访问账本了。

如果没使用访问者模式,一定会增加许多if else,而且每增加一个访问者,你都需要改你的if else,代码会显得非常臃肿,而且非常难以扩展和维护。

 

 

 

 

 如果将上述代码的visitInput和visitOutput重载为两个Visit方法的话,我们就可以说访问者模式是伪动态双分派的

 

 

 

 

 

 

优点:

1、使得数据结构和作用于结构上的操作解耦,使得操作集合可以独立变化。

2、添加新的操作或者说访问者会非常容易。

3、将对各个元素的一组操作集中在一个访问者类当中。

4、使得类层次结构不改变的情况下,可以针对各个层次做出不同的操作,而不影响类层次结构的完整性。

5、可以跨越类层次结构,访问不同层次的元素类,做出相应的操作。

缺点:

1、增加新的元素会非常困难。

2、实现起来比较复杂,会增加系统的复杂性。

3、破坏封装,如果将访问行为放在各个元素中,则可以不暴露元素的内部结构和状态,但使用访问者模式的时候,为了让访问者能获取到所关心的信息,元素类不得不暴露出一些内部的状态和结构,就像收入和支出类必须提供访问金额和单子的项目的方法一样。

posted @ 2021-07-28 16:48  一拳超人的逆袭  阅读(38)  评论(0编辑  收藏  举报