begin 2023年04月02日15:56:19

引子

定义

表示在对象结构的元素上执行的操作。访问者模式(Visitor)允许您定义一种新操作,而无需更改它所作用的元素的类。——《设计模式:可复用面向对象软件的基础》

访问者模式是一种行为型设计模式。

使用场景

  • 对象机构包含了许多具有不同接口的对象类,您希望对这些对象执行依赖于其具体类的操作。
  • 需要对对象结构中的对象执行许多不同且不相关的操作,并且您希望避免这些操作“污染”它们的类。Visitor允许将相关操作定义在一个类中,从而将它们放在一起。当对象结构被许多应用程序共享时,使用Visitor将操作放在需要它们的应用程序中。
  • 定义对象结构的类很少改变,但是您经常希望在类上定义新的操作。更改对象结构类需要为所有访问者重新定义接口,这可能成本很高。如果对象结构类经常变化,那么最好在这些类中定义操作。

图示

访问者模式结构图:

访问者模式-LMLPHP

角色

抽象访问者角色(Visitor):

  • 为对象结构中的每个 ConcreteElement 类声明一个 visit 操作。
  • 操作的名称和签名(visitConcreteElementA、visitConcreteElementB)标识向访问者(ConcreteVisitorA、ConcreteVisitor)发送 visit 请求的类,让访问者可以确定所访问元素的具体类(ConcreteElementA、ConcreteElementB)。
  • 然后访问者可以通过元素特定的接口直接访问该元素。

具体访问者角色(ConcreteVisitorA、ConcreteVisitorB):

  • 实现访问者声明的每个操作。
  • 每个操作实现为对象结构中对应的对象类定义的算法片段(针对具体元素所执行的操作,如获取ConcreteElementA的名字等)
  • ConcreteVisitor 为算法提供了上下文,并存储其本地状态。该状态通常在遍历对象结构时积累结果。

对象结构角色(ObjectStructure):

  • 可以枚举其元素。
  • 可以提供一个高层接口,以允许访问者访问其元素。
  • 可以是一个组合(参见组合模式)或者一个集合,如列表或集合

抽象元素角色(Element):

  • 定义一个接受访问者作为参数的 Accept 操作。

具体元素角色(ConcreteElementA、ConcreteElementB):

  • 实现一个接受访问者作为参数的 Accept 操作。

代码示例

生命主要分为过去、现在、未来,乐观者看到不念过去,不畏将来,立足现在努力,悲观者看到悔恨过去,迷茫未来,或不知所措的现在,同样的生命不同的人看到不同的世界。

代码示例类图:
访问者模式-LMLPHP

代码示例:

抽象访问者角色:

// 人类
public interface Man {
    void visitPast(Past past);
    void visitPresent(Present present);
    void visitFuture(Future future);
}

具体访问者角色:

// 乐观主义者
public class Optimist implements Man {
    @Override
    public void visitPast(Past past) {
        System.out.println("不念" + past.getName());
    }

    @Override
    public void visitPresent(Present present) {
        System.out.println("享受" + present.getName());
    }

    @Override
    public void visitFuture(Future future) {
        System.out.println("不畏" + future.getName());
    }
}
// 悲观主义者
public class Pessimist implements Man {
    @Override
    public void visitPast(Past past) {
        System.out.println("悔恨" + past.getName());
    }

    @Override
    public void visitPresent(Present present) {
        System.out.println("焦虑" + present.getName());
    }

    @Override
    public void visitFuture(Future future) {
        System.out.println("迷茫" + future.getName());
    }
}

对象结构角色:

// 生命
public class Life {
    private List<Time> timeList = new ArrayList<>();

    public Life() {
        timeList.add(new Past());
        timeList.add(new Present());
        timeList.add(new Future());
    }

    public void visitTime(Man man) {
        for (Time time : timeList) {
            if (time instanceof Past) {
                man.visitPast((Past) time);
            } else if (time instanceof Present) {
                man.visitPresent((Present) time);
            } else if (time instanceof Future) {
                man.visitFuture((Future) time);
            }
        }
    }
}

抽象元素角色:

// 时间
public interface Time {
    void accept(Man man);
    String getName();
}

具体元素角色:

// 过去
public class Past implements Time {

    private String name = "过去";

    @Override
    public void accept(Man man) {
        man.visitPast(this);
    }

    public String getName() {
        return name;
    }
}
// 现在
public class Present implements Time {

    private String name = "现在";

    @Override
    public void accept(Man man) {
        man.visitPresent(this);
    }
    public String getName() {
        return name;
    }
}
// 未来
public class Future implements Time {

    private String name = "未来";

    @Override
    public void accept(Man man) {
        man.visitFuture(this);
    }

    public String getName() {
        return name;
    }
}

客户端:


public class Client {
    public static void main(String[] args) {
        Optimist optimist = new Optimist();
        Pessimist pessimist = new Pessimist();

        Life life = new Life();
        System.out.println("乐观者:");
        life.visitTime(optimist);
        System.out.println("悲观者:");
        life.visitTime(pessimist);
    }
}

结果:

乐观者:
不念过去
享受现在
不畏未来
悲观者:
悔恨过去
焦虑现在
迷茫未来

优点

  • 操作和结构分开,易于新增操作

缺点

  • 修改结构需要修改所有操作类,成本极大

总结

访问者莫斯允许您定义一种新操作,而无需更改它所作用的元素的类。访问者模式适用于结构固定,但是操作不固定的对象,它把对象结构和作用于结构的操作耦合解开,方便增加新的操作。

end 2023年04月05日15:22:07

04-06 01:17