Diseño del modo Observador de patrones (escucha, suscripción) || Seguridad de subprocesos || c ++ Detallado

1. ¿Cuál es el modo de observador?

El modo de observador se usa a menudo para desacoplar la observación de eventos y el procesamiento final. Es un modo de comportamiento de objeto. Si hay una relación de dependencia de uno a muchos entre los objetos, cuando un objeto cambia, otros objetos que dependen de este objeto deben realizar los cambios correspondientes.

Para dar un ejemplo: todos no son ajenos a las cuentas públicas ahora, y a menudo prestan atención a las cuentas públicas. Entonces, este modelo de prestar atención a la cuenta pública es en realidad un modo de observación: cuando se publique nuevo contenido de la cuenta pública a la que prestamos atención, se enviará a aquellos de nosotros que sigamos esta cuenta pública, por lo que no hemos seguido esta cuenta pública. Las personas no recibirán el contenido publicado por este número público. Entonces la cuenta pública en este momento es equivalente a un observador, y nosotros somos equivalentes a los oyentes. El observador descubre que existe un impulso de contenido y lo envía a las personas que lo han seguido. Recibimos el contenido y lo leemos (cambios de comportamiento).

Diagrama modelo UML:

En el ejemplo descrito anteriormente, la persona que se suscribe a la cuenta pública es equivalente a Listen, y la cuenta pública es equivalente a Observer.

También hay un escenario en el que ahora elegimos cursos en colegios y universidades: cada estudiante es equivalente a un oyente y el sistema de la Oficina de Asuntos Académicos es equivalente a un observador. Cuando tomemos clases, todos recibirán el horario de clases de su curso elegido. Cuando la Oficina de Asuntos Académicos envíe un aviso de qué clase tomar, el tiempo de clase se enviará a los estudiantes que hayan elegido este curso. Aviso para asistir a la clase.

Hemos tomado el modo del curso como un ejemplo para realizar el modo de observador.

2. Modo de observador

# include<iostream>
using namespace std;
# include<unordered_map>
//学生基类
class Student
{
public:
	Student(string name):_name(name) {}
	//学生上课事件
	virtual void AttendClass(int classId) = 0;
protected:
	string _name;
};
//两个学生
class Student1 :public Student
{
public:
	Student1(string name):Student(name){}
	void AttendClass(int classId)
	{
		cout << "学生" << _name << "在上课程" << classId << endl;
	}
};
class Student2 :public Student
{
public:
	Student2(string name) :Student(name) {}
	void AttendClass(int classId)
	{
		cout << "学生" << _name << "在上课程" << classId << endl;
	}
};
//教务系统
class DeanSys
{
public:
	//学生选课
	void SelectCourse(Student* stu, int classId)
	{
		//判断当前课程是第一次被人选还是已经有人选过了
		unordered_map<int, list<Student*>>::iterator it = _course.find(classId);
		if (it == _course.end())
		{
			_course[classId].push_back(stu);
		}
		else
		{
			it->second.push_back(stu);
		}
	}

	//通知学生上课
	void NoticeStudent(int classId)
	{
		unordered_map<int, list<Student*>>::iterator it = _course.find(classId);
		if (it != _course.end())
		{
			for (Student* stu : it->second)
			{
				stu->AttendClass(classId);
			}
		}
	}

private:
	//记录学生和课程信息
	unordered_map<int, list<Student*>> _course;

};
int main()
{
	//实例两个学生
	Student* stu1 = new Student1("张三");
	Student* stu2 = new Student2("李四");
	//教务系统
	DeanSys dean;
	//张三选了课程1,2,3
	dean.SelectCourse(stu1, 1);
	dean.SelectCourse(stu1, 2);
	dean.SelectCourse(stu1, 3);
	//李四选了课程2,3
	dean.SelectCourse(stu2, 2);
	dean.SelectCourse(stu2, 3);
	//教务处发通知让学生上课
	int classId;
	while (1)
	{
		cout << "请输入课程ID:>>";
		cin >> classId;
		if (classId <= 0)
			break;
		dean.NoticeStudent(classId);
	}
        delete stu1;
        delete stu2;
}

Resultados de ejecución del programa:

3. Modo de observador seguro para subprocesos

En el código anterior, el método para notificar al estudiante (oyente) de la Oficina de Asuntos Académicos (observador) para que tome la clase es el siguiente:

//通知学生上课
	void NoticeStudent(int classId)
	{
		unordered_map<int, list<Student*>>::iterator it = _course.find(classId);
		if (it != _course.end())
		{
			for (Student* stu : it->second)
			{
				stu->AttendClass(classId);
			}
		}
	}

Luego, al llamar a stu-> AttendClass (classId) en varios subprocesos, el observador no tiene forma de saber si el objeto de escucha aún existe. En este momento, si el objeto de escucha ya no existe, entonces este código generará un error. Este es el problema de seguridad de los objetos compartidos en subprocesos múltiples.

Sabemos que los punteros inteligentes fuertes y débiles proporcionados por C ++ 11 pueden resolver bien este problema. Para la introducción de punteros inteligentes, consulte mi otro artículo:

https://blog.csdn.net/qq_42214953/article/details/88936479

A continuación, use punteros inteligentes C ++ para implementar el modo de observador seguro para subprocesos:

# include<iostream>
using namespace std;
# include<unordered_map>
class Student
{
public:
	Student(string name):_name(name) {}
	//学生上课事件
	virtual void AttendClass(int classId) = 0;
protected:
	string _name;
};
class Student1 :public Student
{
public:
	Student1(string name):Student(name){}
	void AttendClass(int classId)
	{
		cout << "学生" << _name << "在上课程" << classId << endl;
	}
};
class Student2 :public Student
{
public:
	Student2(string name) :Student(name) {}
	void AttendClass(int classId)
	{
		cout << "学生" << _name << "在上课程" << classId << endl;
	}
};

//教务系统
class DeanSys
{
public:
	//学生选课
	void SelectCourse(weak_ptr<Student> stu, int classId)
	{
		//判断当前课程是第一次被人选还是已经有人选过了
		unordered_map<int, list<weak_ptr<Student>>>::iterator it = _course.find(classId);
		if (it == _course.end())
		{
			_course[classId].push_back(stu);
		}
		else
		{
			it->second.push_back(stu);
		}
	}

	//通知学生上课
	void NoticeStudent(int classId)
	{
		unordered_map<int, list<weak_ptr<Student>>>::iterator it = _course.find(classId);
		if (it != _course.end())
		{
		
			for (list<weak_ptr<Student>>::iterator stu = it->second.begin(); stu != it->second.end(); ++stu)
			{
                                //弱智能指针提升为强智能指针来进行访问操作
				shared_ptr<Student> p = stu->lock();
				if (p != nullptr)
				{
					p->AttendClass(classId);
				}
				else
				{
					stu = it->second.erase(stu);
				}
			}
		}
	}

private:
	//记录学生和课程信息
	unordered_map<int, list<weak_ptr<Student>>> _course;

};
int main()
{
	//实例两个学生
	shared_ptr<Student> stu1( new Student1("张三"));
	shared_ptr<Student> stu2 ( new Student2("李四"));
	//教务系统
	DeanSys dean;
	//张三选了课程1,2,3
	dean.SelectCourse(stu1, 1);
	dean.SelectCourse(stu1, 2);
	dean.SelectCourse(stu1, 3);
	//李四选了课程2,3
	dean.SelectCourse(stu2, 2);
	dean.SelectCourse(stu2, 3);
	//教务处发通知让学生上课
	int classId;
	while (1)
	{
		cout << "请输入课程ID:>>";
		cin >> classId;
		if (classId <= 0)
			break;
		dean.NoticeStudent(classId);
	}
}

 

124 artículos originales publicados · Me gusta 24 · Visitas 10,000+

Supongo que te gusta

Origin blog.csdn.net/qq_42214953/article/details/105454104
Recomendado
Clasificación