C++设计模式

一、设计模式的分类

Gang of Four的“Design Patterns: Elements of Resualbel Software”书将设计模式归纳为三大类型,共23种。

创建型模式 : 通常和对象的创建有关,涉及到对象实例化的方式。(共5种模式)

结构型模式:描述的是如何组合类和对象以获得更大的结构。(共7种模式)

行为型模式:用来对类或对象怎样交互和怎样分配职责进行描述。(共11种模式)

创建型模式----用来处理对象的创建过程,主要包含以下5种设计模式:

1,工厂方法模式(Factory Method Pattern)的用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中。

2,抽象工厂模式(Abstract Factory Pattern)的意图是提供一个创建一系列相关或者相互依赖的接口,而无需指定它们具体的类。

3,建造者模式(Builder Pattern)的意图是将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。

4,原型模式(Prototype Pattern)是用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

5,单例模式(Singleton Pattern)是保证一个类仅有一个实例,并提供一个访问它的全局访问点。

结构型模式-------用来处理类或者对象的组合,主要包含以下7种设计模式:

6,代理模式(Proxy Pattern)就是为其他对象提供一种代理以控制对这个对象的访问。

7,装饰者模式(Decorator Pattern)动态的给一个对象添加一些额外的职责。就增加功能来说,此模式比生成子类更为灵活。

8,适配器模式(Adapter Pattern)是将一个类的接口转换成客户希望的另外一个接口。使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

9,桥接模式(Bridge Pattern)是将抽象部分与实际部分分离,使它们都可以独立的变化。

10,组合模式(Composite Pattern)是将对象组合成树形结构以表示“部分--整体”的层次结构。使得用户对单个对象和组合对象的使用具有一致性。

11,外观模式(Facade Pattern)是为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

12,享元模式(Flyweight Pattern)是以共享的方式高效的支持大量的细粒度的对象。

行为型模式------用来对类或对象怎样交互和怎样分配职责进行描述,主要包含以下11种设计模式:

13,模板方法模式(Template Method Pattern)使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

14,命令模式(Command Pattern)是将一个请求封装为一个对象,从而使你可用不同的请求对客户端进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

15,责任链模式(Chain of Responsibility Pattern),在该模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求,这使得系统可以在不影响客户端的情况下动态地重新组织链和分配责任。

16,策略模式(Strategy Pattern)就是准备一组算法,并将每一个算法封装起来,使得它们可以互换。

17,中介者模式(Mediator Pattern)就是定义一个中介对象来封装系列对象之间的交互。终结者使各个对象不需要显示的相互调用 ,从而使其耦合性松散,而且可以独立的改变他们之间的交互。

18,观察者模式(Observer Pattern)定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

19,备忘录模式(Memento Pattern)是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。

20,访问者模式(Visitor Pattern)就是表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

21,状态模式(State Pattern)就是对象的行为,依赖于它所处的状态。

22,解释器模式(Interpreter Pattern)就是描述了如何为简单的语言定义一个语法,如何在该语言中表示一个句子,以及如何解释这些句子。

23,迭代器模式(Iterator Pattern)是提供了一种方法顺序来访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。

二、设计模式基本原则

最终目的:高内聚,低耦合

1) 开放封闭原则 (OCP,Open For Extension, Closed For Modification Principle)

类的改动是通过增加代码进行的,而不是修改源代码。

//开闭原则:说的是代码扩展性问题——对扩展开放,对修改关闭(封闭);

//开闭原则详细的解释:当增加新功能,不应该通过修改已经存在的代码来进行,而是应该通过扩展代码(比如增加新类,增加新成员函数)来进行。

2) 单一职责原则 (SRP,Single Responsibility Principle)

类的职责要单一,对外只提供一种功能,而引起类变化的原因都应该只有一个。

3) 依赖倒置原则 (DIP,Dependence Inversion Principle)

依赖于抽象(接口),不要依赖具体的实现(类),也就是针对接口编程。

4) 接口隔离原则 (ISP,Interface Segegation Principle)

不应该强迫客户的程序依赖他们不需要的接口方法。一个接口应该只提供一种对外功能,不应该把所有操作都封装到一个接口中去。

5) 里氏替换原则 (LSP, Liskov Substitution Principle)

任何抽象类出现的地方都可以用他的实现类进行替换。实际就是虚拟机制,语言级别实现面向对象功能。

6) 优先使用组合而不是继承原则(CARP,Composite/Aggregate Reuse Principle)

如果使用继承,会导致父类的任何变换都可能影响到子类的行为。

如果使用对象组合,就降低了这种依赖关系。

7) 迪米特法则(LOD,Law of Demeter)

一个对象应当对其他对象尽可能少的了解,从而降低各个对象之间的耦合,提高系统的可维护性。例如在一个程序中,各个模块之间相互调用时,通常会提供一个统一的接口来实现。这样其他模块不需要了解另外一个模块的内部实现细节,这样当一个模块内部的实现发生改变时,不会影响其他模块的使用。(黑盒原理)

三、常见的几种设计模式设计

1.单例模式(创建型模式)

单例模式就是只能由一个实例,那么我们就必须保证

1)该类不能被复制。

2)该类不能被公开的创造。(构造和析构为私有,故不能在其他位置使用 :类名+对象名 方式在其他地方使用,因为构造私有了)

注意:

1)饿汉模式本身是线程安全的,饿汉模式在程序一开始就构造函数初始化了,所以本身就线程安全的

2)懒汉模式本身不是线程安全的 需要加互斥量。不加互斥量,需要需要在开始运行的时候new出来。

懒汉模式:

namespace _nmsp1
{
	//懒汉式(很懒惰之意)——程序执行后该单件类对象并不存在,只有第一次调用getInstance成员函数时该单件类对象才被创建
	class GameConfig
	{
		//......
	private:
		GameConfig() {};
		GameConfig(const GameConfig& tmpobj);
		GameConfig& operator=(const GameConfig& tmpobj);
		~GameConfig() {}
	public:
		static GameConfig* getInstance()
		{
			//std::lock_guard<std::mutex> gcguard(my_mutex);  粗暴加锁,不建议采用
			if (m_instance == nullptr)
			{
				//这里加锁(双重锁定/双重检查)——潜在问题:内存访问重新排序(重新排列编译器产生的汇编指令)导致双重锁定失效问题。 volatile。
				//std::lock_guard<std::mutex> gcguard(my_mutex);
				//if (m_instance == nullptr)  //if(m_instance != nullptr)
				//{
				static Garbo garboobj;
				m_instance = new GameConfig();
				//}
			}
			return m_instance;
		}

		/*
	public:
		static void freeInstance()
		{
			if (m_instance != nullptr)
			{
				delete GameConfig::m_instance;
				GameConfig::m_instance = nullptr;
			}
		}*/

	private:
		//手工释放单件类对象引入的GameConfig类中的嵌套类(垃圾回收)
		class Garbo
		{
		public:
			~Garbo()
			{
				if (GameConfig::m_instance != nullptr)
				{
					delete GameConfig::m_instance;
					GameConfig::m_instance = nullptr;
				}
			}
		};

	private:
		static GameConfig* m_instance; //指向本类对象的指针
	};
	GameConfig* GameConfig::m_instance = nullptr; //在类外,某个.cpp源文件的开头位置,为静态成员变量赋值(定义并赋值)
}

饿汉模式:

namespace _nmsp3
{
	//饿汉式(很饥渴很迫切之意)——程序一致性,不管是否调用了getInstance成员函数,这个单件类就已经被创建了(对象创建不受多线程问题困扰)。
	class GameConfig
	{
		//......
	private:
		GameConfig() {};
		GameConfig(const GameConfig& tmpobj);
		GameConfig& operator=(const GameConfig& tmpobj);
		~GameConfig() {}
	public:
		static GameConfig* getInstance()
		{			
			return m_instance; //相比于懒汉模式区别1
		}
	
	private:
		//手工释放单件类对象引入的GameConfig类中的嵌套类(垃圾回收)
		class Garbo
		{
		public:
			~Garbo()
			{
				if (GameConfig::m_instance != nullptr)
				{
					delete GameConfig::m_instance;
					GameConfig::m_instance = nullptr;
				}
			}
		};
	private:
		static Garbo garboobj;

	private:
		static GameConfig* m_instance; 
	};
    //饿汉模式是程序运行后直接new出来,懒汉模式是需要的时候才去new,存在线程不安全的隐患
	GameConfig* GameConfig::m_instance = new GameConfig(); //趁静态成员变量定义的时候直接初始化是允许的,及时GameConfig构造函数是用private修饰
	GameConfig::Garbo GameConfig::garboobj;

	//int g_test = GameConfig::getInstance()->m_i; //m_i为一个int型成员变量
}

2.简单工厂模式(创建型模型)

工厂模式:通过把创建对象的代码包装起来,做到创建对象的代码与具体的业务逻辑代码相隔离的目的。

工厂模式细分:a)简单工厂模式;b)工厂方法模式;c)抽象工厂模式。

引入“简单工厂”设计模式的定义(实现意图):定义一个工厂类(MonsterFactory),该类的成员函数(createMonster)可以根据不同参数创建并返回不同的类对象,被创建的对象所属的类(M_Undead,M_Element,M_Mechanic)一般都具有相同的父类(Monster),调用者(这里指main函数)无需关心创建对象的细节。

简单工厂方法模式:实现了创建怪物类代码(createMonster),与具体怪物类(M_Undead,M_Element,M_Mechanic)解耦合的效果。

简单工厂方法,工厂中是通过简单的if else来实现创建不同的产品

样例一:

#include <iostream>
#include <vector>
#include <sstream>

#ifdef _DEBUG   //只在Debug(调试)模式下
#ifndef DEBUG_NEW
#define DEBUG_NEW new(_NORMAL_BLOCK,__FILE__,__LINE__) //重新定义new运算符
#define new DEBUG_NEW
#endif
#endif

//#include <boost/type_index.hpp>
using namespace std;
//#pragma warning(disable : 4996) 

namespace _nmsp1
{
	//怪物父类
	class Monster
	{
	public:
		//构造函数
		Monster(int life, int magic, int attack) :m_life(life), m_magic(magic), m_attack(attack) {}
		virtual ~Monster() {} //做父类时析构函数应该为虚函数

	protected://可能被子类访问的成员,所以用protected修饰
		//怪物属性
		int m_life; //生命值
		int m_magic; //魔法值
		int m_attack; //攻击力
	};
	//亡灵类怪物
	class M_Undead :public Monster
	{
	public:
		//构造函数
		M_Undead(int life, int magic, int attack) :Monster(life, magic, attack)
		{
			cout << "一个亡灵类怪物来到了这个世界" << endl;
		}
		//其他代码略......
	};
	//元素类怪物
	class M_Element :public Monster
	{
	public:
		//构造函数
		M_Element(int life, int magic, int attack) :Monster(life, magic, attack)
		{
			cout << "一个元素类怪物来到了这个世界" << endl;
		}
		//其他代码略......
	};
	//机械类怪物
	class M_Mechanic :public Monster
	{
	public:
		//构造函数
		M_Mechanic(int life, int magic, int attack) :Monster(life, magic, attack)
		{
			cout << "一个机械类怪物来到了这个世界" << endl;
		}
		//其他代码略......
	};
	//-------------------------------
	//怪物工厂类
	class MonsterFactory
	{
	public:
		//Monster* createMonster(string strmontype) //简单工厂模式
		static Monster* createMonster(string strmontype) //静态工厂方法模式(Static Factory Method)
		{
			Monster* prtnobj = nullptr;
			if (strmontype == "udd") //udd代表要创建亡灵类怪物
			{
				prtnobj = new M_Undead(300, 50, 80);
			}
			else if (strmontype == "elm") //elm代表要创建元素类怪物
			{
				prtnobj = new M_Element(200, 80, 100);
			}
			else if (strmontype == "mec") //mec代表要创建机械类怪物
			{
				prtnobj = new M_Mechanic(400, 0, 110);
			}
			return prtnobj;
		}
	};
}



//测试用例
int main()
{
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//程序退出时检测内存泄漏并显示到“输出”窗口

	/*_nmsp1::MonsterFactory facobj;
	_nmsp1::Monster* pM1 = facobj.createMonster("udd"); //产生了一只亡灵类怪物,当然这里必须知道“udd”代表的是创建亡灵类怪物
	_nmsp1::Monster* pM2 = facobj.createMonster("elm"); //创建一只元素类怪物
	_nmsp1::Monster* pM3 = facobj.createMonster("mec"); //创建一只机械类怪物

	//释放资源
	delete pM1;
	delete pM2;
	delete pM3;
	*/

	
	//此时简单工厂模式又可以称为静态工厂方法模式(Static Factory Method)
	_nmsp1::Monster* pM1 = _nmsp1::MonsterFactory::createMonster("udd"); //产生了一只亡灵类怪物,当然这里必须知道“udd”代表的是创建亡灵类怪物
	_nmsp1::Monster* pM2 = _nmsp1::MonsterFactory::createMonster("elm"); //创建一只元素类怪物
	_nmsp1::Monster* pM3 = _nmsp1::MonsterFactory::createMonster("mec"); //创建一只机械类怪物

	//释放资源
	delete pM1;
	delete pM2;
	delete pM3;

	return 0;
}

样例二:

#include <iostream>
using namespace std;

class Fruit 
{
public:
	virtual void getFruit() = 0;

protected:
private:
};

class Banana : public Fruit
{
public:
	virtual void getFruit()
	{
		cout << "我是香蕉...." << endl;
	}
protected:
private:
};

class Apple : public Fruit
{
public:
	virtual void getFruit()
	{
		cout << "我是苹果...." << endl;
	}
protected:
private:
};


class Factory
{
public:
	Fruit *create(char *p)
	{

		if (strcmp(p, "banana") == 0)
		{
			return new Banana;	 
		}
		else if (strcmp(p, "apple") == 0)
		{
			return new Apple;
		}
		else
		{
			printf("不支持\n" ) ;
			return NULL;
		}
	}
};


void main()
{
	Factory *f = new Factory;

	Fruit *fruit = NULL;


	//工厂生产 香蕉
	fruit = f->create("banana");
	fruit->getFruit();
	delete fruit;


	fruit = f->create("apple");
	fruit->getFruit();
	delete fruit;

	delete f;
	cout<<"hello..."<<endl;
	system("pause");
	return ;
}

3.工厂方法模式(创建型模型)

工厂方法(Factory Method)模式:简称工厂模式或者多态工厂模式,与简单工厂模式比,灵活性更强,实现也更加复杂,引入更多的新类,符合开闭原则,付出的代价是需要新增加多个新的工厂类。

一般可以认为,将简单工厂模式的代码经过把工厂类进行抽象改造成符合开闭原则后的代码,就变成了工厂方法模式的代码。

与简单工厂相比较的优势:

简单工厂模式把创建对象这件事放到了一个统一的地方来处理,弹性比较差。而工厂方法模式相当于建立了一个程序实现框架,从而让子类来决定对象如何创建。工厂方法模式往往需要创建一个与产品等级结构(层次)相同的工厂等级结构,这也增加了新类的层次结构和数目。

样例一:

#include <iostream>
#include <vector>
#include <sstream>

#ifdef _DEBUG   //只在Debug(调试)模式下
#ifndef DEBUG_NEW
#define DEBUG_NEW new(_NORMAL_BLOCK,__FILE__,__LINE__) //重新定义new运算符
#define new DEBUG_NEW
#endif
#endif

//#include <boost/type_index.hpp>
using namespace std;
//#pragma warning(disable : 4996) 

namespace _nmsp1
{
	//怪物父类
	class Monster
	{
	public:
		//构造函数
		Monster(int life, int magic, int attack) :m_life(life), m_magic(magic), m_attack(attack) {}
		virtual ~Monster() {} //做父类时析构函数应该为虚函数

	protected://可能被子类访问的成员,所以用protected修饰
		//怪物属性
		int m_life; //生命值
		int m_magic; //魔法值
		int m_attack; //攻击力
	};
	//亡灵类怪物
	class M_Undead :public Monster
	{
	public:
		//构造函数
		M_Undead(int life, int magic, int attack) :Monster(life, magic, attack)
		{
			cout << "一个亡灵类怪物来到了这个世界" << endl;
		}
		//其他代码略......
	};
	//元素类怪物
	class M_Element :public Monster
	{
	public:
		//构造函数
		M_Element(int life, int magic, int attack) :Monster(life, magic, attack)
		{
			cout << "一个元素类怪物来到了这个世界" << endl;
		}
		//其他代码略......
	};
	//机械类怪物
	class M_Mechanic :public Monster
	{
	public:
		//构造函数
		M_Mechanic(int life, int magic, int attack) :Monster(life, magic, attack)
		{
			cout << "一个机械类怪物来到了这个世界" << endl;
		}
		//其他代码略......
	};
	//野兽类
	//class M_Beast :public Monster { .... };
	//-------------------------------
	/*
	//怪物工厂类
	class MonsterFactory
	{
	public:
		//Monster* createMonster(string strmontype) //简单工厂模式
		static Monster* createMonster(string strmontype) //静态工厂方法模式(Static Factory Method)
		{
			Monster* prtnobj = nullptr;
			if (strmontype == "udd") //udd代表要创建亡灵类怪物
			{
				prtnobj = new M_Undead(300, 50, 80);
			}
			else if (strmontype == "elm") //elm代表要创建元素类怪物
			{
				prtnobj = new M_Element(200, 80, 100);
			}
			else if (strmontype == "mec") //mec代表要创建机械类怪物
			{
				prtnobj = new M_Mechanic(400, 0, 110);
			}
			return prtnobj;
		}
	};
	*/
	//所有工厂类的父类
	class M_ParFactory
	{
	public:
		virtual Monster* createMonster() = 0; //具体的实现在子类中进行
		virtual ~M_ParFactory() {} //做父类时析构函数应该为虚函数
	};
	//M_Undead怪物类型的工厂,生产M_Undead类型怪物
	class M_UndeadFactory : public M_ParFactory
	{
	public:
		virtual Monster* createMonster()
		{
			//return  new M_Undead(300, 50, 80); //创建亡灵类怪物
			Monster *ptmp = new M_Undead(300, 50, 80); //创建亡灵类怪物
			//这里可以增加一些其他业务代码
			//......
			return ptmp;
		}
	};

	//M_Element怪物类型的工厂,生产M_Element类型怪物
	class M_ElementFactory : public M_ParFactory
	{
	public:
		virtual Monster* createMonster()
		{
			return  new M_Element(200, 80, 100); //创建元素类怪物
		}
	};

	//M_Mechanic怪物类型的工厂,生产M_Mechanic类型怪物
	class M_MechanicFactory : public M_ParFactory
	{
	public:
		virtual Monster* createMonster()
		{
			return  new M_Mechanic(400, 0, 110); //创建机械类怪物
		}
	};
	//class M_BeastFactory:public M_ParFactory{......};
	//全局的用于创建怪物对象的函数,注意形参的类型是工厂父类类型的指针,返回类型是怪物父类类型的指针
	Monster* Gbl_CreateMonster(M_ParFactory* factory)
	{
		return  factory->createMonster(); //createMonster虚函数扮演了多态new的行为,factory指向的具体怪物工厂类不同,创建的怪物对象也不同。
	}

	//-------------------
	//不想创建太多工厂类,又想封装变化
	//创建怪物工厂子类模板
	template <typename T>
	class M_ChildFactory :public M_ParFactory
	{
	public:
		virtual Monster* createMonster()
		{
			return new T(300, 50, 80); //如果需要不同的值则可以通过createMonster的形参将值传递进来
		}
	};


}


int main()
{
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//程序退出时检测内存泄漏并显示到“输出”窗口

	/*
	_nmsp1::M_ParFactory* p_ud_fy = new _nmsp1::M_UndeadFactory(); //多态工厂,注意指针类型
	_nmsp1::Monster* pM1 = _nmsp1::Gbl_CreateMonster(p_ud_fy); //产生了一只亡灵类怪物,也是多态,注意返回类型
	                                                         //当然,这里也可以直接写成 Monster *pM1 = p_ud_fy->createMonster();

	_nmsp1::M_ParFactory* p_elm_fy = new _nmsp1::M_ElementFactory();
	_nmsp1::Monster *pM2 = _nmsp1::Gbl_CreateMonster(p_elm_fy); //产生了一只元素类怪物

	_nmsp1::M_ParFactory* p_mec_fy = new _nmsp1::M_MechanicFactory();
	_nmsp1::Monster* pM3 = _nmsp1::Gbl_CreateMonster(p_mec_fy); //产生了一只机械类怪物

	//释放资源
	//释放工厂
	delete p_ud_fy;
	delete p_elm_fy;
	delete p_mec_fy;

	//释放怪物
	delete pM1;
	delete pM2;
	delete pM3;
	*/
	_nmsp1::M_ChildFactory<_nmsp1::M_Undead> myFactory;
	_nmsp1::Monster* pM10 = myFactory.createMonster();

	//释放资源
	delete pM10;


	return 0;
}

样例二:

#include <iostream>
using namespace std;


class Fruit
{
public:
	virtual void  sayname()  = 0;
};

class  Banana : public Fruit
{
public:
	void  sayname()
	{
		cout << "我是香蕉" << endl;
	}
};

class  Apple : public Fruit
{
public:
	void  sayname()
	{
		cout << "我是 Apple" << endl;
	} 
};

class  AbFactory 
{
public:
	virtual Fruit *CreateProduct() = 0;
};

class BananaFactory :public AbFactory
{
public:
	virtual Fruit *CreateProduct()
	{
		return new Banana;
	}
};

class AppleFactory :public AbFactory
{
public:
	virtual Fruit *CreateProduct()
	{
		return new Apple;
	}
};

//
//添加新的产品

class Pear : public Fruit
{
public:
	virtual void sayname()
	{
		cout << "我是 pear" << endl;
	}
protected:
private:
};

class PearFactory : public AbFactory
{
public:
	virtual Fruit *CreateProduct()
	{
		return new Pear;
	}
};



void main()
{
	AbFactory		*factory = NULL;
	Fruit			*fruit = NULL;

	//吃 香蕉
	factory = new BananaFactory;
	fruit = factory->CreateProduct();
	fruit->sayname();

	delete fruit;
	delete factory;


	//Pear 
	factory = new PearFactory;
	fruit = factory->CreateProduct();
	fruit->sayname();

	delete fruit;
	delete factory;

	
	cout<<"hello..."<<endl;
	system("pause");
	return ;
}

4.抽象工厂模式

抽象工厂(Abstract Factory)模式

工厂方法模式:一个工厂创建一种类怪物。

但如果一个工厂子类能够创建不止一种而是多种具有相同规则的怪物对象,那么就可以有效的减少所创建的工厂子类数量,这就是抽象工厂模式的核心思想。

工厂方法模式和抽象工厂模式区别:

a)工厂方法模式:一个工厂生产一个产品

b)抽象工厂模式:一个工厂生产多个产品(产品族)

样例一:

namespace _nmsp3
{
	//身体抽象类
	class Body
	{
	public:
		virtual void getName() = 0;
		virtual ~Body() {}
	};

	//衣服抽象类
	class Clothes
	{
	public:
		virtual void getName() = 0;
		virtual ~Clothes() {}
	};

	//鞋子抽象类
	class Shoes
	{
	public:
		virtual void getName() = 0;
		virtual ~Shoes() {}
	};

	//---------------------------
	//抽象工厂类
	class AbstractFactory
	{
	public:
		//所创建的部件应该稳定的保持这三个部件,才适合抽象工厂模式
		virtual Body* createBody() = 0; //创建身体
		virtual Clothes* createClothes() = 0; //创建衣服
		virtual Shoes* createShoes() = 0; //创建鞋子
		virtual ~AbstractFactory() {}
	};

	//---------------------------
	//芭比娃娃类
	class BarbieDoll
	{
	public:
		//构造函数
		BarbieDoll(Body* tmpbody, Clothes* tmpclothes, Shoes* tmpshoes)
		{
			body = tmpbody;
			clothes = tmpclothes;
			shoes = tmpshoes;
		}

		void Assemble() //组装芭比娃娃
		{
			cout << "成功组装了一个芭比娃娃:" << endl;
			body->getName();
			clothes->getName();
			shoes->getName();
		}

	private:
		Body* body;
		Clothes* clothes;
		Shoes* shoes;
	};
	//---------------------------
	//中国厂商实现的三个部件
	class China_Body :public Body
	{
	public:
		virtual void getName()
		{
			cout << "中国厂商产的_身体部件" << endl;
		}
	};
	class China_Clothes :public Clothes
	{
	public:
		virtual void getName()
		{
			cout << "中国厂商产的_衣服部件" << endl;
		}
	};
	class China_Shoes :public Shoes
	{
	public:
		virtual void getName()
		{
			cout << "中国厂商产的_鞋子部件" << endl;
		}
	};
	//创建一个中国工厂
	class ChinaFactory : public AbstractFactory
	{
	public:
		virtual Body* createBody()
		{
			return new China_Body;
		}
		virtual Clothes* createClothes()
		{
			return new China_Clothes;
		}
		virtual Shoes* createShoes()
		{
			return new China_Shoes;
		}		
	};
	//---------------------------
	//日本厂商实现的三个部件
	class Japan_Body :public Body
	{
	public:
		virtual void getName()
		{
			cout << "日本厂商产的_身体部件" << endl;
		}
	};
	class Japan_Clothes :public Clothes
	{
	public:
		virtual void getName()
		{
			cout << "日本厂商产的_衣服部件" << endl;
		}
	};
	class Japan_Shoes :public Shoes
	{
	public:
		virtual void getName()
		{
			cout << "日本厂商产的_鞋子部件" << endl;
		}
	};
	//创建一个日本工厂
	class JapanFactory : public AbstractFactory
	{
	public:
		virtual Body* createBody()
		{
			return new Japan_Body;
		}
		virtual Clothes* createClothes()
		{
			return new Japan_Clothes;
		}
		virtual Shoes* createShoes()
		{
			return new Japan_Shoes;
		}
	};
	//---------------------------
	//美国厂商实现的三个部件
	class America_Body :public Body
	{
	public:
		virtual void getName()
		{
			cout << "美国厂商产的_身体部件" << endl;
		}
	};
	class America_Clothes :public Clothes
	{
	public:
		virtual void getName()
		{
			cout << "美国厂商产的_衣服部件" << endl;
		}
	};
	class America_Shoes :public Shoes
	{
	public:
		virtual void getName()
		{
			cout << "美国厂商产的_鞋子部件" << endl;
		}
	};
	//创建一个美国工厂
	class AmericaFactory : public AbstractFactory
	{
	public:
		virtual Body* createBody()
		{
			return new America_Body;
		}
		virtual Clothes* createClothes()
		{
			return new America_Clothes;
		}
		virtual Shoes* createShoes()
		{
			return new America_Shoes;
		}
	};
}




int main()
{
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//程序退出时检测内存泄漏并显示到“输出”窗口

	//创建第一个芭比娃娃------------
	//(1)创建一个中国工厂
	_nmsp3::AbstractFactory* pChinaFactory = new _nmsp3::ChinaFactory();
	//(2)创建中国产的各种部件
	_nmsp3::Body* pChinaBody = pChinaFactory->createBody();
	_nmsp3::Clothes* pChinaClothes = pChinaFactory->createClothes();
	_nmsp3::Shoes* pChinaShoes = pChinaFactory->createShoes();
	//(3)创建芭比娃娃
	_nmsp3::BarbieDoll* pbd1obj = new _nmsp3::BarbieDoll(pChinaBody, pChinaClothes, pChinaShoes);
	pbd1obj->Assemble(); //组装芭比娃娃

	cout << "-------------------------------------" << endl;
	//创建第二个芭比娃娃------------
	//(1)创建另外两个工厂:日本工厂,美国工厂
	_nmsp3::AbstractFactory* pJapanFactory = new _nmsp3::JapanFactory();
	_nmsp3::AbstractFactory* pAmericaFactory = new _nmsp3::AmericaFactory();
	//(2)创建中国产的身体部件,日本产的衣服部件,美国产的鞋子部件
	_nmsp3::Body* pChinaBody2 = pChinaFactory->createBody();
	_nmsp3::Clothes* pJapanClothes = pJapanFactory->createClothes();
	_nmsp3::Shoes* pAmericaShoes = pAmericaFactory->createShoes();
	//(3)创建芭比娃娃
	_nmsp3::BarbieDoll* pbd2obj = new _nmsp3::BarbieDoll(pChinaBody2, pJapanClothes, pAmericaShoes);
	pbd2obj->Assemble(); //组装芭比娃娃

	//最后记得释放内存----------------
	delete pbd1obj;
	delete pChinaShoes;
	delete pChinaClothes;
	delete pChinaBody;
	delete pChinaFactory;
	//------------
	delete pbd2obj;
	delete pAmericaShoes;
	delete pJapanClothes;
	delete pChinaBody2;
	delete pAmericaFactory;
	delete pJapanFactory;

	return 0;
}

样例二:

class AbstractFactory

{

public:

virtual Fruit* CreateBanana() = 0;

virtual Fruit* CreateApple() = 0;

};

抽象工厂 生产多种产品

#include <iostream>
using namespace std;

class Fruit
{
public:
	virtual void SayName() = 0;
};

class AbstractFactory
{
public:
	virtual Fruit* CreateBanana() = 0;
	virtual Fruit* CreateApple() = 0;
};

class NorthBanana : public Fruit
{
public:
	virtual void SayName()
	{
		cout << "我是北方香蕉" << endl;
	}
};

class NorthApple : public Fruit
{
public:
	virtual void SayName()
	{
		cout << "我是北方苹果" << endl;
	}
};


class SourthBanana : public Fruit
{
public:
	virtual void SayName()
	{
		cout << "我是南方香蕉" << endl;
	}
};


class SourthApple : public Fruit
{
public:
	virtual void SayName()
	{
		cout << "我是南方苹果" << endl;
	}
};

class NorthFacorty : public AbstractFactory
{
	virtual Fruit * CreateBanana()
	{
		return new NorthBanana;
	}
	virtual Fruit * CreateApple()
	{
		return new NorthApple;
	}
};

class SourthFacorty : public AbstractFactory
{
	virtual Fruit * CreateBanana()
	{
		return new SourthBanana;
	}
	virtual Fruit * CreateApple()
	{
		return new SourthApple;
	}
};


void main()
{
	Fruit			*fruit = NULL;
	AbstractFactory *af = NULL;

	///--------------
	af = new SourthFacorty;
	fruit = af->CreateApple();
	fruit->SayName();
	delete fruit;
	fruit = af->CreateBanana();
	fruit->SayName();
	delete fruit;

	///------
	af = new NorthFacorty;
	fruit = af->CreateApple();
	fruit->SayName();
	delete fruit;
	fruit = af->CreateBanana();
	fruit->SayName();
	delete fruit;

	delete af;
	system("pause");
	return ;
}

5.建造者模式(创建型模式)

建造者(Builder)模式,也称:构建器/构建者/生成器模式-创建型模式。与抽象工厂模式不同的是,建造者模式是在Director的控制下一步一步的构造出来的,在建造的过程中,建造者模式可以进行更精细的控制。

建造者模式元素的组成:

a)Builder(抽象构建器)

b)ConcreteBuilder(具体构建器)

c)Product(产品)

d)Director(指挥者)

可以参考:C++设计模式——建造者模式 - Ring_1992 - 博客园

样例:

#include <iostream>
using namespace std;

#include "string"

class House
{
public:
	void setDoor(string door)
	{
		this->m_door = door;
	}

	void setWall(string wall)
	{
		this->m_wall = wall;
	}
	void setWindow(string window)
	{
		this->m_window = window;
	}

	//--
	string getDoor( )
	{
		cout << m_door << endl;
		return this->m_door ;
	}

	string getWall()
	{
		cout << m_wall << endl;
		return this->m_wall;
	}
	string getWindow()
	{
		cout << m_window << endl;
		return m_window;
	}

private:
	string	m_door;
	string	m_wall;
	string	m_window;
};

class  Builder
{
public:
	virtual void buildWall() = 0;
	virtual void buildDoor() = 0;
	virtual void buildWindow() = 0;
	virtual House* getHouse() = 0;
};

//公寓工程队
class  FlatBuilder : public Builder
{
public:
	FlatBuilder()
	{
		m_house = new House;
	}
	virtual void buildWall()
	{
		m_house->setWall(" flat wall");
	}

	virtual void buildDoor()
	{
		m_house->setDoor("flat door");
	}

	virtual void buildWindow()
	{
		m_house->setWindow("flat window");
	}

	virtual House* getHouse()
	{
		return m_house;
	}
private:
	House *m_house;
};

//别墅 villa 工程队
class  VillaBuilder : public Builder
{
public:
	VillaBuilder()
	{
		m_house = new House;
	}
	virtual void buildWall()
	{
		m_house->setWall(" villa wall");
	}

	virtual void buildDoor()
	{
		m_house->setDoor("villa door");
	}

	virtual void buildWindow()
	{
		m_house->setWindow("villa window");
	}

	virtual House* getHouse()
	{
		return m_house;
	}
private:
	House *m_house;
};

//设计师(指挥者) 负责建造逻辑  
//建筑队 干具体的活
class Director 
{
public:
	Director( Builder * build)
	{
		m_build = build;
	}
	void Construct()
	{
		m_build->buildWall();
		m_build->buildWindow();
		m_build->buildDoor();
	}
private:
	 Builder * m_build;
};


void main()
{
	House		*house  = NULL;
	Builder		*builder = NULL;
	Director	*director = NULL;

	// 请一个建造别墅的工程队
	builder = new VillaBuilder;

	//设计师 指挥 工程队 干活
	director = new Director(builder);
	director->Construct(); 
	house  =  builder->getHouse();
	house->getWindow();
	house->getDoor();

	delete house;
	delete builder;

	//请 FlatBuilder 公寓
	builder = new FlatBuilder;
	director = new Director(builder);
	director->Construct(); 
	house  =  builder->getHouse();
	house->getWindow();
	house->getDoor();
	delete house;
	delete builder;


	delete director;
	system("pause");
	return ;
}

6.原型模式(创建型模式)

原型模式:通过一个对象(原型对象)克隆出多个一模一样的对象。

原型模式的两种角色:

a)Prototype(抽象原型类):Person类。

b)ConcretePrototype(具体原型类):CPlusPlusProgrammer类。

如果对象内部数据比较复杂多变并且在创建对象的时候希望保持对象的当前状态,那么用原型模式显然比较合适。

为什么要使用原型模式?

原型模式和建造者模式、工厂方法模式一样,都属于创建型模式的一种。简单的来说,我们使用原型模式,就是为了创建对象。但是,在以下场景下,使用原型模式是最好的选择:

1)当我们的对象类型不是开始就能确定的,而这个类型是在运行期确定的话,那么我们通过这个类型的对象克隆出一个新的对象比较容易一些;

2)有的时候,我们需要一个对象在某个状态下的副本,此时,我们使用原型模式是最好的选择;例如:一个对象,经过一段处理之后,其内部的状态发生了变化;这个时候,我们需要一个这个状态的副本,如果直接new一个新的对象的话,但是它的状态是不对的,此时,可以使用原型模式,将原来的对象拷贝一个出来,这个对象就和之前的对象是完全一致的了;

3)当我们处理一些比较简单的对象时,并且对象之间的区别很小,可能就几个属性不同而已,那么就可以使用原型模式来完成,省去了创建对象时的麻烦了;

4)有的时候,创建对象时,构造函数的参数很多,而自己又不完全的知道每个参数的意义,就可以使用原型模式来创建一个新的对象,不必去理会创建的过程,让创建过程见鬼去吧。

所以,在上述的的情况下,在设计的时候,适当的考虑一下原型模式,减少对应的工作量,减少程序的复杂度,提高效率。

可以参考:C++设计模式——原型模式 - Ring_1992 - 博客园

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

class Person
{
public:
	virtual Person* clone() = 0;
	virtual void printT() = 0;
};

class  CPlusPlusProgrammer : public Person
{
public:
	CPlusPlusProgrammer()
	{
		m_name = "";
		m_age = 0;
		m_resume = NULL;
	    setResume("aaaa");
	}
	CPlusPlusProgrammer(string name, int age)
	{
		m_name = name;
		m_age = age;
		m_resume = NULL;
		setResume("aaaa");
	}
	void setResume(char *p)
	{
		if (m_resume != NULL)
		{
			delete m_resume;
		}
		m_resume = new char[strlen(p) + 1];
		strcpy(m_resume, p);
	}


	virtual void printT()
	{
		cout << "m_name" << m_name << " m_age" << m_age << "m_resume:" << m_resume <<  endl;
	}
	virtual Person* clone()
	{
		CPlusPlusProgrammer *tmp = new CPlusPlusProgrammer;
		//tmp->m_name = this->m_name;
		*tmp = *this; // =  浅拷贝
		return tmp;
	}
protected:
private:
	string	m_name;
	int		m_age ;
	char	*m_resume;
		
};

int  main()
{
	Person *c1 = new CPlusPlusProgrammer("张三", 32);
	c1->printT();


	Person *c2 = c1->clone();
	c2->printT();

	cout<<"hello..."<<endl;
	system("pause");
	return 0;
}

7.模板方法模式(行为型模式)

模板方法模式(Template Method Pattern)使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 利用多态的时候,这个是必用到的。

模板方法模式的定义(实现意图):定义了一个操作中的算法的骨架(稳定部分),而将一些步骤延迟到子类中去实现(父类中定义虚函数,子类中实现/重写这个虚函数),从而达到在整体稳定的情况下能够产生一些变化的目的。

设计模式的经典总结:设计模式的作用就是在变化和稳定中间寻找隔离点,分离稳定和变化,从而来管理变化。

模板方法模式也被认为导致了一种反向控制结构——这种结构被称为好莱坞法则——不要来调用我,我会去调用你。

#include <iostream>
using namespace std;


class MakeCar
{
public:
	virtual void MakeHead() = 0;
	virtual void MakeBody() = 0;
	virtual void MakeTail() = 0;

public:
	void Make() //模板函数 把业务逻辑给做好
	{
		MakeTail();
		MakeBody();
		MakeHead();
	}
};

//
class Jeep : public MakeCar
{
public:
	virtual void MakeHead()
	{
		cout << "jeep head" << endl;
	}

	virtual void MakeBody()
	{
		cout << "jeep body" << endl;
	}

	virtual void MakeTail()
	{
		cout << "jeep tail" << endl;
	}
};

class Bus : public MakeCar
{
public:
	virtual void MakeHead()
	{
		cout << "Bus head" << endl;
	}

	virtual void MakeBody()
	{
		cout << "Bus body" << endl;
	}

	virtual void MakeTail()
	{
		cout << "Bus tail" << endl;
	}
};

void main()
{
	MakeCar *car = new Bus;
	car->Make();
	delete car;

	MakeCar *car2 = new Jeep;
	car2->Make();
	delete car2;

	
	cout<<"hello..."<<endl;
	system("pause");
	return ;
}

8.观察者模式(行为型模式)

观察者设计模式 定义(实现意图):定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会自动得到通知。也叫发布-订阅(Publish-Subscribe)

观察者模式的四种角色

a)Subject(主题):观察目标,这里指Notifier类。

b)ConcreteSubject(具体主题):这里指TalkNotifier类。

c)Observer(观察者):这里指Fighter类。

d)ConcreteObserver(具体观察者):这里指F_Warrior和F_Mage子类。

观察者模式的特点:

a)在观察者和观察目标之间建立了一个抽象的耦合

b)观察目标会向观察者列表中的所有观察者发送通知。

c)可以通过增加代码来增加新的观察者或者观察目标,符合开闭原则

样例一:

namespace _nmsp2
{
	class Fighter; //类前向声明
	class Notifier //通知器父类
	{
	public:
		virtual void addToList(Fighter* player) = 0; //把要被通知的玩家加入到列表中
		virtual void removeFromList(Fighter* player) = 0; //把不想被通知的玩家从列表中去除
		virtual void notify(Fighter* talker, string tmpContent) = 0; //通知的一些细节信息
		virtual ~Notifier() {}
	};

	//玩家父类
	class Fighter
	{
	public:
		Fighter(int tmpID, string tmpName) :m_iPlayerID(tmpID), m_sPlayerName(tmpName) //构造函数
		{
			m_iFamilyID = -1; //-1表示没有加入任何家族
		}
		virtual ~Fighter() {} //析构函数

	public:
		void SetFamilyID(int tmpID) //加入家族的时候要设置家族ID
		{
			m_iFamilyID = tmpID;
		}
		int GetFamilyID() //获取家族ID
		{
			return m_iFamilyID;
		}

	public:
		void SayWords(string tmpContent,Notifier *notifier) //玩家说了某句话
		{
			notifier->notify(this, tmpContent);
		}
	
		//通知该玩家接收到其他玩家发送来的聊天信息,虚函数,子类可以覆盖以实现不同的功能
		virtual void NotifyWords(Fighter* talker, string tmpContent)
		{
			//显示信息
			cout << "玩家:" << m_sPlayerName << "收到了玩家:" << talker->m_sPlayerName << " 发送的聊天信息:" << tmpContent << endl;
		}

	private:
		int m_iPlayerID;  //玩家ID,全局唯一
		string m_sPlayerName; //玩家名字
		int m_iFamilyID;  //家族ID
	};

	//"战士"类玩家,父类为Fighter
	class F_Warrior :public Fighter
	{
	public:
		F_Warrior(int tmpID, string tmpName) :Fighter(tmpID, tmpName) {} //构造函数
	};

	//"法师"类玩家,父类为Fighter
	class F_Mage :public Fighter
	{
	public:
		F_Mage(int tmpID, string tmpName) :Fighter(tmpID, tmpName) {} //构造函数
	};

	//聊天信息通知器
	class TalkNotifier :public Notifier
	{
	public:
		//将玩家增加到家族列表中来
		virtual void addToList(Fighter* player)
		{
			int tmpfamilyid = player->GetFamilyID();
			if (tmpfamilyid != -1) //加入了某个家族
			{
				auto iter = m_familyList.find(tmpfamilyid);
				if (iter != m_familyList.end())
				{
					//该家族id在map中已经存在
					iter->second.push_back(player); //直接把该玩家加入到该家族
				}
				else
				{
					//该家族id在map中不存在
					list<Fighter*> tmpplayerlist;
					m_familyList.insert(make_pair(tmpfamilyid, tmpplayerlist)); //以该家族id为key,增加条目到map中
					m_familyList[tmpfamilyid].push_back(player); //向该家族中增加第一个玩家
				}
			}
		}
		//将玩家从家族列表中删除
		virtual void removeFromList(Fighter* player)
		{
			int tmpfamilyid = player->GetFamilyID();
			if (tmpfamilyid != -1) //加入了某个家族
			{
				auto iter = m_familyList.find(tmpfamilyid);
				if (iter != m_familyList.end())
				{
					m_familyList[tmpfamilyid].remove(player);
				}
			}
		}

		//家族中某玩家说了句话,调用该函数来通知家族中所有人
		virtual void notify(Fighter* talker, string tmpContent) //talker是讲话的玩家
		{
			int tmpfamilyid = talker->GetFamilyID();
			if (tmpfamilyid != -1) //加入了某个家族
			{
				auto itermap = m_familyList.find(tmpfamilyid);
				if (itermap != m_familyList.end())
				{
					//遍历该玩家所属家族的所有成员
					for (auto iterlist = itermap->second.begin(); iterlist != itermap->second.end(); ++iterlist)
					{
						(*iterlist)->NotifyWords(talker, tmpContent);
					}
				}
			}
		}

	private:
		//map中的key表示家族id,value代表该家族中所有玩家列表
		map<int, list<Fighter*> > m_familyList;
	};
}


int main()
{
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//程序退出时检测内存泄漏并显示到“输出”窗口


	//创建游戏玩家
	_nmsp2::Fighter* pplayerobj1 = new _nmsp2::F_Warrior(10, "张三"); //实际游戏中很多数据取自数据库。
	pplayerobj1->SetFamilyID(100); //假设该玩家所在的家族的家族ID是100
	
	_nmsp2::Fighter* pplayerobj2 = new _nmsp2::F_Warrior(20, "李四");
	pplayerobj2->SetFamilyID(100);
	
	_nmsp2::Fighter* pplayerobj3 = new _nmsp2::F_Mage(30, "王五");
	pplayerobj3->SetFamilyID(100);
	
	_nmsp2::Fighter* pplayerobj4 = new _nmsp2::F_Mage(50, "赵六");
	pplayerobj4->SetFamilyID(200); //赵六和前面三人属于两个不同的家族
	
	//创建通知器
	_nmsp2::Notifier* ptalknotify = new _nmsp2::TalkNotifier();

	//玩家增加到家族列表中来,这样才能收到家族聊天信息
	ptalknotify->addToList(pplayerobj1);
	ptalknotify->addToList(pplayerobj2);
	ptalknotify->addToList(pplayerobj3);
	ptalknotify->addToList(pplayerobj4);

	//某游戏玩家聊天,同族人都应该收到该信息
	pplayerobj1->SayWords("全族人立即到沼泽地集结,准备进攻!", ptalknotify);

	cout << "王五不想再收到家族其他成员的聊天信息了---" << endl;
	ptalknotify->removeFromList(pplayerobj3); //将王五从家族列表中删除
	pplayerobj2->SayWords("请大家听从族长调遣,前往沼泽地!", ptalknotify);

	//释放资源
	delete pplayerobj1;
	delete pplayerobj2;
	delete pplayerobj3;
	delete pplayerobj4;
	delete ptalknotify;



	return 0;
}

样例二:

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


class Secretary;


//观察者 
class PlayserObserver
{
public:
	PlayserObserver(Secretary *secretary)
	{
		this->m_secretary = secretary;
	}
	void update(string action)
	{
		cout << "action:" << action << endl;
		cout << "老板来了 我很害怕啊..." << endl;
		
	}
private:
	Secretary *m_secretary;
};
//
class Secretary
{
public:
	Secretary()
	{
		m_list.clear();
	}
	void Notify(string info)
	{
		//给所有的 观察者 发送 情报
		for ( list<PlayserObserver *>::iterator it=m_list.begin(); it!=m_list.end(); it++)
		{
			(*it)->update(info); //
		}
	}

	void setPlayserObserver(PlayserObserver *o)
	{
		m_list.push_back(o);
	}

private:
	list<PlayserObserver *> m_list;
};
void main()
{
	Secretary			*secretary = NULL;
	PlayserObserver		*po1 = NULL;
	PlayserObserver		*po2 = NULL;

	secretary = new Secretary;
	po1 = new PlayserObserver(secretary);
	po2 = new PlayserObserver(secretary);

	secretary->setPlayserObserver(po1);
	secretary->setPlayserObserver(po2);

	secretary->Notify("老板来了") ;
	secretary->Notify("老板走了");
	delete secretary ;
	delete po1 ;
	delete po2 ;

	system("pause");
	return ;
}

还有一些常用的算法:

适配器模式,装饰器模式,代理模式,享元模式,策略模式,迭代器模式

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值