设计模式系列:搞懂访问者模式,数据结构与数据操作分离

访问者模式是一种行为设计模式,它允许在不修改对象结构的情况下,为对象结构中的元素添加新的操作。模式的核心是解耦数据结构和操作,通过访问者角色实现元素的多种访问方式。在商场购物的场景中,顾客和收银员作为访问者,对商品有不同的关注点,体现了访问者模式的灵活性和扩展性。然而,该模式可能破坏对象的封装性和违反依赖倒置原则,增加新元素类时会遇到困难。适用于对象结构稳定但操作频繁变化的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

访问者模式的定义:将数据结构和对数据结构中元素的操作分离,并把对数据结构中元素的操作封装,使其在不改变数据结构的前提下可以添加新的操作,为数据结构中的每个元素提供多种访问方式。属于行为型模式。

访问者模式的核心是解耦数据结构和数据操作,使得对元素的操作更容易扩展。

访问者模式的结构:访问者模式主要包含以下5个角色。

  1. 抽象访问者(Visitor):定义一个访问具体元素的接口,为每个具体元素类对应一个访问操作 visit() ,该操作中的参数就是具体元素对象。
  2. 具体访问者(ConcreteVisitor):实现抽象访问者中的方法,实现元素的具体操作。
  3. 抽象元素(Element):定义一个包含接受操作 accept() 的接口或抽象类,被接受的访问者对象作为 accept() 方法的参数。
  4. 具体元素(ConcreteElement)角色:实现抽象元素提供的 accept() 操作,其方法体通常都是 visitor.visit(this)。
  5. 对象结构(Object Structure):包含元素的容器,提供让访问者对象遍历容器中的所有元素的方法。

访问者模式的通用实现:

//抽象元素
public interface IElement {
    void accept(IVisitor visitor);
}

//具体元素
public class ConcreteElementA implements IElement{
    @Override
    public void accept(IVisitor visitor) {
        visitor.visit(this);
    }

    public String operationA() {
        return "对元素A一顿操作!";
    }
}

//具体元素
public class ConcreteElementB implements IElement{
    @Override
    public void accept(IVisitor visitor) {
        visitor.visit(this);
    }

    public String operationB() {
        return "对元素B一顿操作!";
    }
}

//对象结构
public class ObjectStructure {
    private List<IElement> list = new ArrayList<>();

    public void accept(IVisitor visitor) {
        Iterator<IElement> iterator = list.iterator();
        while (iterator.hasNext()) {
            iterator.next().accept(visitor);
        }
    }

    public void add(IElement element) {
        list.add(element);
    }
    public void remove(IElement element) {
        list.remove(element);
    }
}

//抽象访问者
public interface IVisitor {
    void visit(ConcreteElementA element);

    void visit(ConcreteElementB element);
}

//具体访问者
public class ConcreteVisitorA implements IVisitor {
    @Override
    public void visit(ConcreteElementA concreteElementA) {
        System.out.println("具体访问者A访问-->" + concreteElementA.operationA());
    }

    @Override
    public void visit(ConcreteElementB concreteElementB) {
        System.out.println("具体访问者A访问-->" + concreteElementB.operationB());
    }
}

//具体访问者
public class ConcreteVisitorB implements IVisitor {
    @Override
    public void visit(ConcreteElementA concreteElementA) {
        System.out.println("具体访问者B访问-->" + concreteElementA.operationA());
    }

    @Override
    public void visit(ConcreteElementB concreteElementB) {
        System.out.println("具体访问者B访问-->" + concreteElementB.operationB());
    }
}

//测试类
public class VisitorTest {
    public static void main(String[] args) {
        ObjectStructure os = new ObjectStructure();
        os.add(new ConcreteElementA());
        os.add(new ConcreteElementB());
        IVisitor visitor = new ConcreteVisitorA();
        os.accept(visitor);
        System.out.println("========================================");
        visitor = new ConcreteVisitorB();
        os.accept(visitor);
    }
}

访问者模式的结构图:

访问者模式的应用实例:顾客在商场购物时将选购的商品放在“购物车”中,顾客主要关心所选商品的性价比,而收银员关心的是商品的价格和数量。我们用访问者模式来模拟一下这个场景。

//抽象商品
public abstract class Goods {
    private String name;

    private Double price;

    private Double amount;

    public Goods(String name,Double price,Double amount){
        this.name = name;
        this.price = price;
        this.amount = amount;
    }

    public String getName() {
        return name;
    }

    public Double getPrice() {
        return price;
    }

    public Double getAmount() {
        return amount;
    }

    public abstract void accept(IVisitor visitor);
}

//具体商品
public class Apple extends Goods{
    public Apple(String name, Double price, Double amount) {
        super(name, price, amount);
    }

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

    public String getCost(){
        return "好吃不贵,易于保存。";
    }
}

//具体商品
public class Banana extends Goods{
    public Banana(String name, Double price, Double amount) {
        super(name, price, amount);
    }

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

    public String getCost(){
        return "好吃,不易保存。";
    }
}

//访问者接口
public interface IVisitor {
    void visit(Apple apple);

    void visit(Banana banana);
}

//顾客(访问者)
public class Customer implements IVisitor{
    @Override
    public void visit(Apple apple) {
        System.out.println("苹果:单价是"+apple.getPrice()+",特点是"+apple.getCost());
    }

    @Override
    public void visit(Banana banana) {
        System.out.println("香蕉:单价是"+banana.getPrice()+",特点是"+banana.getCost());
    }
}

//商家(访问者)
public class Saler implements IVisitor{
    @Override
    public void visit(Apple apple) {
        System.out.println("苹果:单价是"+apple.getPrice()+",数量是"+apple.getAmount());
    }

    @Override
    public void visit(Banana banana) {
        System.out.println("香蕉:单价是"+banana.getPrice()+",数量是"+banana.getAmount());
    }
}

//购物车
public class ShoppingCart {
    static List<Goods> goods = new ArrayList<>();

    static {
        goods.add(new Apple("红富士苹果",4.00,3.00));
        goods.add(new Apple("花牛苹果",6.00,2.00));
        goods.add(new Apple("国产香蕉",5.00,2.00));
        goods.add(new Apple("进口香蕉",8.00,2.00));
    }

    public void showGoods(IVisitor visitor){
        for (Goods good : goods) {
            good.accept(visitor);
        }
    }
}

//测试类
public class Test {
    public static void main(String[] args) {
        ShoppingCart shoppingCart = new ShoppingCart();
        System.out.println("==============顾客看商品================");
        shoppingCart.showGoods(new Customer());
        System.out.println("==============商家看商品================");
        shoppingCart.showGoods(new Saler());
    }
}

访问者模式的优点:

  1. 扩展性好。能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。
  2. 复用性好。可以通过访问者来定义整个对象结构通用的功能,从而提高系统的复用程度。
  3. 灵活性好。访问者模式将数据结构与数据操作解耦,使得操作集合可相对自由地变化。
  4. 符合单一职责原则。访问者模式把相关的行为封装在一起,每一个访问者的功能都比较单一。

访问者模式的缺点:

  1. 破坏封装。访问者模式中具体元素对访问者公布细节,这破坏了对象的封装性。
  2. 违反了依赖倒置原则。访问者模式依赖了具体类,而没有依赖抽象类。
  3. 增加新的元素类很困难。在访问者模式中,每增加一个新的元素类,都要在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”。

访问者模式的应用场景:

  1. 对象结构相对稳定,但其操作算法经常变化的场景。
  2. 数据对象与数据操作分离的场景。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风雨编码路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值