访问者模式实现

访问者模式实现步骤

  1. 理清元素信息,定义一个抽象的元素类,里面包含了一个方法,用来接收访问者。
  2. 定义真实的抽象元素的实现类,实现自己的特有方法。
  3. 定义一个抽象的访问者类。
  4. 定义具体的访问者类,里面包含了对被访问元素的方法的调用,对元素对象的访问,只能够通过这个访问者。

案例

我们用商品计算价格来举例,我们先建 net.haicoder.visitor 包。先建抽象元素接口 Goods.java ,再定义具体实现类 Cigarette.javaPig.java Wine.java

建立抽象的访问者类 Visitor.java ,具体访问者实现类 VisitorImpl.java ,购物车类 ShoppingCart.java 和测试类 TestMain.java 。文件创建完毕,具体目录结构如下:

26 访问者模式代码结构图.png

Goods.java 代码如下:

package net.haicoder.visitor; /** * 抽象元素 */ public interface Goods { double accept(Visitor visitor); }

Cigarette.java 代码如下:

package net.haicoder.visitor; public class Cigarette implements Goods { @Override public double accept(Visitor visitor) { return visitor.visit(this); } public double accountByPack() { System.out.println("烟按包计价,购买的数量为:" + getCount() + "瓶,购买的单价为:" + getPrice() + ",总价为:" + getCount() * getPrice()); return getCount() * getPrice(); } private int count; private float price; public int getCount() { return count; } public void setCount(int count) { this.count = count; } public float getPrice() { return price; } public void setPrice(float price) { this.price = price; } }

Pig.java 代码如下:

package net.haicoder.visitor; public class Pig implements Goods { private float price; private Float count; @Override public double accept(Visitor visitor) { return visitor.visit(this); } public double accountByUnit() { System.out.println("猪肉按斤计价,购买的数量为:" + getCount() + "斤,购买的单价为:" + getPrice() + ",总价为:" + getCount() * getPrice()); return getCount() * getPrice(); } public float getPrice() { return price; } public void setPrice(float price) { this.price = price; } public Float getCount() { return count; } public void setCount(Float count) { this.count = count; } }

Wine.java 代码如下:

package net.haicoder.visitor; public class Wine implements Goods { @Override public double accept(Visitor visitor) { return visitor.visit(this); } public double accountByBottle() { System.out.println("酒按瓶计价,购买的数量为:" + getCount() + "瓶,购买的单价为:" + getPrice() + ",总价为:" + getCount() * getPrice()); return getCount() * getPrice(); } private int count; private float price; public int getCount() { return count; } public void setCount(int count) { this.count = count; } public float getPrice() { return price; } public void setPrice(float price) { this.price = price; } }

Visitor.java 代码如下:

package net.haicoder.visitor; public interface Visitor { double visit(Wine wine); double visit(Pig pig); double visit(Cigarette cigarette); }

VisitorImpl.java 代码如下:

package net.haicoder.visitor; public class VisitorImpl implements Visitor { @Override public double visit(Wine wine) { return wine.accountByBottle(); } @Override public double visit(Pig pig) { return pig.accountByUnit(); } @Override public double visit(Cigarette cigarette) { return cigarette.accountByPack(); } }

ShoppingCart.java 代码如下:

package net.haicoder.visitor; import java.util.ArrayList; import java.util.List; public class ShoppingCart { private List list = new ArrayList<>(); public void add(Object object) { list.add(object); } public void remove(Object object) { list.remove(object); } public List getList() { return list; } }

TestMain.java 代码如下:

package net.haicoder.visitor; public class TestMain { public static void main(String[] args) { System.out.println("嗨客网(www.haicoder.net)"); Wine wine = new Wine(); wine.setCount(10); wine.setPrice(20f); Pig pig = new Pig(); pig.setCount(10f); pig.setPrice(35f); Cigarette cigarette = new Cigarette(); cigarette.setCount(1); cigarette.setPrice(20f); ShoppingCart shoppingCart = new ShoppingCart(); shoppingCart.add(wine); shoppingCart.add(pig); shoppingCart.add(cigarette); double amt = 0; Visitor visitor = new VisitorImpl(); for (int i = 0; i < shoppingCart.getList().size(); i++) { amt += ((Goods) shoppingCart.getList().get(i)).accept(visitor); } System.out.println("本次购物车内所有物品的总价为:" + amt); } }

代码运行结果如下图:

27 访问者模式执行结果.png

访问者模式总结

将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式。将数据结构和数据的操作相分离。