设计模式_23 访问者模式

23 访问者模式

23.1 概念

封装了一些作用于某种数据结构中的各元素的操作,可以在不改变这个数据结构的前提下定义作用于这些元素的新操作。

23.2 结构

抽象访问者角色:定义了对每一个元素访问的行为,它的参数就是可以访问的元素,它的方法个数理论上来讲与元素个数是一样的。访问者模式要求元素个数不能改变。
具体访问者角色:给出对每一个元素类访问时所产生的具体行为。
具体元素角色:提供接受访问方法的具体实现,通常情况下是使用访问者提供的访问该元素的方法。
对象结构角色:定义当中所提到的对象结构,对象结构是一个抽象描述,具体为一个具有容器性质或者复合对象特性的类,其中含有一组元素,并且可以迭代这些元素,供访问者访问。

23.3 实现

23.3.1 UML图

在这里插入图片描述

23.3.2 代码

AnimalAndPerson.h

#ifndef _ANIMALANDPERSON_H_
#define _ANIMALANDPERSON_H_

#include<iostream>
#include<string>
#include<list>
using namespace std;

class Person;

class Animal {
private:
	string name;
public:
	Animal(string name);
	virtual void accept(Person* person) = 0;
	string getName();
};

class Cat : public Animal {
public:
	Cat(string name);
	void accept(Person* person);
};

class Dog : public Animal {
public:
	Dog(string name);
	void accept(Person* person);
};

class Person {
private:
	string name;
public:
	Person(string name);
	virtual void feed(Dog* dog) = 0;
	virtual void feed(Cat* cat) = 0;
	string getName();
};

class Host : public Person {
public:
	Host(string name);
	void feed(Dog* dog);
	void feed(Cat* cat);
};

class Guest : public Person {
public:
	Guest(string name);
	void feed(Dog* dog);
	void feed(Cat* cat);
};

class Home {
private:
	list<Animal*> animals;
public:
	void addAnimal(Animal* animal);
	void deleteAnimal(Animal* animal);
	void action(Person* person);
};

#endif

AnimalAndPerson.cpp

#include"AnimalAndPerson.h"

//元素角色
Animal::Animal(string name) {
	this->name = name;
}
string Animal::getName() {
	return this->name;
}

Cat::Cat(string name) : Animal(name) {}
void Cat::accept(Person* person) {
	person->feed(this);
	cout << this->getName() << "吃掉了" << person->getName() << "喂的食物" << endl;
	cout << endl;
}

Dog::Dog(string name) : Animal(name) {}
void Dog::accept(Person* person) {
	person->feed(this);
	cout << this->getName() << "吃掉了" << person->getName() << "喂的食物" << endl;
	cout << endl;
}

//访问者角色
Person::Person(string name) {
	this->name = name;
}
string Person::getName() {
	return this->name;
}


Host::Host(string name) : Person(name) {}
void Host::feed(Dog* dog) {
	cout << this->getName() << "喂给了" << dog->getName() << "食物" << endl;
}
void Host::feed(Cat* cat) {
	cout << this->getName() << "喂给了" << cat->getName() << "食物" << endl;
}

Guest::Guest(string name) : Person(name) {}
void Guest::feed(Dog* dog) {
	cout << this->getName() << "喂给了" << dog->getName() << "食物" << endl;
}
void Guest::feed(Cat* cat) {
	cout << this->getName() << "喂给了" << cat->getName() << "食物" << endl;
}

//对象结构角色
void Home::addAnimal(Animal* animal) {
	this->animals.push_back(animal);
}
void Home::deleteAnimal(Animal* animal) {
	this->animals.remove(animal);
}
void Home::action(Person* person) {
	for (list<Animal*>::iterator it = animals.begin(); it != animals.end(); it++) {
		(*it)->accept(person);
	}
}

main.cpp

#include"AnimalAndPerson.h"

int main() {
	Home* home = new Home();
	Person* host = new Host("主人");
	Person* guest = new Guest("客人");
	Animal* dogOne = new Dog("哈士奇");
	Animal* dogTwo = new Dog("柯基");
	Animal* cat = new Cat("布偶猫");
	home->addAnimal(dogOne);
	home->addAnimal(dogTwo);
	home->addAnimal(cat);
	home->action(host);
	home->deleteAnimal(dogTwo);
	home->action(guest);
	return 0;
}

23.4 优缺点

23.4.1 优点

扩展性好。在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。
复用性好。通过访问者来定义整个对象结构通用的功能,从而提高复用度。
分离无关行为。通过访问者来分离无关行为,把相关的行为封装在一起,构成一个访问者,这样每一个访问者的功能都比较单一。

23.4.2 缺点

对象结构变化很困难。每增加一个新的元素类,都要在每一个具体访问类中增加相应具体操作,违背了“开闭原则”。
违反了依赖倒转原则。访问者模式依赖了具体类,而没有依赖抽象类。

23.5 使用场景

对象结构相对稳定,但其操作算法经常变化的程序。
对象结构中的对象需要提供多种不同且不想关的操作,而且要避免让这些操作的变化影响对象的结构。

23.6 分派

23.6.1 定义

变量被声明的类型叫做变量的静态类型,变量所引用的对象的真实类型又叫做变量的实际类型。比如Animal* cat = new Cat();,其中 cat 的静态类型为 Animal* ,实际类型为Cat*。根据对象的类型而对方法进行选择,就是分派。分派分为静态分派和动态分派。
静态分派:发生在编译时期,分派根据静态类型信息发生。重载就是静态分派。
动态分派:发生在运行时期,动态分派动态的置换掉某个方法。重写为动态分派。

23.6.2 双分派

双分派实现动态绑定的本质,在重载方法委派的前面加上了继承体系中覆盖的环节,由于覆盖是动态的,所以重载就是动态的里。

例如上例,如果用如下代码编写,程序报错,给 feed() 函数传递的 *itAnimal*类型,feed无法识别。

//AnimalAndPerson.cpp
void Cat::accept(Person* person) {
	cout << this->getName() << "吃掉了" << person->getName() << "喂的食物" << endl;
}

void Host::feed(Dog* dog) {
	cout << this->getName() << "喂给了" << dog->getName() << "食物" << endl;
	dog->accept(this);
	cout << endl;
}

void Home::action(Person* person) {
	for (list<Animal*>::iterator it = animals.begin(); it != animals.end(); it++) {
		person->feed(*it); //Error
	}
}

//main.cpp
Animal* cat = new Cat("布偶猫");

但是如果在 Cat 类中调用 feed() 函数,则 Animal*类型动态分配为 Cat*。

//AnimalAndPerson.cpp
void Cat::accept(Person* person) {
	person->feed(this); //在Cat类中调用feed函数
	cout << this->getName() << "吃掉了" << person->getName() << "喂的食物" << endl;
	cout << endl;
}

void Host::feed(Dog* dog) {
	cout << this->getName() << "喂给了" << dog->getName() << "食物" << endl;
}

void Home::action(Person* person) {
	for (list<Animal*>::iterator it = animals.begin(); it != animals.end(); it++) {
		(*it)->accept(person);
	}
}

//main.cpp
Animal* cat = new Cat("布偶猫");

return 设计模式概述;

返回设计模式概述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值