访问者模式
访问者模式,你可以从表面上理解未访问和采访,就和几个明星的发布会差不多。几个明星或者剧组进行发布会,记者进行采访的时候其顺序一般是一个个明星轮着来,然后记者也是论者了,因为这保证了N*M问题进行时的流畅性,虽然可能比较麻烦,因为有些时候明明一个问题,可以很多明星一起夹杂着回答的。简单来说,访问者模式就是当多个元素共同影响的时候,往往情况时M*N,甚至更多种情况,然后以其中一种元素作为基准,将其他的元素作为客户选择进行分离,这样就可以减少不必要的循环,然后不管里添加那个元素,都不会影响已有的元素结构(比如发布会再加一个明星,其他明星和记者的回答都不会被改变,而只是新增加了一个人的答案而已),而又需要满足开发的拓展性,而诞生的一个模式,专业点就是:作用于同一个对象的不同元素,在使你不改变各元素类的前提下,还可以定义作用域这些元素的新操作。
Visitor:抽象访问者,是其中一个元素的抽象类。比如记者
ConcreteVisitor:具体类,对于某个个体的详细实现。比如各大媒体的记者,属性又什么衣服、工牌、话筒标识等等
Element类:抽象元素类,可以理解为被选为作为基准的那个元素,比如明星。
ConcreteElement:具体类,单个个体的具体属性,
ObjectStrructure:对象结构,用链表或者向量存储基准类的对象,将另外的元素作为参数输入来进行操作。
这里主要使用的双分派思想:接收者的运行时区别和参数区别,简单来说就是M*N的问题,把他分离开来(M*1)*N.
使用场景:
- 对象对应的类很少改变,但是需要不时定义新的操作
- 当一个对象需要多元素进行操作,但是又不想他的类里面含有其他元素的时候,又需要较好的拓展性
优点:
- 单一职责:将结构和作用于结构的逻辑进行分离,降低耦合性
- 拓展性好:容易增加信息元素
缺点:
- 但是时增加新的数据结构麻烦了
实操
思路:
- 将大学录取分数进行分开讨论,进行派生,生成类组
- 因为元素需要进行交互,而且不能在自己的类中含有对方类的属性,因此用函数调用的方式
- 选定一个基准,并且建立一个数据类(System)进行基准存储,给定接口被外部调用,而其参数就是另外一个元素。双分派:循环的时候分了不同学生、在学校之中也用分数进行讨论
// VisitoModel.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <string>
#include <vector>
using namespace std;
//如果当需要讨论两个甚至多个元素的共同作用,
//你们你就可以使用访问者模式,因为M*N这种情况单独讨论很复杂
//那么你就可以将其分开,以一种未基准进行遍历,另外一种作为参数进行输入,相当于M*1
class CStudents;
class CSchool
{
protected:
int m_score;
public:
virtual void isQualified(CStudents* student) {}
};
class CStudents
{
protected:
string m_name;
int m_score;
public:
int getScore() { return m_score; }
string getName() { return m_name; }
virtual void isAdmission(CSchool* school) {}
};
class CWuDaSchool:public CSchool
{
public:
CWuDaSchool() { m_score = 626; }
void isQualified(CStudents* student)
{
if (NULL == student)
return;
if (m_score <= student->getScore())
{
cout << student->getName();
cout << "-";
cout << student->getScore();
cout << "-WuDa:录取了。" << endl;
}
else
{
cout << student->getName();
cout << "-";
cout << student->getScore();
cout << "-WuDa:未录取。" << endl;
}
}
};
class CHuaKeSchool :public CSchool
{
public:
CHuaKeSchool() { m_score = 624; }
void isQualified(CStudents* student)
{
if (NULL == student)
return;
if (m_score <= student->getScore())
{
cout << student->getName();
cout << "-";
cout << student->getScore();
cout << "-HuaKe:录取了。" << endl;
}
else
{
cout << student->getName();
cout << "-";
cout << student->getScore();
cout << "-HuaKe:未录取。" << endl;
}
}
};
class CStudentsA :public CStudents
{
public:
CStudentsA(string name, int score) { m_score = score; m_name = name; }
void isAdmission(CSchool* school)
{
if (NULL == school)
return;
school->isQualified(this);
}
};
class CStudentsB :public CStudents
{
public:
CStudentsB(string name, int score) { m_score = score; m_name = name; }
void isAdmission(CSchool* school)
{
if (NULL == school)
return;
school->isQualified(this);
}
};
class CStudentSystem
{
private:
vector<CStudents*> m_student;
public:
void addStudent(CStudents* student) { m_student.push_back(student); }
void toCheck(CSchool* school)
{
if (NULL == school)
return;
for (int i = 0; i < m_student.size(); ++i)
{
m_student[i]->isAdmission(school);
}
}
};
int main()
{
CStudents *s1 = new CStudentsA("学生1(西藏)", 400);
CStudents *s2 = new CStudentsB("学生2(武汉)", 625);
CStudentSystem *allStu = new CStudentSystem();
allStu->addStudent(s1);
allStu->addStudent(s2);
CSchool *school1 = new CWuDaSchool();
CSchool* school2 = new CHuaKeSchool();
allStu->toCheck(school1);
allStu->toCheck(school2);
}