作者:云都小生
概述
在某个药业公司中,工作流程一般是这样。开单人员根据客户人员,写出一张订单,这张订单会先发到仓库人员的手中。
仓库的人员根据订单的信息,准备好对应的产品,然后把订单给到负责财务的人员。
财务人员根据订单的信息,检点产品数量是否到位、是否超出。最后根据订单信息计算出总金额,对数据库进行相应的操作···
上面这个案例是我想的,只是为了用来引出访问者模式的概念,如果有什么不对的地方,欢迎指正,我会更改。
通过上面这个例子,我们知道,订单是一个复杂的对象。而开单人员、仓库人员、财务人员对这张订单的操作并不一样。这就是我们软件开发中,经常会碰到的一种场景——不同对象对复杂对象的操作方式不一样。
访问者模式相当于,在一个工厂里面,不同工作人员对同一产品的不同操作。
不明智的设计示范
public class Order {
public void show()
{
System.out.println("这是一张订单");
}
}
public class Processor {
public Order order;
public void FillOrder(Order order)
{
this.order = order;
}
//处理
public void process(String position)
{
if(position.equalsIgnoreCase("财务人员"))
{
//财务人员处理订单
System.out.println("财务人员清点完毕后,计算总金额并填写到订单上");
}
else if(position.equalsIgnoreCase("仓库人员"))
{
//仓库人员处理订单
System.out.println("仓库人员备货后,在订单上划勾");
}
else if(position.equalsIgnoreCase("开单人员"))
{
//仓库人员处理订单
System.out.println("开单人员填充这张订单的需求部分");
}
}
}
上面这个设计方案,很明显就有问题。
一旦我想增加另外一个职位,对订单进行另一种操作,就需要修改原来的代码,违背了开闭原则。
并且,Processor的职责相当的多,违背了“单一职责原则”。
这样设计的修改、扩展难度比较大,我们结合这个场景,引出访问者模式。
角色分析
在访问者模式中,通常有抽象访问者、具体访问者、抽象元素、具体元素和对象结构。
抽象访问者:抽象访问者中,对每一个具体元素类都声明了一个访问的业务方法。
具体访问者:具体访问者继承了抽象访问者,实现了每个对具体元素的操作方法。
抽象元素:在抽象元素三种,定义了一个accept()方法,这个方法通常噫一个抽象访问者作为参数。
具体元素:实现了父类声明的accept方法,在这个方法中调用访问者的访问方法,实现对一个元素的操作。
对象结构:对象结构一个元素的集合,存放众多的元素对象,提供了遍历内部元素的方法。
案例
在某工厂中,有三类质检员,分别是A、B,他们对于产品A,B的处理方式都不一样,这个时候我们需要通过访问者模式,来模拟这个处理的过程。
//抽象产品类
public abstract class Product {
public static int serialNum = 0;
public abstract void accept(Processor p);
}
//具体产品类:A
public class ProductA extends Product{
int productNum;
ProductA()
{
this.productNum = ++serialNum;
}
public void accept(Processor p)
{
p.process(this);
}
}
//具体产品类:B
public class ProductB extends Product{
int productNum;
ProductB()
{
this.productNum = ++serialNum;
}
public void accept(Processor p)
{
p.process(this);
}
}
//抽象处理者
public abstract class Processor {
public abstract void process(ProductA pa);
public abstract void process(ProductB pb);
}
//具体处理者:A
public class ProcessorA extends Processor{
public void process(ProductA pa)
{
System.out.println("质检员A处理了产品A\t产品编号:" + pa.productNum);
}
public void process(ProductB pb)
{
System.out.println("质检员A处理了产品B\t产品编号:"+ pb.productNum);
}
}
//具体处理者:B
public class ProcessorB extends Processor{
public void process(ProductA pa)
{
System.out.println("质检员B处理了产品A\t产品编号:" + pa.productNum);
}
public void process(ProductB pb)
{
System.out.println("质检员B处理了产品B\t产品编号:" + pb.productNum);
}
}
//对象结构
import java.util.ArrayList;
public class ProductList {
private ArrayList<Product> list = new ArrayList<Product>();
public void addProduct(Product product)
{
list.add(product);
}
public void accept(Processor processor)
{
for(Object obj : list)
{
((Product)obj).accept(processor);
}
}
}
//测试类
public class Test {
public static void main(String[] args) {
ProductList list = new ProductList();
Product p1,p2,p3,p4;
p1 = new ProductA();
p2 = new ProductA();
p3 = new ProductB();
p4 = new ProductB();
list.addProduct(p1);
list.addProduct(p2);
list.addProduct(p3);
list.addProduct(p4);
list.accept(new ProcessorA());
}
}
这样如果我们想增加一个新的质检员C就变得很容易了。但是,如果我们想增加一个新的产品,就有点难度了。
案例
访问者模式的结构较为复杂,在实际应用中使用频率不是特别高。而且,想使用访问者模式,需要考虑的问题比上面的案例多得多。
访问者模式的优势在于,它为不同访问者处理同一对象的不同方式,提供了一个良好的框架。在这个框架里面,能够在不修改源代码的情况下,去增加访问者。
在访问者模式中,有关的元素都会存放在对象结构类中,这样分开了职责,降低了复杂度。
缺点在于,如果想增加新的元素,就需要修改抽象访问者和各个具体访问者,违背了“开闭原则”。
2018/4/18 22:10:38 @Author:云都小生