光看访客这个名字,猜测这个访客模式应该非常好理解,只要玩过Linux的人,都能深刻明白Root和非Root和访客账号登录的巨大差别性。

What is Visitor?

如果你没玩过Linux,那么假设公共的图书馆有一台电脑,有两个账户:

  • 其中一个是管理员(Admin)的账户,拥有这个电脑的所有权限,但是设置了密码,必须是管理员(她有密码)才能登录;
  • 另一个账户是不需要密码,但是只能玩游戏和看电子书,拥有的权限有限。张三和李四先后使用了这台电脑,那么他们就可以当作是访问者(Visitor)

注意:
访客模式不是就是一种权限控制手段,访问者模式用于在不修改现有对象结构的情况下,定义对对象结构中各元素的新操作

访问者模式的主要目的是将数据结构与对其操作的行为解耦,使得操作可以独立变化而不影响数据结构的稳定性。它通过定义访问者对象,让访问者对象去访问数据结构中的元素,并执行相应的操作。

与访问者模式不同,权限控制是一种安全机制,用于限制对系统资源的访问权限。它确保只有经过授权的用户或角色能够执行特定的操作或访问特定的资源。权限控制通常涉及身份验证、授权策略、访问级别等概念,目的是保护系统的安全性和数据的完整性。

尽管访问者模式和权限控制都涉及到访问和操作的概念,但它们的目的和实现方式是不同的。访问者模式关注于对象结构的操作和扩展,而权限控制关注于系统资源的访问权限和安全性。

他的这个名字非常具有迷惑性,我觉得不应该叫他访问者模式,很容易就让人想到登录电脑那个访问者模式,想到是控制模式那边去,我觉得我得改个名字,就叫他主体不变却可以自由加入行为模式,好吧,确实有点长。

Key Elements

那么我们就可以根据这个例子来设计访问者模式,

  • 首先定义一个抽象的访问者,拥有玩游戏看电子书的方法;
  • 再定义一个抽象节点电脑,接受这个请求的方法;
  • 具体的访问者
  • 具体的节点电脑

假设电脑登录的案例,容易让人关注权限管控操作,让人混淆,所以我用另一个案例——动物的行为案例:

  • 动物接口 void accept(AnimalVisitor visitor);
  • 动物实现类 Dog、Cat、Pig
  • AnimalVisitor 接口
  • AnimalVisitor 实现 (动物们的所有操作,都需要通过AnimalVisitor实现来增加)
  • Client(Zoo)
    feedingVisitor = new FeedingVisitor();
    animal.dog.accept(feedingVisitor);

Example

下面是一个简单的Java示例,用于说明访问者模式的基本概念,假设我们有一个简单的动物园,里面有不同类型的动物(如狗、猫和鸟),我们需要对这些动物进行不同的操作(如喂食、散步等):

首先,我们定义一个动物接口(Animal):

public interface Animal {    void accept(AnimalVisitor visitor);}// 然后,我们定义不同类型的动物类,它们实现了动物接口:public class Dog implements Animal {    @Override    public void accept(AnimalVisitor visitor) {        visitor.visitDog(this);    }}public class Cat implements Animal {    @Override    public void accept(AnimalVisitor visitor) {        visitor.visitCat(this);    }}public class Bird implements Animal {    @Override    public void accept(AnimalVisitor visitor) {        visitor.visitBird(this);    }}

接下来,我们定义一个访问者接口(AnimalVisitor),用于定义不同的操作:

public interface AnimalVisitor {    void visitDog(Dog dog);    void visitCat(Cat cat);    void visitBird(Bird bird);}// 然后,我们实现访问者接口,定义具体的操作:public class FeedingVisitor implements AnimalVisitor {    @Override    public void visitDog(Dog dog) {        System.out.println("Feeding dog: Give it some dog food.");    }    @Override    public void visitCat(Cat cat) {        System.out.println("Feeding cat: Give it some cat food.");    }    @Override    public void visitBird(Bird bird) {        System.out.println("Feeding bird: Give it some bird food.");    }}public class WalkingVisitor implements AnimalVisitor {    @Override    public void visitDog(Dog dog) {        System.out.println("Walking dog: Take it for a walk in the park.");    }    @Override    public void visitCat(Cat cat) {        System.out.println("Walking cat: Let it roam in the backyard.");    }    @Override    public void visitBird(Bird bird) {        System.out.println("Walking bird: Let it fly around in a safe area.");    }}

最后,我们可以创建动物对象,并使用访问者对象执行相应的操作:

public class Zoo {    public static void main(String[] args) {        Animal[] animals = { new Dog(), new Cat(), new Bird() };                AnimalVisitor feedingVisitor = new FeedingVisitor();        AnimalVisitor walkingVisitor = new WalkingVisitor();                for (Animal animal : animals) {            animal.accept(feedingVisitor);            animal.accept(walkingVisitor);        }    }}

out:

Feeding dog: Give it some dog food.Walking dog: Take it for a walk in the park.Feeding cat: Give it some cat food.Walking cat: Let it roam in the backyard.Feeding bird: Give it some bird food.Walking bird: Let it fly around in a safe area.

这个例子中,动物园中的不同类型的动物实现了相同的接口(Animal),并且接受访问者(AnimalVisitor)进行操作。不同的访问者实现了不同的操作方法,通过调用动物的accept()方法,动物将自身传递给访问者,从而执行相应的操作。

这个例子简化了访问者模式的概念,使得小学生也能理解其中的基本原理和流程。