概念
访问者模式是一种行为设计模式,允许在不修改已有代码的情况下,动态地添加新的操作到对象结构中。它将数据结构与操作解耦,使得可以独立地定义作用于复杂对象结构的操作。
作用
访问者模式的主要作用是解决在一个对象结构上定义多个操作的问题,特别是这些操作需要频繁改变时。它使得可以在不修改对象结构的前提下,方便地添加新的操作,符合单一职责原则和开闭原则。
使用场景
1.一个对象结构包含很多类对象,它们有不同的接口,而想对这些对象实施一些依赖于其具体类的操作。
2.需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免这些操作“污染”这些对象的类。
3.对象结构中的对象类型很少改变,但经常需要在此对象结构上定义新的操作。
实现
访问者模式的实现通常包括以下几个部分:
1.Visitor(访问者接口):声明了访问者可以访问哪些元素,通过为每种元素类声明一个访问操作(visit())来实现。
2.ConcreteVisitor(具体访问者):实现了Visitor接口中的访问操作,定义了对元素的具体访问行为。
3.Element(元素接口):声明了一个accept()方法,用于接受访问者访问。
4.ConcreteElement(具体元素):实现了Element接口中的accept()方法,通常会调用访问者的相应访问方法。
5.ObjectStructure(对象结构):是一个包含元素的容器,提供了遍历元素的方法,让访问者可以访问所有元素。
示例
1.访问者接口
// 访问者接口
interface ComputerPartVisitor {
void visit(Mouse mouse);
void visit(Keyboard keyboard);
void visit(Display display);
void visit(Computer computer);
}
2.具体访问者-清洁访问者
// 具体访问者 - 清洁访问者
class CleanVisitor implements ComputerPartVisitor {
@Override
public void visit(Mouse mouse) {
System.out.println("清洁鼠标");
}
@Override
public void visit(Keyboard keyboard) {
System.out.println("清洁键盘");
}
@Override
public void visit(Display display) {
System.out.println("清洁显示器");
}
@Override
public void visit(Computer computer) {
System.out.println("清洁电脑");
}
}
3.具体访问者-升级访问者
// 具体访问者 - 升级访问者
class UpgradeVisitor implements ComputerPartVisitor {
@Override
public void visit(Mouse mouse) {
System.out.println("升级鼠标驱动");
}
@Override
public void visit(Keyboard keyboard) {
System.out.println("升级键盘驱动");
}
@Override
public void visit(Display display) {
System.out.println("升级显示器驱动");
}
@Override
public void visit(Computer computer) {
System.out.println("升级电脑系统");
}
}
4.元素接口
// 元素接口
interface ComputerPart {
void accept(ComputerPartVisitor visitor);
}
5.具体元素
// 具体元素 - 鼠标
class Mouse implements ComputerPart {
@Override
public void accept(ComputerPartVisitor visitor) {
visitor.visit(this);
}
}
// 具体元素 - 键盘
class Keyboard implements ComputerPart {
@Override
public void accept(ComputerPartVisitor visitor) {
visitor.visit(this);
}
}
// 具体元素 - 显示器
class Monitor implements ComputerPart {
@Override
public void accept(ComputerPartVisitor visitor) {
visitor.visit(this);
}
}
// 具体元素 - 电脑
class Computer implements ComputerPart {
private List<ComputerPart> parts;
public Computer() {
parts = new ArrayList<>();
parts.add(new Mouse());
parts.add(new Keyboard());
parts.add(new Monitor());
}
@Override
public void accept(ComputerPartVisitor visitor) {
for (ComputerPart part : parts) {
part.accept(visitor);
}
visitor.visit(this);
}
}
6.测试类
// 使用示例
public class VisitorPatternDemo {
public static void main(String[] args) {
Computer computer = new Computer();
ComputerPartVisitor cleanVisitor = new CleanVisitor();
computer.accept(cleanVisitor);
ComputerPartVisitor upgradeVisitor = new UpgradeVisitor();
computer.accept(upgradeVisitor);
}
}
优缺点
优点
1.单一职责原则:将相关的行为集中在一个访问者类中,而不是分散在许多被访问的类中。
2.开闭原则:在不修改已有代码的情况下,可以方便地添加新的访问者类,从而定义新的操作。
3.复用性:访问者可以复用元素类中的方法,而不需要重新实现这些方法。
缺点
1.类的依赖性:访问者和元素之间存在强依赖关系,如果元素类的接口发生改变,那么访问者类也需要相应地进行修改。
2.破坏封装性:访问者模式要求元素类暴露其内部细节,这可能会破坏元素类的封装性。
3.适用性有限:如果对象结构中的元素类型经常变化,那么使用访问者模式会增加系统的维护成本。
不使用访问者模式的实现
如果不使用访问者模式,可以通过在元素类中直接添加操作方法来实现类似的效果。例如,在上面的例子中,可以在Mouse、Keyboard、Monitor和Computer类中分别添加清洁和升级的方法。但是,这种方式会导致每个元素类都包含大量的操作方法,违反了单一职责原则,并且在需要添加新的操作时,需要修改所有元素类的代码,不符合开闭原则。
1.具体元素
// 鼠标
class Mouse {
public void clean() {
System.out.println("清洁鼠标");
}
public void upgrade() {
System.out.println("升级鼠标驱动");
}
}
// 键盘
class Keyboard {
public void clean() {
System.out.println("清洁键盘");
}
public void upgrade() {
System.out.println("升级键盘驱动");
}
}
// 显示器
class Monitor {
public void clean() {
System.out.println("清洁显示器");
}
public void upgrade() {
System.out.println("升级显示器驱动");
}
}
class Computer {
private List<ComputerPart> parts;
public Computer() {
parts = new ArrayList<>();
parts.add(new Mouse());
parts.add(new Keyboard());
parts.add(new Monitor());
}
public void clean() {
System.out.println("清洁电脑");
for (ComputerPart part : parts) {
part.clean();
}
}
public void upgrade() {
System.out.println("升级电脑系统");
for (ComputerPart part : parts) {
part.upgrade();
}
}
}
2.测试类
// 使用示例
public class NoVisitorPatternDemo {
public static void main(String[] args) {
Computer computer = new Computer();
computer.check();
computer.clean();
computer.upgrade();
}
}