设计模式学习笔记十二:访问者模式

访问者模式是一种对象行为型设计模式,用于在不修改对象结构的情况下为对象的元素添加新的操作。适用场景为对象结构稳定但行为需要频繁变化的情况。文章通过客户回访的场景模拟展示了访问者模式的应用,对比了访问者模式与策略模式的区别,并指出访问者模式在结构不变时易于扩展行为,但结构变化会带来较大调整。
摘要由CSDN通过智能技术生成

设计模式学习笔记十二:访问者模式

介绍

访问者(visitor)模式,属于对象行为型模式,它实现了结构与行为的解耦。
意图:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。(本段摘自《GoF设计模式》 5.11)

适用场景

访问者模式适合对象的结构稳定,行为变动频繁的情况。反之,结构变动频繁的场景不适合使用次模式。在后面的实现中可以很容易的证实这一点,结构的变化会增加更多繁复的操作。在一个已经的接口中增加方法会导致在其所有的实现类中都进行一次实现实现,没人愿意这么做。

UML结构图:

可以先略过,回头再看。
Visitor

场景模拟

这里我以客户回访场景尝试解释访问者模式的应用:在公司Z中,会定期对他的客户进行回访。根据客户重要度的不同,人物、时间、地点也会不同。不管是否愿意承认,生活中到处充满着等级的划分不是么?
+ 普通客户:铜牌业务员A;时间:工作日;地点:电话连线。
+ 潜力优质客户:银牌业务员B;时间:沟通确定;地点:茶楼。
+ 优质客户:金牌业务员C;时间:沟通确定;地点:避暑山庄。

代码实现:

1.回访操作

package com.array7.visitor;

/**
 * 回访接口,即Element
 */
public interface IRevisit {
    void accpet(IWorkerVisitor visitor);
}

/**
 * 约定的业务员,即ConcreteElement
 */
public class Worker implements IRevisit {

    @Override
    public void accpet(IWorkerVisitor visitor) {
        visitor.visit(this);
    }
}

/**
 * 约定的回访时间,即ConcreteElement
 */
public class Time implements IRevisit {
    @Override
    public void accpet(IWorkerVisitor visitor) {
        visitor.visit(this);
    }
}

/**
 * 约定的地点,即ConcreteElement
 */
public class Place implements IRevisit {
    @Override
    public void accpet(IWorkerVisitor visitor) {
        visitor.visit(this);
    }
}

/**
 * 最终回访单,即ConcreteElement
 */
public class Revisit implements IRevisit {
    private IRevisit[] revisits;
    public Revisit(IRevisit... revisits) {
        this.revisits = revisits;
    }
    @Override
    public void accpet(IWorkerVisitor visitor) {
        for (IRevisit revisit : revisits) {
            revisit.accpet(visitor);
        }
        visitor.visit(this);
    }
}

2.访问者操作

package com.array7.visitor;

/**
 * 访问者接口,即Visitor
 */
public interface IWorkerVisitor {
    void visit(Worker worker);
    void visit(Time time);
    void visit(Place place);
    void visit(Revisit revisit);
}

/**
 * 金牌业务员访问者,即concreteVisitor
 */
public class CustomerAVisitor implements IWorkerVisitor {
    @Override
    public void visit(Worker worker) {
        System.out.println("安排金牌业务员A回访客户");
    }

    @Override
    public void visit(Time time) {
        System.out.println("安排金牌业务员A与客户约定时间:2015-07-26");
    }

    @Override
    public void visit(Place place) {
        System.out.println("安排金牌业务员A与客户约定地点:避暑山庄");
    }

    @Override
    public void visit(Revisit revisit) {
        System.out.println("金牌业务员A开始回访");;
    }
}

/**
 * 银牌业务员访问者,即concreteVisitor
 */
public class CustomerBVisitor implements IWorkerVisitor {
    @Override
    public void visit(Worker worker) {
        System.out.println("安排银牌业务员B回访客户");
    }

    @Override
    public void visit(Time time) {
        System.out.println("安排银牌业务员B与客户约定时间:2015-07-26");
    }

    @Override
    public void visit(Place place) {
        System.out.println("安排银牌业务员B与客户约定地点:茶楼");
    }

    @Override
    public void visit(Revisit revisit) {
        System.out.println("银牌业务员B开始回访");
    }
}

/**
 * 铜牌业务员访问者,即concreteVisitor
 */
public class CustomerCVisitor implements IWorkerVisitor {
    @Override
    public void visit(Worker worker) {
        System.out.println("安排铜牌业务员C回访客户");
    }

    @Override
    public void visit(Time time) {
        System.out.println("铜牌业务员C不需要与客户约定时间");
    }

    @Override
    public void visit(Place place) {
        System.out.println("铜牌业务员C不需要与客户约定地点");
    }

    @Override
    public void visit(Revisit revisit) {
        System.out.println("铜牌业务员C开始回访");
    }
}

3.Run

public class Run {
    public static void main(String[] args) {
        IRevisit revisitA = new Revisit(new Worker(), new Time(), new Place());
        revisitA.accpet(new CustomerAVisitor());
        System.out.println();
        IRevisit revisitB = new Revisit(new Worker(), new Time(), new Place());
        revisitB.accpet(new CustomerBVisitor());
        System.out.println();
        IRevisit revisitC = new Revisit(new Worker(), new Time(), new Place());
        revisitC.accpet(new CustomerCVisitor());
    }
}

输出

安排金牌业务员A回访客户
安排金牌业务员A与客户约定时间:2015-07-26
安排金牌业务员A与客户约定地点:避暑山庄
金牌业务员A开始回访

安排银牌业务员B回访客户
安排银牌业务员B与客户约定时间:2015-07-26
安排银牌业务员B与客户约定地点:茶楼
银牌业务员B开始回访

安排铜牌业务员C回访客户
铜牌业务员C不需要与客户约定时间
铜牌业务员C不需要与客户约定地点
铜牌业务员C开始回访

策略模式与访问者模式的区别

之前有讲过策略设计模式(http://blog.csdn.net/array7/article/details/43833921),仔细考虑发现本文中的场景适用策略模式也同样可以实现,并且会比适用访问者模式更加简单。下面来对两者进行一下比较:
+ 两者都属于对象行为型模式,同时都体现了对算法的封装,并且都可以在运行时动态指定算法。
+ 区别体现在策略模式只有一个上下文,策略模式的结构决定了Context只能传递一个策略进入。访问者模式则可以是在实现化Element结构之后,随时可以指定多个访问者。虽然在场景模拟中没有特意做区分,但是通过代码的实现的我们发现是可以很容易做到的。
+ 如果策略模式的算法部分不放在构造对象中传入,而使用accpet方法传入,那么这个策略模式就是一个访问者模式的实现了。So,策略模式也可以看成是访问者模式的一个特例。就像工厂方法模式是抽象工厂模式的一个特例一样。

总结

从上面的实现来看引证了适用场景中说的访问者模式适合对象的结构稳定,行为变动频繁的情况。反之,结构变动频繁的场景不适合使用次模式
+ 在结构不变的情况,增加行为即增加访问者是很容易的,只要新政一个访问者的实现即可。
+ 如果更改了结构(如Element的增删改),访问者接口要发生变动,同时所有访问者实现都要对应调整。

以上是我理解的访问者模式,了解优劣才知何时适用。
不准确之处还请指正,十分感谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值