1、模式的定义与特点
访问者(Visitor)模式:将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式。
它将对数据的操作与数据结构进行分离,是行为型模式中最复杂的一种模式。
访问者模式是一种对象行为型模式,其优点:
1、扩展性好。
能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。
2、复用性好。
可以通过访问者来定义整个对象结构通用的功能,从而提高系统的复用程度。
3、灵活性好。
访问者模式将数据结构与作用于结构上的操作解耦,使得操作集合可相对自由地演化而不影响系统的数据结构。
4、符合单一职责原则。
访问者模式把相关的行为封装在一起,构成一个访问者,使每一个访问者的功能都比较单一。
缺点:
1、增加新的元素类很困难。
在访问者模式中,每增加一个新的元素类,都要在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”。
2、破坏封装。
访问者模式中具体元素对访问者公布细节,这破坏了对象的封装性。
3、违反了依赖倒置原则。
访问者模式依赖了具体类,而没有依赖抽象类。
2、模式的结构
访问者模式实现的关键是如何将作用于元素的操作分离出来封装成独立的类。
主要角色:
1、抽象访问者(Visitor)角色:定义一个访问具体元素的接口,为每个具体元素类对应一个访问操作visit() ,该操作中的参数类型标识了被访问的具体元素。
2、具体访问者(ConcreteVisitor)角色:实现抽象访问者角色中声明的各个访问操作,确定访问者访问一个元素时该做什么。
3、抽象元素(Element)角色:声明一个包含接受操作accept()的接口,被接受的访问者对象作为accept()方法的参数。
4、具体元素(ConcreteElement)角色:实现抽象元素角色提供的accept()操作,其方法体通常都是visitor.visit(this) ,另外具体元素中可能还包含本身业务逻辑的相关操作。
5、对象结构(Object Structure)角色:是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由List、Set、Map等聚合类实现。
3、模式的应用场景
1、对象结构相对稳定,但其操作算法经常变化的程序。
2、对象结构中的对象需要提供多种不同且不相关的操作,而且要避免让这些操作的变化影响对象的结构。
3、对象结构包含很多类型的对象,希望对这些对象实施一些依赖于其具体类型的操作。
4、模式的扩展
访问者模式是使用频率较高的一种设计模式,它常常同以下两种设计模式联用。
1、与迭代器模式联用
因为访问者模式中的“对象结构”是一个包含元素角色的容器,当访问者遍历容器中的所有元素时,常常要用迭代器。
如果对象结构中的聚合类没有提供迭代器,也可以用迭代器模式自定义一个。
2、同组合模式联用
因为访问者模式中的“元素对象”可能是叶子对象或者是容器对象,如果元素对象包含容器对象,就必须用到组合模式,其结构图如图2所示。
5、模式的实现
抽象访问者角色:
package com.example.designpattern.visitor;
/**
* 抽象访问者角色
*
* @author Administrator
* @date 2020/8/6
*/
interface IVisitor {
public void visit(Man man);
public void visit(Woman woman);
}
抽象元素角色:
package com.example.designpattern.visitor;
/**
* 抽象元素角色
*
* @author Administrator
* @date 2020/8/6
*/
interface IPerson {
public void accept(IVisitor v);
}
对象结构角色:
package com.example.designpattern.visitor;
import java.util.ArrayList;
/**
* 对象结构角色
*
* @author Administrator
* @date 2020/8/6
*/
class PersonStructure {
private ArrayList<IPerson> list = new ArrayList<>();
public void attach(IPerson p) {
list.add(p);
}
public void detach(IPerson p) {
list.remove(p);
}
public void acceptVisitor(IVisitor v) {
for (IPerson p : list) {
p.accept(v);
}
}
}
具体元素角色1:
package com.example.designpattern.visitor;
/**
* 具体元素角色
*
* @author Administrator
* @date 2020/8/6
*/
class Man implements IPerson {
@Override
public void accept(IVisitor v) {
v.visit(this);
}
}
具体元素角色2:
package com.example.designpattern.visitor;
/**
* 具体元素角色
*
* @author Administrator
* @date 2020/8/6
*/
class Woman implements IPerson {
@Override
public void accept(IVisitor v) {
v.visit(this);
}
}
具体访问者角色1:
package com.example.designpattern.visitor;
/**
* 具体访问者角色
*
* @author Administrator
* @date 2020/8/6
*/
class Success implements IVisitor {
@Override
public void visit(Man man) {
System.out.println("男人成功时,喝酒庆祝");
}
@Override
public void visit(Woman woman) {
System.out.println("女人成功时,疯狂Shopping");
}
}
具体访问者角色2:
package com.example.designpattern.visitor;
/**
* 具体访问者角色
*
* @author Administrator
* @date 2020/8/6
*/
class Fail implements IVisitor {
@Override
public void visit(Man man) {
System.out.println("男人失败时,喝酒解闷");
}
@Override
public void visit(Woman woman) {
System.out.println("女人失败时,疯狂Shopping");
}
}
具体访问者角色3:
package com.example.designpattern.visitor;
/**
* 具体访问者角色
*
* @author Administrator
* @date 2020/8/6
*/
class Love implements IVisitor {
@Override
public void visit(Man man) {
System.out.println("男人恋爱时,假装什么都懂");
}
@Override
public void visit(Woman woman) {
System.out.println("女人恋爱时,假装什么都不懂");
}
}
调用:
package com.example.designpattern.visitor;
/**
* @author Administrator
* @date 2020/8/6
*/
class Client {
public static void main(String[] args) {
// 创建一个对象结构
PersonStructure ps = new PersonStructure();
// 创建不同的元素
Man man = new Man();
Woman woman = new Woman();
ps.attach(man);
ps.attach(woman);
//访问者
IVisitor success = new Success();
ps.acceptVisitor(success);
System.out.println();
IVisitor fail = new Fail();
ps.acceptVisitor(fail);
System.out.println();
IVisitor love = new Love();
ps.acceptVisitor(love);
}
}
测试结果:
6、PPT素材
微信公众号: TechU