设计模式-行为模式-访问者模式

335 阅读2分钟

设计模式

设计模式分为创建型模式、结构型模式和行为型模式。
创建型模式:创建对象。
结构型模式:把复杂结构分解为多个类,分解的是类本身(包括算法和属性)。
行为型模式:把复杂算法分解到多个类,分解的是算法。

行为模式-访问者模式

访问者模式是为了在不改变原有类结构的情况下增加一种算法,这种算法将在类外实现,并且将类对象传递给算法。

UML 图

访问者模式的 UML 图.png

关键在 Element 接口,声明了一个方法来接收访问者。访问者将具体的 Element 传递给算法。

示例代码

public interface Element {
    void accept(Visitor visitor);
}

public class ConcreteElementA implements Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

public class ConcreteElementB implements Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

public interface Visitor {
    void visit(ConcreteElementA elementA);
    void visit(ConcreteElementB elementB);
}

public class ConcreteVisitor implements Visitor {
    @Override
    public void visit(ConcreteElementA elementA) {
        System.out.println("ConcreteVisitor visit ConcreteElementA");
    }

    @Override
    public void visit(ConcreteElementB elementB) {
        System.out.println("ConcreteVisitor visit ConcreteElementB");
    }
}

public class Client {
    public static void main(String[] args) {
        Element elementA = new ConcreteElementA();
        Element elementB = new ConcreteElementB();
        Visitor visitor = new ConcreteVisitor();
        elementA.accept(visitor);
        elementB.accept(visitor);
    }
}

输出:

ConcreteVisitor visit ConcreteElementA
ConcreteVisitor visit ConcreteElementB

为什么不能重载替代访问者模式

使用重载会遇到一个问题:子类的类型会被擦除。

示例代码:

interface Graphic{
    void draw();
}

class Shape implements Graphic{
    @Override
    public void draw() {
        System.out.println("Shape");
    }
}

class Dot extends Shape{
    @Override
    public void draw() {
        System.out.println("Dot");
    }
}

class Circle extends Dot{
    @Override
    public void draw() {
        System.out.println("Circle");
    }
}

class Exporter{
    public void export(Shape shape){
        System.out.println("export shape");
    }

    public void export(Dot dot){
        System.out.println("export dot");
    }

    public void export(Circle circle){
        System.out.println("export circle");
    }
}

public class Client {
    public static void main(String[] args) {
        Shape shape = new Circle();
        Exporter exporter = new Exporter();
        exporter.export(shape);
    }
}

上面的代码运行后输出:

export shape

Shape 有多个子类,每个子类都重写了 draw 方法,但是在运行时,调用的是 Shape 的 draw 方法,而不是 Circle 的 draw 方法。这是因为 Java 中的重载是静态绑定的(编译时),而不是动态绑定的(编译后的运行时)。

而访问者模式的实现 visitor.visit(this) 中 this 的类型在编译时就确定了。