设计模式——访问者模式


作者:云都小生


概述



在某个药业公司中,工作流程一般是这样。开单人员根据客户人员,写出一张订单,这张订单会先发到仓库人员的手中。

仓库的人员根据订单的信息,准备好对应的产品,然后把订单给到负责财务的人员。

财务人员根据订单的信息,检点产品数量是否到位、是否超出。最后根据订单信息计算出总金额,对数据库进行相应的操作···

上面这个案例是我想的,只是为了用来引出访问者模式的概念,如果有什么不对的地方,欢迎指正,我会更改。

通过上面这个例子,我们知道,订单是一个复杂的对象。而开单人员、仓库人员、财务人员对这张订单的操作并不一样。这就是我们软件开发中,经常会碰到的一种场景——不同对象对复杂对象的操作方式不一样。

访问者模式相当于,在一个工厂里面,不同工作人员对同一产品的不同操作。


不明智的设计示范


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:云都小生

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值