设计模式——19. 访问者模式

这篇具有很好参考价值的文章主要介绍了设计模式——19. 访问者模式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 说明

访问者模式(Visitor Pattern)是一种行为型设计模式,它允许你在不改变元素类(被访问者)的前提下,定义对元素的新操作(访问者),并将这些操作封装到独立的访问者类中。这样,你可以在不修改被访问者的类的情况下,通过不同的访问者来执行不同的操作。
访问者模式的主要目的是将数据结构和数据操作分离,使得可以在不修改数据结构的情况下,添加新的操作。这对于复杂的数据结构和多种不同的操作场景非常有用。它提供了一种可扩展性强的方式来处理各种数据结构和操作的组合。
访问者模式通常包含以下几个关键角色:

  1. 访问者(Visitor):定义了访问被访问者元素的方法,通常为每一种被访问的元素类型定义一个访问方法。
  2. 具体访问者(Concrete Visitor):实现了访问者接口中定义的方法,即针对每种被访问的元素类型提供了具体的操作逻辑。
  3. 被访问者(Element):定义了一个接受访问者的方法,通常是 accept(Visitor visitor),用于接收访问者的访问。
  4. 具体被访问者(Concrete Element):实现了被访问者接口中的 accept 方法,将自身传递给访问者,使访问者能够访问自身。
  5. 结构对象(Object Structure):包含了多个被访问者,可以遍历这些被访问者,并将访问者应用到它们身上。

访问者模式的优点包括了支持新的操作扩展而无需修改元素类,以及将相关操作封装在独立的访问者类中,使代码更加清晰和易于维护。然而,它也会导致访问者类的数量增加,增加了系统的复杂性。因此,访问者模式适用于那些需要频繁添加新操作而不希望修改现有类的情况。

2. 使用的场景

访问者模式在以下情况下通常很有用:

  1. 需要对复杂对象结构进行操作和遍历:当你有一个复杂的对象结构,其中包含不同类型的元素,并且你需要对这些元素执行各种不同的操作,访问者模式可以将操作和元素解耦,使得操作能够轻松应用于整个对象结构。
  2. 不希望修改现有元素类:如果你不想修改已经存在的元素类,但需要为这些类添加新的操作,访问者模式是一种有效的方式。你可以通过创建新的访问者类来添加新的操作,而无需修改已存在的元素类。
  3. 支持多种不同的操作:当你需要为对象结构添加多个不同的操作,这些操作可能是不断变化和扩展的,访问者模式可以让你更容易地管理和扩展这些操作。
  4. 数据结构和算法分离:访问者模式将数据结构和数据操作分离开来,使得数据结构可以专注于数据的表示,而操作可以专注于数据的处理。这样有助于保持代码的清晰和可维护性。
  5. 分布式操作:当你需要在对象结构的元素上执行分布在多个类中的操作时,访问者模式可以用于将这些操作组织起来,并在需要时轻松添加新的操作。

总之,访问者模式适用于需要对复杂对象结构进行多种不同操作,且这些操作可能会不断变化和扩展的情况。它提供了一种灵活的方式来处理这些情况,同时保持代码的可维护性和可扩展性。

3. 应用例子

下面是一个使用Python实现的访问者模式的简单例子,我们将创建一个动物园的模拟,其中有不同种类的动物,我们将使用访问者模式来访问并执行不同的操作:

# 抽象访问者
class Visitor:
    def visit_dog(self, dog):
        pass

    def visit_cat(self, cat):
        pass


# 具体访问者
class AnimalSoundVisitor(Visitor):
    def visit_dog(self, dog):
        print(f"The dog makes a sound: {dog.sound}")

    def visit_cat(self, cat):
        print(f"The cat makes a sound: {cat.sound}")


# 抽象被访问者
class Animal:
    def accept(self, visitor):
        pass


# 具体被访问者
class Dog(Animal):
    def __init__(self):
        self.sound = "Woof!"

    def accept(self, visitor):
        visitor.visit_dog(self)


class Cat(Animal):
    def __init__(self):
        self.sound = "Meow!"

    def accept(self, visitor):
        visitor.visit_cat(self)


# 对象结构
class Zoo:
    def __init__(self):
        self.animals = []

    def add_animal(self, animal):
        self.animals.append(animal)

    def perform_operation(self, visitor):
        for animal in self.animals:
            animal.accept(visitor)


if __name__ == "__main__":
    zoo = Zoo()
    zoo.add_animal(Dog())
    zoo.add_animal(Cat())

    sound_visitor = AnimalSoundVisitor()
    zoo.perform_operation(sound_visitor)

在这个示例中,我们创建了两个具体被访问者类 Dog 和 Cat,它们都实现了 accept 方法,以便接受访问者的访问。我们还创建了一个具体访问者类 AnimalSoundVisitor,它实现了对不同动物对象的访问操作。
Zoo 类是对象结构,它包含了多个被访问者动物对象,并提供了 perform_operation 方法来接受访问者的访问。

当我们运行这个示例时,AnimalSoundVisitor 将访问动物对象并执行不同的操作,输出每种动物的声音。这展示了如何使用访问者模式来在不修改动物类的情况下添加新的操作。

4. 实现要素

访问者模式的实现要素包括以下几个关键组件:

  1. 抽象访问者(Visitor):定义了访问被访问者元素的方法,通常为每一种被访问的元素类型定义一个访问方法。
  2. 具体访问者(Concrete Visitor):实现了访问者接口中定义的方法,即针对每种被访问的元素类型提供了具体的操作逻辑。
  3. 抽象被访问者(Element):定义了一个接受访问者的方法,通常是 accept(Visitor visitor),用于接收访问者的访问。
  4. 具体被访问者(Concrete Element):实现了被访问者接口中的 accept 方法,将自身传递给访问者,使访问者能够访问自身。
  5. 对象结构(Object Structure):包含了多个被访问者,可以遍历这些被访问者,并将访问者应用到它们身上。

5. Java/golang/javascrip/C++ 等语言实现方式

5.1 Java实现

上述例子用Java语言实现示例如下:

// 抽象访问者
interface Visitor {
    void visit(Dog dog);
    void visit(Cat cat);
}

// 具体访问者
class AnimalSoundVisitor implements Visitor {
    @Override
    public void visit(Dog dog) {
        System.out.println("The dog makes a sound: " + dog.getSound());
    }

    @Override
    public void visit(Cat cat) {
        System.out.println("The cat makes a sound: " + cat.getSound());
    }
}

// 抽象被访问者
interface Animal {
    void accept(Visitor visitor);
}

// 具体被访问者
class Dog implements Animal {
    private String sound = "Woof!";

    public String getSound() {
        return sound;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

class Cat implements Animal {
    private String sound = "Meow!";

    public String getSound() {
        return sound;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

// 对象结构
class Zoo {
    private List<Animal> animals = new ArrayList<>();

    public void addAnimal(Animal animal) {
        animals.add(animal);
    }

    public void performOperation(Visitor visitor) {
        for (Animal animal : animals) {
            animal.accept(visitor);
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Zoo zoo = new Zoo();
        zoo.addAnimal(new Dog());
        zoo.addAnimal(new Cat());

        AnimalSoundVisitor soundVisitor = new AnimalSoundVisitor();
        zoo.performOperation(soundVisitor);
    }
}

在上述示例中,我们使用Java编程语言实现了访问者模式。类似于Python示例,我们定义了抽象访问者接口(Visitor)以及具体访问者类(AnimalSoundVisitor),并实现了访问不同动物对象的方法。

具体的被访问者类(Dog 和 Cat)实现了accept方法,以接受访问者的访问。Zoo 类是对象结构,包含多个被访问者动物对象,并提供了 performOperation 方法来接受访问者的访问。
在 main 方法中,我们创建了动物对象,将它们添加到动物园中,并创建了一个 AnimalSoundVisitor 实例来执行访问操作。运行程序后,将输出不同动物的声音。这演示了如何使用访问者模式来添加新的操作而无需修改现有动物类。

5.2 Golang实现

上述例子用golang实现示例如下:

package main

import "fmt"

// 抽象访问者
type Visitor interface {
        VisitDog(dog *Dog)
        VisitCat(cat *Cat)
}

// 具体访问者
type AnimalSoundVisitor struct{}

func (v *AnimalSoundVisitor) VisitDog(dog *Dog) {
        fmt.Printf("The dog makes a sound: %s\n", dog.GetSound())
}

func (v *AnimalSoundVisitor) VisitCat(cat *Cat) {
        fmt.Printf("The cat makes a sound: %s\n", cat.GetSound())
}

// 抽象被访问者
type Animal interface {
        Accept(visitor Visitor)
}

// 具体被访问者
type Dog struct {
        sound string
}

func NewDog() *Dog {
        return &Dog{sound: "Woof!"}
}

func (d *Dog) GetSound() string {
        return d.sound
}

func (d *Dog) Accept(visitor Visitor) {
        visitor.VisitDog(d)
}

type Cat struct {
        sound string
}

func NewCat() *Cat {
        return &Cat{sound: "Meow!"}
}

func (c *Cat) GetSound() string {
        return c.sound
}

func (c *Cat) Accept(visitor Visitor) {
        visitor.VisitCat(c)
}

// 对象结构
type Zoo struct {
        animals []Animal
}

func (z *Zoo) AddAnimal(animal Animal) {
        z.animals = append(z.animals, animal)
}

func (z *Zoo) PerformOperation(visitor Visitor) {
        for _, animal := range z.animals {
                animal.Accept(visitor)
        }
}

func main() {
        zoo := &Zoo{}
        zoo.AddAnimal(NewDog())
        zoo.AddAnimal(NewCat())

        soundVisitor := &AnimalSoundVisitor{}
        zoo.PerformOperation(soundVisitor)
}

在这个示例中,我们使用Go语言实现了访问者模式。与前面的示例类似,我们定义了抽象访问者接口(Visitor),具体访问者类(AnimalSoundVisitor),以及抽象被访问者接口(Animal)和具体被访问者类(Dog 和 Cat)。然后,我们创建了对象结构 Zoo,将动物对象添加到动物园中,并使用 PerformOperation 方法执行访问操作。

在 main 函数中,我们创建了动物对象,将它们添加到动物园中,并创建了一个 AnimalSoundVisitor 实例来执行访问操作。运行程序后,将输出不同动物的声音。这演示了如何使用访问者模式来添加新的操作而无需修改现有动物类。

5.3 Javascript实现

上述例子用javascript实现示例如下:

// 抽象访问者
class Visitor {
  visitDog(dog) {}
  visitCat(cat) {}
}

// 具体访问者
class AnimalSoundVisitor extends Visitor {
  visitDog(dog) {
    console.log(`The dog makes a sound: ${dog.getSound()}`);
  }

  visitCat(cat) {
    console.log(`The cat makes a sound: ${cat.getSound()}`);
  }
}

// 抽象被访问者
class Animal {
  accept(visitor) {}
}

// 具体被访问者
class Dog extends Animal {
  constructor() {
    super();
    this.sound = "Woof!";
  }

  getSound() {
    return this.sound;
  }

  accept(visitor) {
    visitor.visitDog(this);
  }
}

class Cat extends Animal {
  constructor() {
    super();
    this.sound = "Meow!";
  }

  getSound() {
    return this.sound;
  }

  accept(visitor) {
    visitor.visitCat(this);
  }
}

// 对象结构
class Zoo {
  constructor() {
    this.animals = [];
  }

  addAnimal(animal) {
    this.animals.push(animal);
  }

  performOperation(visitor) {
    for (const animal of this.animals) {
      animal.accept(visitor);
    }
  }
}

// 创建动物园和动物
const zoo = new Zoo();
zoo.addAnimal(new Dog());
zoo.addAnimal(new Cat());

const soundVisitor = new AnimalSoundVisitor();
zoo.performOperation(soundVisitor);

在这个示例中,我们使用JavaScript语言实现了访问者模式。我们定义了抽象访问者类 Visitor 和具体访问者类 AnimalSoundVisitor,以及抽象被访问者类 Animal 和具体被访问者类 Dog 和 Cat。然后,我们创建了对象结构 Zoo,将动物对象添加到动物园中,并使用 performOperation 方法执行访问操作。

在示例的最后部分,我们创建了动物园和动物对象,并执行了访问操作,输出不同动物的声音。这演示了如何使用访问者模式来添加新的操作而无需修改现有动物类。

5.4 C++实现

上述例子用C++实现如下:

#include <iostream>
#include <vector>

// 前置声明
class Dog;
class Cat;

// 抽象访问者
class Visitor {
public:
    virtual void visit(Dog* dog) = 0;
    virtual void visit(Cat* cat) = 0;
};

// 具体访问者
class AnimalSoundVisitor : public Visitor {
public:
    void visit(Dog* dog) override {
        std::cout << "The dog makes a sound: " << dog->getSound() << std::endl;
    }

    void visit(Cat* cat) override {
        std::cout << "The cat makes a sound: " << cat->getSound() << std::endl;
    }
};

// 抽象被访问者
class Animal {
public:
    virtual void accept(Visitor* visitor) = 0;
};

// 具体被访问者
class Dog : public Animal {
private:
    std::string sound = "Woof!";

public:
    std::string getSound() {
        return sound;
    }

    void accept(Visitor* visitor) override {
        visitor->visit(this);
    }
};

class Cat : public Animal {
private:
    std::string sound = "Meow!";

public:
    std::string getSound() {
        return sound;
    }

    void accept(Visitor* visitor) override {
        visitor->visit(this);
    }
};

// 对象结构
class Zoo {
private:
    std::vector<Animal*> animals;

public:
    void addAnimal(Animal* animal) {
        animals.push_back(animal);
    }

    void performOperation(Visitor* visitor) {
        for (Animal* animal : animals) {
            animal->accept(visitor);
        }
    }
};

int main() {
    Zoo zoo;
    zoo.addAnimal(new Dog());
    zoo.addAnimal(new Cat());

    AnimalSoundVisitor soundVisitor;
    zoo.performOperation(&soundVisitor);

    return 0;
}

在这个示例中,我们使用C++语言实现了访问者模式。我们定义了抽象访问者类 Visitor 和具体访问者类 AnimalSoundVisitor,以及抽象被访问者类 Animal 和具体被访问者类 Dog 和 Cat。然后,我们创建了对象结构 Zoo,将动物对象添加到动物园中,并使用 performOperation 方法执行访问操作。

在 main 函数中,我们创建了动物园和动物对象,并执行了访问操作,输出不同动物的声音。这演示了如何使用访问者模式来添加新的操作而无需修改现有动物类。

6. 练习题

考虑一个图书馆管理系统,其中包括不同类型的图书(例如,小说、非小说、杂志等)。每种类型的图书都有不同的属性和操作。使用访问者模式来实现一个报表生成器,该报表生成器可以根据不同类型的图书生成不同的报表。

要求:

  1. 定义一个抽象访问者类 Visitor,其中包括用于访问不同类型的图书的抽象方法(例如,visitNovel、visitMagazine等)。
  2. 定义具体访问者类 ReportGenerator,该类实现了抽象访问者类中的方法,用于生成不同类型图书的报表。
  3. 定义一个抽象图书类 Book,其中包括图书的通用属性和一个抽象方法 accept,用于接受访问者的访问。
  4. 定义具体图书类,如 Novel、NonFiction、Magazine,它们继承自抽象图书类,并实现了 accept 方法,以便接受 ReportGenerator 访问。
  5. 创建一个图书馆类,该类包含图书的集合,并提供方法来添加不同类型的图书。
  6. 在主程序中,创建图书馆对象,添加不同类型的图书,并使用 ReportGenerator 来生成报表。

你可以使用 C++、Java、Python 或任何其他编程语言来实现这个练习。
你可以在评论区里或者私信我回复您的答案,这样我或者大家都能帮你解答,期待着你的回复~文章来源地址https://www.toymoban.com/news/detail-725999.html

到了这里,关于设计模式——19. 访问者模式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 设计模式之访问者模式(上)

    访问者模式 1)概述 1.概念 访问者模式包含 访问者 和 被访问元素 两个主要组成部分。 处方单中的各种药品信息就是 被访问的元素 ,而划价人员和药房工作人员就是 访问者 ,被访问的元素通常具有不同的类型,且不同的访问者可以对它们进行不同的访问操作。 被访问元素

    2024年04月25日
    浏览(41)
  • Java设计模式-访问者模式

    在软件开发领域中,设计模式是解决常见问题的经典方法。其中,访问者模式是一种强大且灵活的设计模式,用于处理对象结构中的元素,并根据不同的访问者实现不同的操作。 访问者模式是一种行为型设计模式,它允许你在不改变元素类的前提下定义新的操作。该模式将算

    2024年02月06日
    浏览(54)
  • js设计模式:访问者模式

    将操作方法封装在一个访问者对象中,而不是封装在每个被访问对象当中。 访问者对象可以通过调用被访问者的接口,用来操作被访问者。

    2024年02月22日
    浏览(71)
  • 设计模式:访问者模式(C++实现)

    访问者模式通过将对元素的操作与元素本身分离,使得可以在不修改元素类的情况下定义新的操作。 运行结果: 在上述代码中,Visitor是访问者接口,定义了访问具体元素的方法。Element是元素接口,定义了接受访问者访问的方法。ConcreteElementA和ConcreteElementB是具体元素类,实

    2024年02月07日
    浏览(53)
  • 03-JAVA设计模式-访问者模式

    访问者模式(Visitor Pattern)是软件设计模式中的一种行为模式,它用于将数据结构中的元素与操作这些元素的操作解耦。这种模式使得可以在不修改数据结构的情况下添加新的操作。 在访问者模式中,我们定义了两个主要角色: 访问者(Visitor): 这个接口声明了一个访问元

    2024年04月29日
    浏览(47)
  • 设计模式(二十三)访问者

    表示一个作用于某对象结构中的各个元素的操作。访问者模式让你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式是一种对象行为型模式 访问者模式是一种较为复杂的行为型模式,它包含访问者和被访问元素两个主要组成部分,这些被访问的元素

    2024年02月19日
    浏览(39)
  • 【设计模式与范式:行为型】69 | 访问者模式(下):为什么支持双分派的语言不需要访问者模式?

    上一节课中,我们学习了访问者模式的原理和实现,并且还原了访问者模式诞生的思维过程。总体上来讲,这个模式的代码实现比较难,所以应用场景并不多。从应用开发的角度来说,它的确不是我们学习的重点。 不过,我们前面反复说过,学习我的专栏,并不只是让你掌握

    2024年02月10日
    浏览(48)
  • 笨蛋学设计模式行为型模式-访问者模式【21】

    8.8.1概念 ​ 访问者模式是一种将操作逻辑与对象结构分离的方法,使得操作可以独立变化,操作逻辑被封装在独立的访问者类中,并在被访问的元素类中提供接受访问者的方法,而不是直接嵌入到数据结构中的对象中。 8.8.2场景 ​ 我们可以将一个购物商场中的商品类作为元

    2024年01月23日
    浏览(54)
  • 瑞_23种设计模式_访问者模式

    🙊 前言:本文章为瑞_系列专栏之《23种设计模式》的访问者模式篇。本文中的部分图和概念等资料,来源于博主学习设计模式的相关网站《菜鸟教程 | 设计模式》和《黑马程序员Java设计模式详解》,特此注明。本文中涉及到的软件设计模式的概念、背景、优点、分类、以及

    2024年04月15日
    浏览(48)
  • 软件设计模式系列之二十五——访问者模式

    访问者模式(Visitor Pattern)是一种强大的行为型设计模式,它允许你在不改变被访问对象的类的前提下,定义新的操作和行为。本文将详细介绍访问者模式,包括其定义、举例说明、结构、实现步骤、Java代码实现、典型应用场景、优缺点、类似模式以及最后的小结。 访问者

    2024年02月08日
    浏览(86)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包