设计模式-行为型之访问者模式

模式动机

  在实际使用时,对同一集合对象的操作并不是唯一的,对相同的元素对象可能存在多种不同的操作方式。而且这些操作方式并不稳定,可能还需要增加新的操作,以满足新的业务需求。此时,我们可以考虑访问者模式,访问者模式的目的是封装一些施加于某种数据结构元素之上的操作,一旦这些操作需要修改的话,接受这个操作的数据结构可以保持不变。为不同类型的元素提供多种访问操作方式,且可以在不修改原有系统的情况下增加新的操作方式。

模式定义

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

模式结构

模式结构
  抽象访问者:Vistor,定义访问操作visit()
  具体访问者:ConcreteVisitor
  抽象元素:Element,定义被访问操作accept()
  具体元素 : ConcreteElement
  对象结构:ObjectStructure,负责存储了不同类型的元素对象,以供不同访问者访问。

代码示例

  顾客在超市中将选购商品,如肉、图书等放在购物车中,然后到收银员处付款。在购物过程中,顾客需要对这些商品进行访问,以便确认这些商品的质量,之后收银员计算价格时也需要访问购物车的商品。此时,购物车作为一个ObjectStructure(对象结构)用于存储各种类型的商品,而顾客和收银员作为访问这些商品的访问者。不同类型的商品其访问形式也可能不同,如肉需要过秤之后再计价,而图书不需要。使用访问者模式来设计该购物过程。

//抽象元素类-商品
public interface Goods {
    public void accept(Visitor visitor);
}
//具体元素类-图书
public class Book implements Goods{
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}
//具体元素类-肉
public class Meat implements Goods{
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}
//抽象访问者
public abstract class Visitor {
    public abstract void visit(Book book);
    public abstract void visit(Meat meat);
}
//具体访问者-售货员
public class Saler extends Visitor{
    @Override
    public void visit(Book book) {
        System.out.println("售货员扫码,查看书的价格");
    }
    @Override
    public void visit(Meat meat) {
        System.out.println("售货员称重,查看肉的价格");
    }
}
//具体访问者-消费者
public class Customer extends Visitor{
    @Override
    public void visit(Book book) {
        System.out.println("消费者查看书的内容,看是否精彩");
    }
    @Override
    public void visit(Meat meat) {
        System.out.println("消费者查看肉的肥瘦、新鲜程度等");
    }

}
//对象结构-购物车
import java.util.ArrayList;
import java.util.List;
public class ShoppingCart {
    private List<Goods> goodsList = new ArrayList<Goods>();
    public void addGoods(Goods goods){
        goodsList.add(goods);
    }
    public void remove(Goods goods){
        goodsList.remove(goods);
    }
    public void accept(Visitor visitor){
        for(Goods goods:goodsList){
            goods.accept(visitor);
        }
    }
}
//客户端测试
public class Client {
    public static void main(String[] args) {
        Goods book = new Book();
        Goods meat = new Meat();
        ShoppingCart shoppingCart = new ShoppingCart();
        shoppingCart.addGoods(book);
        shoppingCart.addGoods(meat);
        Visitor saler = new Saler();
        Visitor customer = new Customer();
        shoppingCart.accept(saler);
        shoppingCart.accept(customer);
    }
}

  控制台输出

售货员扫码,查看书的价格
售货员称重,查看肉的价格
消费者查看书的内容,看是否精彩
消费者查看肉的肥瘦、新鲜程度等

总结

  在访问者模式中,相同的访问者可以以不同的方式访问不同的元素,相同的元素可以接受不同访问者以不同访问方式访问。在访问者模式中,增加新的访问者无须修改原有系统,系统具有较好的可扩展性。但增加一个新的元素类都需要要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”。
  访问者模式包含五个角色:抽象访问者为对象结构类中每一个抽象元素类声明一个访问操作;具体访问者实现了每个由抽象访问者声明的操作,每一个操作用于访问对象结构中一种类型的元素;抽象元素一般是抽象类或者接口,它定义一个accept()方法,该方法以一个抽象访问者作为参数;具体元素实现了accept()方法,在其accept()中调用访问者的访问方法以便完成对一个元素的操作;对象结构是一个元素的集合,它用于存放元素对象,并且提供了遍历其内部元素的方法。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值