c++ 设计模式 的课本范例(下)

发布于:2024-07-02 ⋅ 阅读:(160) ⋅ 点赞:(0)

(19) 桥接模式 Bridge,不是采用类继承,而是采用类组合,一个类的数据成员是类对象,来扩展类的功能。源码如下:

class OS  // 操作系统负责绘图
{
public:
	virtual ~OS() {}
	virtual void draw(char * ptrCache , int lengthCache) = 0 ;
};

class OS_Window : public OS
{
public:
	void draw(char* ptrCache, int lengthCache) { cout << " windows 下绘图\n\n"; }
};

class OS_Linux : public OS
{
public:
	void draw(char* ptrCache, int lengthCache) { cout << " Linux 下绘图\n\n"; }
};

class Image  // 本基类有成员函数负责解析与加载图片至缓存,但绘图调用跟操作系统有关的底层函数
{
protected: OS * ptrOS;
public:
	virtual ~Image() {}
	Image(OS* p) : ptrOS(p) {}
	virtual void parseImage( const char * name) = 0;
};

class Image_jpg : public Image
{
public:
	Image_jpg(OS * p) : Image(p){}

	void parseImage(const char* name)
	{
		cout << " 解析 jpg 图片  ,  ";
		char c[100];                  // 假定分析 jpg 格式后的图片信息统一用 100 字节存储。
		ptrOS->draw(c , 100);
	}
};

class Image_png : public Image
{
public:
	Image_png(OS* p) : Image(p) {}

	void parseImage( const char* name)
	{
		cout << " 解析 png 图片  ,  ";
		char c[50];                  // 假定分析 png 格式后的图片信息统一用 50 字节存储。
		ptrOS->draw(c, 50);
	}
};

int main()
{
	OS_Window osWindow;
	OS_Linux osLinux;

	Image_jpg jpgA(&osLinux) , jpgB(&osWindow) ;
	Image_png pngA(&osLinux) , pngB(&osWindow) ;

	jpgA.parseImage("aaa"); 
	jpgB.parseImage("b");
	pngA.parseImage("c");
	pngB.parseImage("dd");

	return 0;
}

测试结果如下:

在这里插入图片描述

(20)中介者模式 Mediator 。比如 UI 设计,页面上的各种控件,牵一发而动全身,彼此联系紧密。若把控件间的联系代码写入各个控件,会很繁琐,庞大。因此可以创建一个中介对象,专门处理当一个 UI 控件的状态变化时的逻辑。也像电脑主板上的总线,借着总线,实现电脑各部件见的连接与通信。以下代码配套的是这个 UI 登录界面:

在这里插入图片描述

配套的代码如下:

class Control;  // 类的前向声明

class Media  // 中介者的基类
{
public:
	virtual ~Media() {}
	virtual void changed(Control * ptrCtrl) = 0;
};

class Control  // 控件的基类
{
protected: 
	string name;       // 控件名称,以此区分控件,所以该名称将是唯一的
	Media* ptrMedia;   // 显示本控件属于哪个中介管理
public:
	virtual ~Control() {}
	Control(const string& s, Media* pM) : name(s), ptrMedia(pM) {}
	virtual void enable(bool enabled) = 0;
	virtual void changed() { ptrMedia->changed(this); }  // 控件产生了变化,交由 中介者 来处理这种相关联的变化
};

class Control_Button : public Control
{
public:
	Control_Button(const string& s, Media* ptr) : Control(s, ptr) {}
	void enable(bool enabled)
	{ 
		if (enabled)
			cout << " 按钮 " << name << "  被启用\n\n";
		else
			cout << " 按钮 " << name << "  被禁用\n\n";
	}
};

class Control_Radio : public Control
{
public:
	Control_Radio(const string& s, Media* ptr) : Control(s, ptr) {}
	void enable(bool enabled) {}  // 对于单选按钮,不必使用此函数

	void select(bool clicked)   // 对于单选按钮,增加此函数
	{
		if(clicked)
			cout << " 单选按钮 " << name << "  被启用\n\n";
		else
			cout << " 单选按钮 " << name << "  被禁用\n\n";
	}
};

class Control_text : public Control
{
private : string text;  // 文本框里保存了账号或密码的内容
public:
	Control_text(const string & t , const string& s, Media* ptr) : text(t) , Control(s, ptr) {}
	Control_text(const string& s, Media* ptr) : text(""), Control(s, ptr) {}

	void enable(bool enabled)
	{
		if (enabled)
			cout << " 文本框 " << name << "  被启用\n\n";
		else
			cout << " 文本框 " << name << "  被禁用\n\n";
	}

	void setText(const string& s) { text = s; }  // 对文本框增加此函数
	bool isEmpty() { return text.empty(); }      // 判断文本框是否为空
};

class Media_UI : public Media
{
private:
	Control_Button* pLogin, * pLogout;
	Control_Radio* pRadioTourist, * pRadioAccount;
	Control_text *pTextName, * pTextPwd;
public:
	Media_UI(){}

	void init(Control_Button* pLin, Control_Button*pLout, Control_Radio* pTourist, Control_Radio* pAccount, Control_text* pName, Control_text* pPwd)
	{
		pLogin = pLin; pLogout = pLout;
		pRadioTourist = pTourist; pRadioAccount = pAccount;
		pTextName = pName; pTextPwd = pPwd;
	}

	virtual void changed(Control* ptrCtrl)
	{
		if (ptrCtrl == pLogout) { cout << " 游戏退出!\n\n"; return; }
	
		if (ptrCtrl == pRadioTourist)
		{
			pRadioTourist->select(true);
			pRadioAccount->select(false);

			pTextName->enable(false);
			pTextPwd->enable(false);
			pLogin->enable(true);

			return;
		}

		if (ptrCtrl == pLogin) { cout << " 开始登录验证\n\n"; }

		if (ptrCtrl == pRadioAccount)
		{
			pRadioTourist->select(false);
			pRadioAccount->select(true);

			pTextName->enable(true);
			pTextPwd->enable(true);

			if (pTextName->isEmpty() || pTextPwd->isEmpty())
				pLogin->enable(false);
			else
				pLogin->enable(true);
		}

		if (ptrCtrl == pTextName || ptrCtrl == pTextPwd)
		{
			if (pTextName->isEmpty() || pTextPwd->isEmpty())
				pLogin->enable(false);
			else
				pLogin->enable(true);
		}

	}
};

int main()
{
	Media_UI media_UI;
	
	Control_Button login("登录", &media_UI), logout("退出" , &media_UI);
	Control_Radio tourist("游客登录", &media_UI), account("账户登录" , &media_UI);
	Control_text name("昵称", &media_UI), password("密码" , &media_UI);

	media_UI.init(&login , &logout , & tourist , & account , & name , & password);

	login.changed();	logout.changed();
	tourist.changed();  account.changed();
	name.changed();     password.changed();

	name.setText("aaa"); password.setText("1234556");
	login.changed(); account.changed(); name.changed();

	return 0;
}

测试结果如下:

在这里插入图片描述

(21)
谢谢


网站公告

今日签到

点亮在社区的每一天
去签到