设计模式18 - 访问者模式【Visitor Pattern】

简介: 设计模式18 - 访问者模式【Visitor Pattern】

访问者模式

定义:

表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。

举例:(记账例子):

账本只有收入和消费类型,而访问者有多种,如老板和会计。

/**
 * 账单接口,有接受访问者的功能
 */
interface Bill {
    void accept(AccountBookView viewer);
}
/**
*消费账单
*/
class ConsumerBill implements Bill {
    private String item;
    private double amount;
    public ConsumerBill(String item, double amount) {
        this.item = item;
        this.amount = amount;
    }
    @Override
    public void accept(AccountBookView viewer) {
        viewer.view(this);
    }
    public String getItem() {
        return item;
    }
    public double getAmount() {
        return amount;
    }
}
/*
*支出账单
*/
class IncomingBill implements Bill {
    private String item;
    private double amount;
    public IncomingBill(String item, double amount) {
        this.item = item;
        this.amount = amount;
    }
    @Override
    public void accept(AccountBookView viewer) {
        viewer.view(this);
    }
    public String getItem() {
        return item;
    }
    public double getAmount() {
        return amount;
    }
}
/**
*访问者接口
*/
interface AccountBookView {
    //查看消费的单子
    void view(ConsumerBill consumerBill);
    //查看收入单子
    void view(IncomingBill incomingBill);
}
/**
*访问者老板
*/
class Boss implements AccountBookView {
    private double totalConsumer;
    private double totalIncome;
    @Override
    public void view(ConsumerBill consumerBill) {
        totalConsumer = totalConsumer + consumerBill.getAmount();
    }
    @Override
    public void view(IncomingBill incomingBill) {
        totalIncome = totalIncome + incomingBill.getAmount();
    }
    public void getTotalConsumer() {
        System.out.println("老板一共消费了" + totalConsumer);
    }
    public void getTotalIncome() {
        System.out.println("老板一共收入了" + totalIncome);
    }
}
/**
*访问者会计
*/
class CPA implements AccountBookView {
    int count = 0;
    // 查看消费的单子
    public void view(ConsumerBill consumerBill) {
        count++;
        if (consumerBill.getItem().equals("消费")) {
                    System.out.println("第" + count + "个单子消费了:" + consumerBill.getAmount());
        }
    }
    // 查看收入单子
    public void view(IncomingBill incomeBill) {
        if (incomeBill.getItem().equals("收入")) {
            System.out.println("第" + count + "个单子收入了:" + incomeBill.getAmount());
        }
    }
}
/**
*账单类:用于添加账单,和为每一个账单添加访问者
*/
class AccountBook {
    private List<Bill> listBill = new ArrayList<Bill>();
    // 添加单子
    public void add(Bill bill) {
        listBill.add(bill);
    }
    // 为每个账单添加访问者
    public void show(AccountBookView viewer) {
        for (Bill b : listBill) {
            b.accept(viewer);
        }
    }
}
/**
* 客户端
*/
public class Client{
    public void main(String[] args) {
        // 创建消费和收入单子
        Bill consumerBill = new ConsumerBill("消费", 3000);
        Bill incomeBill = new IncomingBill("收入", 5000);
        Bill consumerBill2 = new ConsumerBill("消费", 4000);
        Bill incomeBill2 = new IncomingBill("收入", 8000);
        // 添加单子
        AccountBook accountBook = new AccountBook();
        accountBook.add(consumerBill);
        accountBook.add(incomeBill);
        accountBook.add(consumerBill2);
        accountBook.add(incomeBill2);
        // 创建访问者
        AccountBookView boss = new Boss();
        AccountBookView cpa = new CPA();
        // 接受访问者
        accountBook.show(boss);
        accountBook.show(cpa);
        // boss查看总收入和总消费
        ((Boss) boss).getTotalConsumer();
        ((Boss) boss).getTotalIncome();
    }

总结:

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

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

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

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

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

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

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

使用场景:

1、对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。

2、需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作”污染”这些对象的类,也不希望在增加新操作时修改这些类。

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


目录
相关文章
|
2月前
|
设计模式 JavaScript 前端开发
JavaScript设计模式--访问者模式
【10月更文挑战第1天】
33 3
|
3月前
|
设计模式
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
这篇文章详细解释了工厂模式,包括简单工厂、工厂方法和抽象工厂三种类型。每种模式都通过代码示例展示了其应用场景和实现方法,并比较了它们之间的差异。简单工厂模式通过一个工厂类来创建各种产品;工厂方法模式通过定义一个创建对象的接口,由子类决定实例化哪个类;抽象工厂模式提供一个创建相关或依赖对象家族的接口,而不需要明确指定具体类。
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
|
7月前
|
设计模式 算法 Java
【设计模式】JAVA Design Patterns——Acyclic Visitor(非循环访问者模式)
【设计模式】JAVA Design Patterns——Acyclic Visitor(非循环访问者模式)
|
3月前
|
设计模式 Java
设计模式--适配器模式 Adapter Pattern
这篇文章介绍了适配器模式,包括其基本介绍、工作原理以及类适配器模式、对象适配器模式和接口适配器模式三种实现方式。
|
3月前
|
设计模式 缓存 算法
Java设计模式-访问者模式(22)
Java设计模式-访问者模式(22)
|
6月前
|
设计模式
设计模式-05建造者模式(Builder Pattern)
设计模式-05建造者模式(Builder Pattern)
|
7月前
|
设计模式 安全 Java
【设计模式】JAVA Design Patterns——Curiously Recurring Template Pattern(奇异递归模板模式)
该文介绍了一种C++的编程技巧——奇异递归模板模式(CRTP),旨在让派生组件能继承基本组件的特定功能。通过示例展示了如何创建一个`Fighter`接口和`MmaFighter`类,其中`MmaFighter`及其子类如`MmaBantamweightFighter`和`MmaHeavyweightFighter`强制类型安全,确保相同重量级的拳手之间才能进行比赛。这种设计避免了不同重量级拳手间的错误匹配,编译时会报错。CRTP适用于处理类型冲突、参数化类方法和限制方法只对相同类型实例生效的情况。
【设计模式】JAVA Design Patterns——Curiously Recurring Template Pattern(奇异递归模板模式)
|
7月前
|
设计模式 安全 Java
【设计模式】字节三面:请举例阐释访问者模式
【设计模式】字节三面:请举例阐释访问者模式
49 2
|
7月前
|
设计模式 存储 Java
Java设计模式:解释一下单例模式(Singleton Pattern)。
`Singleton Pattern`是Java中的创建型设计模式,确保类只有一个实例并提供全局访问点。它通过私有化构造函数,用静态方法返回唯一的实例。类内静态变量存储此实例,对外仅通过静态方法访问。
53 1
|
7月前
|
设计模式 Go
[设计模式 Go实现] 行为型~访问者模式
[设计模式 Go实现] 行为型~访问者模式