C++设计模式之建造者模式
2014-08-29 23:26
435 查看
在内蒙古这辽阔的草原上,放养着成千上万的奶牛。蒙牛集团在这里崛起,迅速抢占中国大半牛奶市场,造就了一个商业帝国。蒙牛集团牛奶生产流程大致是这样的: 放养奶牛--->牛奶加工--->牛奶包装--->销售。经历从放养奶牛到进行市场销售这一系列环节,蒙牛牛奶才得以诞生。虽然生产流程比这个流程还复杂,但对客户而言,根本不需要知道牛奶生产的细节,只需要到超市购买就行了。在设计模式中,也存在一个类似的模式,封装了产品创建的一系列操作过程,客户端无需知道这些操作流程就可以直接使用这个产品,称之为建造者模式。
建造者模式定义如下:
建造者模式一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。
建造者模式结构图
在建造者模式结构图中包含如下几个角色:
Builder(抽象建造者):它为创建一个产品Product对象的各个部件指定抽象接口,在该接口中一般声明两类方法,一类方法是buildPartX(),它们用于创建复杂对象的各个部件;另一类方法是getResult(),它们用于返回复杂对象。Builder既可以是抽象类,也可以是接口。
ConcreteBuilder(具体建造者):它实现了Builder接口,实现各个部件的具体构造和装配方法,定义并明确它所创建的复杂对象,也可以提供一个方法返回创建好的复杂产品对象。
Product(产品角色):它是被构建的复杂对象,包含多个组成部件,具体建造者创建该产品的内部表示并定义它的装配过程。
Director(指挥者):指挥者又称为导演类,它负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系,可以在其construct()建造方法中调用建造者对象的部件构造与装配方法,完成复杂对象的建造。客户端一般只需要与指挥者进行交互,在客户端确定具体建造者的类型,并实例化具体建造者对象,然后通过指挥者类的构造函数或者Setter方法将该对象传入指挥者类中。
在建造者模式的定义中提到了复杂对象,那么什么是复杂对象?简单来说,复杂对象是指那些包含多个成员属性的对象,这些成员属性也称为部件或零件,如汽车包括方向盘、发动机、轮胎等部件;电子邮件包括发件人、收件人、主题、内容、附件等部件;Socket数据包包含包头、包体、包尾等部件;XML配置文件包含头部信息、数据体、尾部信息等部件。
2、暴风影音播放器的设计与实现
现需要开发一款类似暴风影音的播放器,该播放软件提供多种界面显示模式,如完整模式、精简模式、记忆模式等。在不同的显示模式下主界面的组成元素有所差异,如在完整模式下将显示菜单、播放列表、主窗口、控制条等;在精简模式下只显示主窗口和控制条;而在记忆模式下将显示主窗口、控制条、收藏列表等。尝试使用建造者模式设计该软件。
暴风影音播放器是具体的产品,该产品包含菜单、主窗口、播放列表、播放进度条、收藏列表等部件。
暴风影音播放器.h头文件代码如下:
[cpp] view
plaincopy
#ifndef _PLAYER_H_
#define _PLAYER_H_
#include <iostream>
#include <string>
using namespace std;
//播放器
class Player
{
private:
string m_strMenu; //菜单栏
string m_strWindow; //主窗口
string m_strPlayList; //播放列表
string m_strControlBar; //进度条
string m_strCollectList; //收藏列表
public:
//设置部件
void SetMenu(string strMenu);
void SetWindow(string strWindow);
void SetPlayList(string strPlayList);
void SetControlBar(string strControlBar);
void SetCollectList(string strCollectList);
//获取各部件
string GetMenu();
string GetWindow();
string GetPlayList();
string GetControlBar();
string GetCollectList();
//显示播放器窗口包含的部件
void Display();
};
#endif
暴风影响播放器Cpp文件代码如下:
[cpp] view
plaincopy
#include "Player.h"
//设置主菜单部件
void Player::SetMenu(string strMenu)
{
m_strMenu = strMenu;
}
//设置主窗口部件
void Player::SetWindow(string strWindow)
{
m_strWindow = strWindow;
}
//设计播放列表部件
void Player::SetPlayList(string strPlayList)
{
m_strPlayList = strPlayList;
}
//设置滚动条部件
void Player::SetControlBar(string strControlBar)
{
m_strControlBar = strControlBar;
}
//设置收藏列表部件
void Player::SetCollectList(string strCollectList)
{
m_strCollectList = strCollectList;
}
//获取主菜单部件
string Player::GetMenu()
{
return m_strMenu;
}
//获取主窗口部件
string Player::GetWindow()
{
return m_strWindow;
}
//获取播放列表部件
string Player::GetPlayList()
{
return m_strPlayList;
}
//获取滚动条部件
string Player::GetControlBar()
{
return m_strControlBar;
}
//获取收藏列表部件
string Player::GetCollectList()
{
return m_strCollectList;
}
//显示播放器窗口包含的部件
void Player::Display()
{
cout << "---" << m_strWindow << endl;
cout << "---" << m_strMenu << endl;
cout << "---" << m_strPlayList << endl;
cout << "---" << m_strControlBar << endl;
cout << "---" << m_strCollectList << endl << endl;
}
暴风影音播放器能在完整模式、精简模式、记忆模式三种模式下播放,各播放模式下,暴风影音的部件不相同。考虑到扩展性,可以定义一个抽象播放模式类,该抽象类中定义了一系列创建具体播放部件的方法。具体的三种播放模式继承于这个抽象播放模式类。
播放模式.h头文件代码如下:
[cpp] view
plaincopy
#ifndef _PLAY_PATTERN_H_
#define _PLAY_PATTERN_H_
#include <iostream>
#include <string>
#include "Player.h"
using namespace std;
//抽象播放模式
class PlayPattern
{
protected:
//具体产品(播放器)
Player * m_pPlayer;
public:
PlayPattern()
{
m_pPlayer = new Player();
}
~PlayPattern()
{
if( NULL != m_pPlayer )
{
delete m_pPlayer;
m_pPlayer = NULL;
}
}
//制造播放窗口
virtual void BuildWindow() = 0;
//制造播放菜单
virtual void BuildMenu() = 0;
//制造播放列表
virtual void BuildPlayList() = 0;
//制造播放进度条
virtual void BuildControlBar() = 0;
//制造收藏列表
virtual void BuildCollectList() = 0;
//获取产品(播放器)
Player * GetPlayer()
{
return m_pPlayer;
}
};
//完整播放模式
class FullPattern : public PlayPattern
{
public:
void BuildWindow();
void BuildMenu();
void BuildPlayList();
void BuildControlBar();
void BuildCollectList();
};
//精简播放模式
class SimplePattern : public PlayPattern
{
public:
void BuildWindow();
void BuildMenu();
void BuildPlayList();
void BuildControlBar();
void BuildCollectList();
};
//记忆播放模式
class MemoryPattern : public PlayPattern
{
public:
void BuildWindow();
void BuildMenu();
void BuildPlayList();
void BuildControlBar();
void BuildCollectList();
};
#endif
播放模式Cpp文件代码如下:
[cpp] view
plaincopy
#include "PlayPattern.h"
//制造播放窗口
void FullPattern::BuildWindow()
{
m_pPlayer->SetWindow("主界面窗口");
}
//制造播放菜单
void FullPattern::BuildMenu()
{
m_pPlayer->SetMenu("主菜单");
}
//制造播放列表
void FullPattern::BuildPlayList()
{
m_pPlayer->SetPlayList("播放列表");
}
//制造播放进度条
void FullPattern::BuildControlBar()
{
m_pPlayer->SetControlBar("进度条");
}
//制造收藏列表
void FullPattern::BuildCollectList()
{
m_pPlayer->SetCollectList(" ");
}
////////////////精简模式///////////////////////////////
void SimplePattern::BuildWindow()
{
m_pPlayer->SetWindow("主界面窗口");
}
void SimplePattern::BuildMenu()
{
m_pPlayer->SetMenu(" ");
}
void SimplePattern::BuildPlayList()
{
m_pPlayer->SetPlayList(" ");
}
void SimplePattern::BuildControlBar()
{
m_pPlayer->SetControlBar("进度条");
}
void SimplePattern::BuildCollectList()
{
m_pPlayer->SetCollectList(" ");
}
/////////////////记忆模式////////////////////////////////
void MemoryPattern::BuildWindow()
{
m_pPlayer->SetWindow("主界面窗口");
}
void MemoryPattern::BuildMenu()
{
m_pPlayer->SetMenu(" ");
}
void MemoryPattern::BuildPlayList()
{
m_pPlayer->SetPlayList(" ");
}
void MemoryPattern::BuildControlBar()
{
m_pPlayer->SetControlBar("进度条");
}
void MemoryPattern::BuildCollectList()
{
m_pPlayer->SetCollectList("收藏列表");
}
在建造者模式的结构中还引入了一个指挥者类Director,用于控制产品的创建过程。本例中ContructManage就是播放器指挥类。用户需要哪种类型的播放模式,只需要创建一个具体的播放模式,然后把这个播放模式传入到播放器指挥者中就可以了,由播放器指挥者处理一系列过程的建造。
暴风影音播放器指挥者类.h头文件实现如下:
[cpp] view
plaincopy
#ifndef _CONTRUCT_MANAGE_H_
#define _CONTRUCT_MANAGE_H_
#include "PlayPattern.h"
#include "Player.h"
//建造管理器
class ContructManage
{
private:
//具体建造者
PlayPattern * m_pPlayPattern;
public:
//设置播放模式
void SetPlayPattern(PlayPattern * pPlayPattern);
//封装建造过程
Player * Construct();
};
#endif
暴风影音播放器指挥者类Cpp文件实现如下:
[cpp] view
plaincopy
#include "ContructManage.h"
//设置播放模式
void ContructManage::SetPlayPattern(PlayPattern * pPlayPattern)
{
m_pPlayPattern = pPlayPattern;
}
//封装建造过程
Player * ContructManage::Construct()
{
m_pPlayPattern->BuildWindow();
m_pPlayPattern->BuildMenu();
m_pPlayPattern->BuildPlayList();
m_pPlayPattern->BuildControlBar();
m_pPlayPattern->BuildCollectList();
Player * pPlayer = m_pPlayPattern->GetPlayer();
return pPlayer;
}
测试文件实现代码如下:
[cpp] view
plaincopy
#include <iostream>
#include "ContructManage.h"
#include "PlayPattern.h"
#include "Player.h"
using namespace std;
int main()
{
/***********************创建建造管理器**********************/
ContructManage * pContructManage = new ContructManage();
Player * pPlayer = NULL;
/***********************完整播放模式************************/
PlayPattern * pFullPattern = new FullPattern();
cout << "完整播放模式:" << endl;
pContructManage->SetPlayPattern(pFullPattern);
pPlayer = pContructManage->Construct();
pPlayer->Display();
/***********************精简播放模式************************/
PlayPattern * pSimplePattern = new SimplePattern();
cout << "精简播放模式:" << endl;
pContructManage->SetPlayPattern(pSimplePattern);
pPlayer = pContructManage->Construct();
pPlayer->Display();
/***********************记忆播放模式************************/
PlayPattern * pMemoryPattern = new MemoryPattern();
cout << "记忆播放模式:" << endl;
pContructManage->SetPlayPattern(pMemoryPattern);
pPlayer = pContructManage->Construct();
pPlayer->Display();
/***********************销毁操作****************************/
cout << endl;
delete pFullPattern;
pFullPattern = NULL;
delete pSimplePattern;
pSimplePattern = NULL;
delete pMemoryPattern;
pMemoryPattern = NULL;
delete pContructManage;
pContructManage = NULL;
return 0;
}
编译并执行,程序结果如下:
在建造者模式中,客户端只需实例化指挥者类,指挥者类针对抽象建造者编程,客户端根据需要传入具体的建造者类型,指挥者将指导具体建造者一步一步构造一个完整的产品(逐步调用具体建造者的buildX()方法),相同的构造过程可以创建完全不同的产品。在暴风影音播放器实例中,如果需要更换具体的播放模式,只需要把具体播放模式传入到播放器指挥者中即可,可以随时切换播放模式;如果需要增加新的播放模式,可以增加一个新的播放模式类作为抽象播放模式子类,并把该播放模式传入到播放器指挥者中,原有代码无须修改,完全符合“开闭原则”。
3、省略指挥者Director的建造者模式
指挥者类Director在建造者模式中扮演非常重要的作用,简单的Director类用于指导具体建造者如何构建产品,它按一定次序调用Builder的buildPartX()方法,控制调用的先后次序,并向客户端返回一个完整的产品对象。Direcotr针对抽象的建造者进行编程,如果需要不同的建造者,只需把建造者传入指挥者类,无需修改之前的代码。
在有些情况下,为了简化系统结构,可以省略指挥者Director,指挥者不再指导产品的创建过程。而是在Builder中提供逐步构建复杂产品对象的construct()方法。
暴风影音播放器是具体的产品,实现代码和上一篇博客一样,这里就不再呈现。有变化的是建造者类,播放模式.h头文件实现代码如下:
[cpp] view
plaincopy
#ifndef _PLAY_PATTERN_H_
#define _PLAY_PATTERN_H_
#include <iostream>
#include <string>
#include "Player.h"
using namespace std;
//抽象播放模式
class PlayPattern
{
protected:
//具体产品(播放器)
Player * m_pPlayer;
public:
PlayPattern()
{
m_pPlayer = new Player();
}
~PlayPattern()
{
if( NULL != m_pPlayer )
{
delete m_pPlayer;
m_pPlayer = NULL;
}
}
//制造播放窗口
virtual void BuildWindow() = 0;
//制造播放菜单
virtual void BuildMenu() = 0;
//制造播放列表
virtual void BuildPlayList() = 0;
//制造播放进度条
virtual void BuildControlBar() = 0;
//制造收藏列表
virtual void BuildCollectList() = 0;
//开始建造,封装建造过程
Player * StartConstruct()
{
BuildWindow();
BuildMenu();
BuildPlayList();
BuildControlBar();
BuildCollectList();
return m_pPlayer;
}
};
//完整播放模式
class FullPattern : public PlayPattern
{
public:
void BuildWindow();
void BuildMenu();
void BuildPlayList();
void BuildControlBar();
void BuildCollectList();
};
//精简播放模式
class SimplePattern : public PlayPattern
{
public:
void BuildWindow();
void BuildMenu();
void BuildPlayList();
void BuildControlBar();
void BuildCollectList();
};
//记忆播放模式
class MemoryPattern : public PlayPattern
{
public:
void BuildWindow();
void BuildMenu();
void BuildPlayList();
void BuildControlBar();
void BuildCollectList();
};
#endif
指导者类不再指导暴风影音产品对象的创建过程,而是由抽象播放器模式StartConstruct方法来封装播放器产品的创建过程。
播放模式Cpp文件代码如下:
[cpp] view
plaincopy
#include "PlayPattern.h"
//制造播放窗口
void FullPattern::BuildWindow()
{
m_pPlayer->SetWindow("主界面窗口");
}
//制造播放菜单
void FullPattern::BuildMenu()
{
m_pPlayer->SetMenu("主菜单");
}
//制造播放列表
void FullPattern::BuildPlayList()
{
m_pPlayer->SetPlayList("播放列表");
}
//制造播放进度条
void FullPattern::BuildControlBar()
{
m_pPlayer->SetControlBar("进度条");
}
//制造收藏列表,完整播放模式没有收藏列表,内容设为空
void FullPattern::BuildCollectList()
{
m_pPlayer->SetCollectList(" ");
}
////////////////精简模式///////////////////////////////
void SimplePattern::BuildWindow()
{
m_pPlayer->SetWindow("主界面窗口");
}
void SimplePattern::BuildMenu()
{
m_pPlayer->SetMenu(" ");
}
void SimplePattern::BuildPlayList()
{
m_pPlayer->SetPlayList(" ");
}
void SimplePattern::BuildControlBar()
{
m_pPlayer->SetControlBar("进度条");
}
void SimplePattern::BuildCollectList()
{
m_pPlayer->SetCollectList(" ");
}
/////////////////记忆模式////////////////////////////////
void MemoryPattern::BuildWindow()
{
m_pPlayer->SetWindow("主界面窗口");
}
void MemoryPattern::BuildMenu()
{
m_pPlayer->SetMenu(" ");
}
void MemoryPattern::BuildPlayList()
{
m_pPlayer->SetPlayList(" ");
}
void MemoryPattern::BuildControlBar()
{
m_pPlayer->SetControlBar("进度条");
}
void MemoryPattern::BuildCollectList()
{
m_pPlayer->SetCollectList("收藏列表");
}
完整播放模式下并不需要建造收藏列表部件,因此把收藏列表的内容设为空,其它情况类型,把不需要建造的部件内容设为空。测试程序实现代码如下:
[cpp] view
plaincopy
#include <iostream>
#include "PlayPattern.h"
#include "Player.h"
using namespace std;
int main()
{
Player * pPlayer = NULL;
/***********************完整播放模式************************/
PlayPattern * pFullPattern = new FullPattern();
cout << "完整播放模式:" << endl;
pPlayer = pFullPattern->StartConstruct();
pPlayer->Display();
/***********************精简播放模式************************/
SimplePattern * pSimplePattern = new SimplePattern();
cout << "精简播放模式:" << endl;
pPlayer = pSimplePattern->StartConstruct();
pPlayer->Display();
/***********************记忆播放模式************************/
MemoryPattern * pMemoryPattern = new MemoryPattern();
cout << "记忆播放模式:" << endl;
pPlayer = pMemoryPattern->StartConstruct();
pPlayer->Display();
/***********************销毁操作****************************/
cout << endl;
delete pFullPattern;
pFullPattern = NULL;
delete pSimplePattern;
pSimplePattern = NULL;
delete pMemoryPattern;
pMemoryPattern = NULL;
return 0;
}
编译并执行,结果如下:
此时,StartConstruct()方法定义了其他buildPartX()方法调用的次序,为其他方法的执行提供了一个流程模板,这与我们在后面要学习的模板方法模式非常类似。对Director类的省略方式都不影响系统的灵活性和可扩展性,同时还简化了系统结构,但加重了抽象建造者类的职责,如果StartConstruct()方法较为复杂,待构建产品的组成部分较多,建议还是将StartConstruct()方法单独封装在Director中,这样做更符合“单一职责原则”
4、引入钩子方法的建造者模式
建造者模式除了逐步构建一个复杂产品对象外,还可以通过Director类来更加精细地控制产品的创建过程,例如增加一类称之为钩子方法(HookMethod)的特殊方法来控制是否对某个buildPartX()的调用,也就是判断产品中某个部件是否需要被建造。钩子方法的返回类型通常为boolean类型,方法名一般为isXXX(),钩子方法定义在抽象建造者类中。在抽象建造者类中提供钩子方法的默认实现,具体建造者类如果不需要建造某个部件,则该建造者类覆盖抽象建造者类的钩子方法。
暴风影音播放器是具体的产品,实现代码和C++设计模式之建造者模式(一)博客一样,这里就不再呈现。而抽象播放器模式类中定义了一系列的钩子方法,并提供了默认的实现,用于判断是否需要创建对应的部件。如果具体播放器模式不需要某个部件,则具体播放器模式覆盖对应的钩子方法。
播放模式.h头文件代码如下:
[cpp] view
plaincopy
#ifndef _PLAY_PATTERN_H_
#define _PLAY_PATTERN_H_
#include <iostream>
#include <string>
#include "Player.h"
using namespace std;
//抽象播放模式
class PlayPattern
{
protected:
//具体产品(播放器)
Player * m_pPlayer;
public:
PlayPattern()
{
m_pPlayer = new Player();
}
~PlayPattern()
{
if( NULL != m_pPlayer )
{
delete m_pPlayer;
m_pPlayer = NULL;
}
}
//制造播放窗口
virtual void BuildWindow() = 0;
//制造播放菜单
virtual void BuildMenu() = 0;
//制造播放列表
virtual void BuildPlayList() = 0;
//制造播放进度条
virtual void BuildControlBar() = 0;
//制造收藏列表
virtual void BuildCollectList() = 0;
//获取产品(播放器)
Player * GetPlayer()
{
return m_pPlayer;
}
//是否建造播放窗口(钩子方法)
virtual bool IsBuildWindow()
{
return true;
}
//是否建造播放菜单(钩子方法)
virtual bool IsBuildMenu()
{
return true;
}
//是否建造播放列表(钩子方法)
virtual bool IsBuildPlayList()
{
return true;
}
//是否建造播放进度条(钩子方法)
virtual bool IsBuildControlBar()
{
return true;
}
//是否建造收藏列表(钩子方法)
virtual bool IsBuildCollectList()
{
return true;
}
};
//完整播放模式
class FullPattern : public PlayPattern
{
public:
void BuildWindow();
void BuildMenu();
void BuildPlayList();
void BuildControlBar();
void BuildCollectList();
//完整播放模式不需要建造收藏列表
bool IsBuildCollectList()
{
return false;
}
};
//精简播放模式
class SimplePattern : public PlayPattern
{
public:
void BuildWindow();
void BuildMenu();
void BuildPlayList();
void BuildControlBar();
void BuildCollectList();
//精简播放模式不需要建造播放菜单
bool IsBuildMenu()
{
return false;
}
//精简播放模式不需要建造播放列表
bool IsBuildPlayList()
{
return false;
}
//精简播放模式不需要建造收藏列表
bool IsBuildCollectList()
{
return false;
}
};
//记忆播放模式
class MemoryPattern : public PlayPattern
{
public:
void BuildWindow();
void BuildMenu();
void BuildPlayList();
void BuildControlBar();
void BuildCollectList();
//记忆播放模式不需要建造播放菜单
bool IsBuildMenu()
{
return false;
}
//记忆播放模式不需要建造播放列表
bool IsBuildPlayList()
{
return false;
}
};
#endif
播放器模式Cpp实现代码如下:
[cpp] view
plaincopy
#include "PlayPattern.h"
//制造播放窗口
void FullPattern::BuildWindow()
{
m_pPlayer->SetWindow("主界面窗口");
}
//制造播放菜单
void FullPattern::BuildMenu()
{
m_pPlayer->SetMenu("主菜单");
}
//制造播放列表
void FullPattern::BuildPlayList()
{
m_pPlayer->SetPlayList("播放列表");
}
//制造播放进度条
void FullPattern::BuildControlBar()
{
m_pPlayer->SetControlBar("进度条");
}
//制造收藏列表
void FullPattern::BuildCollectList()
{
m_pPlayer->SetCollectList(" ");
}
////////////////精简模式///////////////////////////////
void SimplePattern::BuildWindow()
{
m_pPlayer->SetWindow("主界面窗口");
}
void SimplePattern::BuildMenu()
{
m_pPlayer->SetMenu(" ");
}
void SimplePattern::BuildPlayList()
{
m_pPlayer->SetPlayList(" ");
}
void SimplePattern::BuildControlBar()
{
m_pPlayer->SetControlBar("进度条");
}
void SimplePattern::BuildCollectList()
{
m_pPlayer->SetCollectList(" ");
}
/////////////////记忆模式////////////////////////////////
void MemoryPattern::BuildWindow()
{
m_pPlayer->SetWindow("主界面窗口");
}
void MemoryPattern::BuildMenu()
{
m_pPlayer->SetMenu(" ");
}
void MemoryPattern::BuildPlayList()
{
m_pPlayer->SetPlayList(" ");
}
void MemoryPattern::BuildControlBar()
{
m_pPlayer->SetControlBar("进度条");
}
void MemoryPattern::BuildCollectList()
{
m_pPlayer->SetCollectList("收藏列表");
}
在暴风影音播放器指导者ContructManage中,调用了一系列的钩子方法,用于判断在不同播放模式下,是否需要创建对应的部件。暴风影音播放器指挥者类.h头文件实现如下:
[cpp] view
plaincopy
#ifndef _CONTRUCT_MANAGE_H_
#define _CONTRUCT_MANAGE_H_
#include "PlayPattern.h"
#include "Player.h"
//建造管理器
class ContructManage
{
private:
//具体建造者
PlayPattern * m_pPlayPattern;
public:
//设计播放器模式(也就是设置具体建造者)
void SetPlayPattern(PlayPattern * pPlayPattern);
//封装建造过程,调用钩子方法,判断对应的部件是否需要建造
Player * Construct();
};
#endif
暴风影音播放器指挥者类Cpp文件实现如下:
[cpp] view
plaincopy
#include "ContructManage.h"
//设计播放器模式(也就是设置具体建造者)
void ContructManage::SetPlayPattern(PlayPattern * pPlayPattern)
{
m_pPlayPattern = pPlayPattern;
}
//封装建造过程,调用一系列钩子方法,判断对应的部件是否需要建造
Player * ContructManage::Construct()
{
bool bRetVal = true;
//根据需要建造播放窗口
bRetVal = m_pPlayPattern->IsBuildWindow();
if( true == bRetVal )
{
m_pPlayPattern->BuildWindow();
}
//根据需要建造播放菜单
bRetVal = m_pPlayPattern->IsBuildMenu();
if( true == bRetVal )
{
m_pPlayPattern->BuildMenu();
}
//根据需要建造播放列表
bRetVal = m_pPlayPattern->IsBuildPlayList();
if( true == bRetVal )
{
m_pPlayPattern->BuildPlayList();
}
//根据需要建造播放进度条
bRetVal = m_pPlayPattern->IsBuildControlBar();
if( true == bRetVal )
{
m_pPlayPattern->BuildControlBar();
}
//根据需要建造收藏列表
bRetVal = m_pPlayPattern->IsBuildCollectList();
if( true == bRetVal )
{
m_pPlayPattern->BuildCollectList();
}
//返回已经建造好的播放器
Player * pPlayer = m_pPlayPattern->GetPlayer();
return pPlayer;
}
测试程序实现代码如下:
[cpp] view
plaincopy
#include <iostream>
#include "ContructManage.h"
#include "PlayPattern.h"
#include "Player.h"
using namespace std;
int main()
{
/***********************创建建造管理器**********************/
ContructManage * pContructManage = new ContructManage();
Player * pPlayer = NULL;
/***********************完整播放模式************************/
PlayPattern * pFullPattern = new FullPattern();
cout << "完整播放模式:" << endl;
pContructManage->SetPlayPattern(pFullPattern);
pPlayer = pContructManage->Construct();
pPlayer->Display();
/***********************精简播放模式************************/
PlayPattern * pSimplePattern = new SimplePattern();
cout << "精简播放模式:" << endl;
pContructManage->SetPlayPattern(pSimplePattern);
pPlayer = pContructManage->Construct();
pPlayer->Display();
/***********************记忆播放模式************************/
PlayPattern * pMemoryPattern = new MemoryPattern();
cout << "记忆播放模式:" << endl;
pContructManage->SetPlayPattern(pMemoryPattern);
pPlayer = pContructManage->Construct();
pPlayer->Display();
/***********************销毁操作****************************/
cout << endl;
delete pFullPattern;
pFullPattern = NULL;
delete pSimplePattern;
pSimplePattern = NULL;
delete pMemoryPattern;
pMemoryPattern = NULL;
delete pContructManage;
pContructManage = NULL;
return 0;
}
编译并执行,结果如下:
通过引入钩子方法,我们可以在建造者指导者类中对复杂产品的构建进行精细的控制,不仅指定buildPartX()方法的执行顺序,还可以控制是否需要执行某个buildPartX()方法。
5、建造者模式总结
建造者模式的核心在于如何一步步构建一个包含多个组成部件的完整对象,使用相同的构建过程构建不同的产品,在软件开发中,如果我们需要创建复杂对象并希望系统具备很好的灵活性和可扩展性可以考虑使用建造者模式。
1.主要优点
建造者模式的主要优点如下:
(1) 在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。建造者模式封装了产品具体的创建流程,符合"封装变化原则"。
(2) 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。由于指挥者类针对抽象建造者编程,增加新的具体建造者无须修改原有类库的代码,系统扩展方便,符合“开闭原则”,也符合"针对抽象进行编程而不是针对具体编程原则"。
(3) 可以更加精细地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。
2.主要缺点
建造者模式的主要缺点如下:
(1) 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,例如很多组成部分都不相同,不适合使用建造者模式,因此其使用范围受到一定的限制。
(2) 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大,增加系统的理解难度和运行成本。
3.建造者模式的具体应用
(1)在游戏角色中,存在魔鬼、天使、英雄等角色。这些角色都包含相同的建造过程(建造头、脚、外观等),而每一个游戏角色建造方法各不相同。
(2)解析XML格式的配置文件时,需要解析配置文件的头部信息、数据体、尾部信息等。可以把解析的三个过程视为建造的三个过程。
(3)解析Rtf文档格式同样存在和解析XML格式的配置文件相同的情况。
(4)我们使用Email发送邮件的是否,需要填写邮件标题、收件人、邮件内容等信息。可以把填写邮件标题、收件人、邮件内容视为三个建造过程。
(5)我们在定义Socket网络通信协议的时候,需要定义数据祯,每祯由包头、包体、包尾组成。这样在通信的双方,就可以按照同样的格式进行收发信息。
(6)使用Gcc编译程序需要经历编译、汇编、链接等过程,最终才能形成可执行程序。
(7)我们使用美图、Photoshop软件美化图像时,得执行一系列操作(锐化、镜像等),最终才有一副绚丽的照片。
(8)在创建对话框程序过程中,会有一个向导提示每一步的创建过程。经历一系列的过程,最终才形成一个对话框。同样,在安装软件的过程中,也会出现向导让我们定制软件的某些外观或者功能。
(9)在定制Linux内核过程中,可以根据需要删减某些不需要的功能模块。定制出一个功能适中的操作系统,俗称内核裁剪,然后把裁剪后的Linux系统移植到嵌入式设备上(ARM等)。
(10)生活中的建造者模式应用: 桥梁建造、三峡工程建造、鸟巢水立方等一系列工程建造;361、安踏、九牧王一系列服装业建造;杂交水稻、转基因大米等粮食建造。
1、建造者模式概述
建造者模式是较为复杂的创建型模式,它将客户端与包含多个组成部分(或部件)的复杂对象的创建过程分离,客户端无须知道复杂对象的内部组成部分与装配方式,只需要知道所需建造者的类型即可。它关注如何一步一步创建一个的复杂对象,不同的具体建造者定义了不同的创建过程,且具体建造者相互独立,增加新的建造者非常方便,无须修改已有代码,系统具有较好的扩展性。例如:用户不需要知道电脑的具体制造流程,而直接使用电脑就可以了,电脑具体制造流程对用户来说就相当于一个黑盒子。建造者模式定义如下:
建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是一种对象创建型模式。 |
建造者模式结构图
在建造者模式结构图中包含如下几个角色:
Builder(抽象建造者):它为创建一个产品Product对象的各个部件指定抽象接口,在该接口中一般声明两类方法,一类方法是buildPartX(),它们用于创建复杂对象的各个部件;另一类方法是getResult(),它们用于返回复杂对象。Builder既可以是抽象类,也可以是接口。
ConcreteBuilder(具体建造者):它实现了Builder接口,实现各个部件的具体构造和装配方法,定义并明确它所创建的复杂对象,也可以提供一个方法返回创建好的复杂产品对象。
Product(产品角色):它是被构建的复杂对象,包含多个组成部件,具体建造者创建该产品的内部表示并定义它的装配过程。
Director(指挥者):指挥者又称为导演类,它负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系,可以在其construct()建造方法中调用建造者对象的部件构造与装配方法,完成复杂对象的建造。客户端一般只需要与指挥者进行交互,在客户端确定具体建造者的类型,并实例化具体建造者对象,然后通过指挥者类的构造函数或者Setter方法将该对象传入指挥者类中。
在建造者模式的定义中提到了复杂对象,那么什么是复杂对象?简单来说,复杂对象是指那些包含多个成员属性的对象,这些成员属性也称为部件或零件,如汽车包括方向盘、发动机、轮胎等部件;电子邮件包括发件人、收件人、主题、内容、附件等部件;Socket数据包包含包头、包体、包尾等部件;XML配置文件包含头部信息、数据体、尾部信息等部件。
2、暴风影音播放器的设计与实现
现需要开发一款类似暴风影音的播放器,该播放软件提供多种界面显示模式,如完整模式、精简模式、记忆模式等。在不同的显示模式下主界面的组成元素有所差异,如在完整模式下将显示菜单、播放列表、主窗口、控制条等;在精简模式下只显示主窗口和控制条;而在记忆模式下将显示主窗口、控制条、收藏列表等。尝试使用建造者模式设计该软件。
暴风影音播放器是具体的产品,该产品包含菜单、主窗口、播放列表、播放进度条、收藏列表等部件。
暴风影音播放器.h头文件代码如下:
[cpp] view
plaincopy
#ifndef _PLAYER_H_
#define _PLAYER_H_
#include <iostream>
#include <string>
using namespace std;
//播放器
class Player
{
private:
string m_strMenu; //菜单栏
string m_strWindow; //主窗口
string m_strPlayList; //播放列表
string m_strControlBar; //进度条
string m_strCollectList; //收藏列表
public:
//设置部件
void SetMenu(string strMenu);
void SetWindow(string strWindow);
void SetPlayList(string strPlayList);
void SetControlBar(string strControlBar);
void SetCollectList(string strCollectList);
//获取各部件
string GetMenu();
string GetWindow();
string GetPlayList();
string GetControlBar();
string GetCollectList();
//显示播放器窗口包含的部件
void Display();
};
#endif
暴风影响播放器Cpp文件代码如下:
[cpp] view
plaincopy
#include "Player.h"
//设置主菜单部件
void Player::SetMenu(string strMenu)
{
m_strMenu = strMenu;
}
//设置主窗口部件
void Player::SetWindow(string strWindow)
{
m_strWindow = strWindow;
}
//设计播放列表部件
void Player::SetPlayList(string strPlayList)
{
m_strPlayList = strPlayList;
}
//设置滚动条部件
void Player::SetControlBar(string strControlBar)
{
m_strControlBar = strControlBar;
}
//设置收藏列表部件
void Player::SetCollectList(string strCollectList)
{
m_strCollectList = strCollectList;
}
//获取主菜单部件
string Player::GetMenu()
{
return m_strMenu;
}
//获取主窗口部件
string Player::GetWindow()
{
return m_strWindow;
}
//获取播放列表部件
string Player::GetPlayList()
{
return m_strPlayList;
}
//获取滚动条部件
string Player::GetControlBar()
{
return m_strControlBar;
}
//获取收藏列表部件
string Player::GetCollectList()
{
return m_strCollectList;
}
//显示播放器窗口包含的部件
void Player::Display()
{
cout << "---" << m_strWindow << endl;
cout << "---" << m_strMenu << endl;
cout << "---" << m_strPlayList << endl;
cout << "---" << m_strControlBar << endl;
cout << "---" << m_strCollectList << endl << endl;
}
暴风影音播放器能在完整模式、精简模式、记忆模式三种模式下播放,各播放模式下,暴风影音的部件不相同。考虑到扩展性,可以定义一个抽象播放模式类,该抽象类中定义了一系列创建具体播放部件的方法。具体的三种播放模式继承于这个抽象播放模式类。
播放模式.h头文件代码如下:
[cpp] view
plaincopy
#ifndef _PLAY_PATTERN_H_
#define _PLAY_PATTERN_H_
#include <iostream>
#include <string>
#include "Player.h"
using namespace std;
//抽象播放模式
class PlayPattern
{
protected:
//具体产品(播放器)
Player * m_pPlayer;
public:
PlayPattern()
{
m_pPlayer = new Player();
}
~PlayPattern()
{
if( NULL != m_pPlayer )
{
delete m_pPlayer;
m_pPlayer = NULL;
}
}
//制造播放窗口
virtual void BuildWindow() = 0;
//制造播放菜单
virtual void BuildMenu() = 0;
//制造播放列表
virtual void BuildPlayList() = 0;
//制造播放进度条
virtual void BuildControlBar() = 0;
//制造收藏列表
virtual void BuildCollectList() = 0;
//获取产品(播放器)
Player * GetPlayer()
{
return m_pPlayer;
}
};
//完整播放模式
class FullPattern : public PlayPattern
{
public:
void BuildWindow();
void BuildMenu();
void BuildPlayList();
void BuildControlBar();
void BuildCollectList();
};
//精简播放模式
class SimplePattern : public PlayPattern
{
public:
void BuildWindow();
void BuildMenu();
void BuildPlayList();
void BuildControlBar();
void BuildCollectList();
};
//记忆播放模式
class MemoryPattern : public PlayPattern
{
public:
void BuildWindow();
void BuildMenu();
void BuildPlayList();
void BuildControlBar();
void BuildCollectList();
};
#endif
播放模式Cpp文件代码如下:
[cpp] view
plaincopy
#include "PlayPattern.h"
//制造播放窗口
void FullPattern::BuildWindow()
{
m_pPlayer->SetWindow("主界面窗口");
}
//制造播放菜单
void FullPattern::BuildMenu()
{
m_pPlayer->SetMenu("主菜单");
}
//制造播放列表
void FullPattern::BuildPlayList()
{
m_pPlayer->SetPlayList("播放列表");
}
//制造播放进度条
void FullPattern::BuildControlBar()
{
m_pPlayer->SetControlBar("进度条");
}
//制造收藏列表
void FullPattern::BuildCollectList()
{
m_pPlayer->SetCollectList(" ");
}
////////////////精简模式///////////////////////////////
void SimplePattern::BuildWindow()
{
m_pPlayer->SetWindow("主界面窗口");
}
void SimplePattern::BuildMenu()
{
m_pPlayer->SetMenu(" ");
}
void SimplePattern::BuildPlayList()
{
m_pPlayer->SetPlayList(" ");
}
void SimplePattern::BuildControlBar()
{
m_pPlayer->SetControlBar("进度条");
}
void SimplePattern::BuildCollectList()
{
m_pPlayer->SetCollectList(" ");
}
/////////////////记忆模式////////////////////////////////
void MemoryPattern::BuildWindow()
{
m_pPlayer->SetWindow("主界面窗口");
}
void MemoryPattern::BuildMenu()
{
m_pPlayer->SetMenu(" ");
}
void MemoryPattern::BuildPlayList()
{
m_pPlayer->SetPlayList(" ");
}
void MemoryPattern::BuildControlBar()
{
m_pPlayer->SetControlBar("进度条");
}
void MemoryPattern::BuildCollectList()
{
m_pPlayer->SetCollectList("收藏列表");
}
在建造者模式的结构中还引入了一个指挥者类Director,用于控制产品的创建过程。本例中ContructManage就是播放器指挥类。用户需要哪种类型的播放模式,只需要创建一个具体的播放模式,然后把这个播放模式传入到播放器指挥者中就可以了,由播放器指挥者处理一系列过程的建造。
暴风影音播放器指挥者类.h头文件实现如下:
[cpp] view
plaincopy
#ifndef _CONTRUCT_MANAGE_H_
#define _CONTRUCT_MANAGE_H_
#include "PlayPattern.h"
#include "Player.h"
//建造管理器
class ContructManage
{
private:
//具体建造者
PlayPattern * m_pPlayPattern;
public:
//设置播放模式
void SetPlayPattern(PlayPattern * pPlayPattern);
//封装建造过程
Player * Construct();
};
#endif
暴风影音播放器指挥者类Cpp文件实现如下:
[cpp] view
plaincopy
#include "ContructManage.h"
//设置播放模式
void ContructManage::SetPlayPattern(PlayPattern * pPlayPattern)
{
m_pPlayPattern = pPlayPattern;
}
//封装建造过程
Player * ContructManage::Construct()
{
m_pPlayPattern->BuildWindow();
m_pPlayPattern->BuildMenu();
m_pPlayPattern->BuildPlayList();
m_pPlayPattern->BuildControlBar();
m_pPlayPattern->BuildCollectList();
Player * pPlayer = m_pPlayPattern->GetPlayer();
return pPlayer;
}
测试文件实现代码如下:
[cpp] view
plaincopy
#include <iostream>
#include "ContructManage.h"
#include "PlayPattern.h"
#include "Player.h"
using namespace std;
int main()
{
/***********************创建建造管理器**********************/
ContructManage * pContructManage = new ContructManage();
Player * pPlayer = NULL;
/***********************完整播放模式************************/
PlayPattern * pFullPattern = new FullPattern();
cout << "完整播放模式:" << endl;
pContructManage->SetPlayPattern(pFullPattern);
pPlayer = pContructManage->Construct();
pPlayer->Display();
/***********************精简播放模式************************/
PlayPattern * pSimplePattern = new SimplePattern();
cout << "精简播放模式:" << endl;
pContructManage->SetPlayPattern(pSimplePattern);
pPlayer = pContructManage->Construct();
pPlayer->Display();
/***********************记忆播放模式************************/
PlayPattern * pMemoryPattern = new MemoryPattern();
cout << "记忆播放模式:" << endl;
pContructManage->SetPlayPattern(pMemoryPattern);
pPlayer = pContructManage->Construct();
pPlayer->Display();
/***********************销毁操作****************************/
cout << endl;
delete pFullPattern;
pFullPattern = NULL;
delete pSimplePattern;
pSimplePattern = NULL;
delete pMemoryPattern;
pMemoryPattern = NULL;
delete pContructManage;
pContructManage = NULL;
return 0;
}
编译并执行,程序结果如下:
在建造者模式中,客户端只需实例化指挥者类,指挥者类针对抽象建造者编程,客户端根据需要传入具体的建造者类型,指挥者将指导具体建造者一步一步构造一个完整的产品(逐步调用具体建造者的buildX()方法),相同的构造过程可以创建完全不同的产品。在暴风影音播放器实例中,如果需要更换具体的播放模式,只需要把具体播放模式传入到播放器指挥者中即可,可以随时切换播放模式;如果需要增加新的播放模式,可以增加一个新的播放模式类作为抽象播放模式子类,并把该播放模式传入到播放器指挥者中,原有代码无须修改,完全符合“开闭原则”。
3、省略指挥者Director的建造者模式
指挥者类Director在建造者模式中扮演非常重要的作用,简单的Director类用于指导具体建造者如何构建产品,它按一定次序调用Builder的buildPartX()方法,控制调用的先后次序,并向客户端返回一个完整的产品对象。Direcotr针对抽象的建造者进行编程,如果需要不同的建造者,只需把建造者传入指挥者类,无需修改之前的代码。
在有些情况下,为了简化系统结构,可以省略指挥者Director,指挥者不再指导产品的创建过程。而是在Builder中提供逐步构建复杂产品对象的construct()方法。
暴风影音播放器是具体的产品,实现代码和上一篇博客一样,这里就不再呈现。有变化的是建造者类,播放模式.h头文件实现代码如下:
[cpp] view
plaincopy
#ifndef _PLAY_PATTERN_H_
#define _PLAY_PATTERN_H_
#include <iostream>
#include <string>
#include "Player.h"
using namespace std;
//抽象播放模式
class PlayPattern
{
protected:
//具体产品(播放器)
Player * m_pPlayer;
public:
PlayPattern()
{
m_pPlayer = new Player();
}
~PlayPattern()
{
if( NULL != m_pPlayer )
{
delete m_pPlayer;
m_pPlayer = NULL;
}
}
//制造播放窗口
virtual void BuildWindow() = 0;
//制造播放菜单
virtual void BuildMenu() = 0;
//制造播放列表
virtual void BuildPlayList() = 0;
//制造播放进度条
virtual void BuildControlBar() = 0;
//制造收藏列表
virtual void BuildCollectList() = 0;
//开始建造,封装建造过程
Player * StartConstruct()
{
BuildWindow();
BuildMenu();
BuildPlayList();
BuildControlBar();
BuildCollectList();
return m_pPlayer;
}
};
//完整播放模式
class FullPattern : public PlayPattern
{
public:
void BuildWindow();
void BuildMenu();
void BuildPlayList();
void BuildControlBar();
void BuildCollectList();
};
//精简播放模式
class SimplePattern : public PlayPattern
{
public:
void BuildWindow();
void BuildMenu();
void BuildPlayList();
void BuildControlBar();
void BuildCollectList();
};
//记忆播放模式
class MemoryPattern : public PlayPattern
{
public:
void BuildWindow();
void BuildMenu();
void BuildPlayList();
void BuildControlBar();
void BuildCollectList();
};
#endif
指导者类不再指导暴风影音产品对象的创建过程,而是由抽象播放器模式StartConstruct方法来封装播放器产品的创建过程。
播放模式Cpp文件代码如下:
[cpp] view
plaincopy
#include "PlayPattern.h"
//制造播放窗口
void FullPattern::BuildWindow()
{
m_pPlayer->SetWindow("主界面窗口");
}
//制造播放菜单
void FullPattern::BuildMenu()
{
m_pPlayer->SetMenu("主菜单");
}
//制造播放列表
void FullPattern::BuildPlayList()
{
m_pPlayer->SetPlayList("播放列表");
}
//制造播放进度条
void FullPattern::BuildControlBar()
{
m_pPlayer->SetControlBar("进度条");
}
//制造收藏列表,完整播放模式没有收藏列表,内容设为空
void FullPattern::BuildCollectList()
{
m_pPlayer->SetCollectList(" ");
}
////////////////精简模式///////////////////////////////
void SimplePattern::BuildWindow()
{
m_pPlayer->SetWindow("主界面窗口");
}
void SimplePattern::BuildMenu()
{
m_pPlayer->SetMenu(" ");
}
void SimplePattern::BuildPlayList()
{
m_pPlayer->SetPlayList(" ");
}
void SimplePattern::BuildControlBar()
{
m_pPlayer->SetControlBar("进度条");
}
void SimplePattern::BuildCollectList()
{
m_pPlayer->SetCollectList(" ");
}
/////////////////记忆模式////////////////////////////////
void MemoryPattern::BuildWindow()
{
m_pPlayer->SetWindow("主界面窗口");
}
void MemoryPattern::BuildMenu()
{
m_pPlayer->SetMenu(" ");
}
void MemoryPattern::BuildPlayList()
{
m_pPlayer->SetPlayList(" ");
}
void MemoryPattern::BuildControlBar()
{
m_pPlayer->SetControlBar("进度条");
}
void MemoryPattern::BuildCollectList()
{
m_pPlayer->SetCollectList("收藏列表");
}
完整播放模式下并不需要建造收藏列表部件,因此把收藏列表的内容设为空,其它情况类型,把不需要建造的部件内容设为空。测试程序实现代码如下:
[cpp] view
plaincopy
#include <iostream>
#include "PlayPattern.h"
#include "Player.h"
using namespace std;
int main()
{
Player * pPlayer = NULL;
/***********************完整播放模式************************/
PlayPattern * pFullPattern = new FullPattern();
cout << "完整播放模式:" << endl;
pPlayer = pFullPattern->StartConstruct();
pPlayer->Display();
/***********************精简播放模式************************/
SimplePattern * pSimplePattern = new SimplePattern();
cout << "精简播放模式:" << endl;
pPlayer = pSimplePattern->StartConstruct();
pPlayer->Display();
/***********************记忆播放模式************************/
MemoryPattern * pMemoryPattern = new MemoryPattern();
cout << "记忆播放模式:" << endl;
pPlayer = pMemoryPattern->StartConstruct();
pPlayer->Display();
/***********************销毁操作****************************/
cout << endl;
delete pFullPattern;
pFullPattern = NULL;
delete pSimplePattern;
pSimplePattern = NULL;
delete pMemoryPattern;
pMemoryPattern = NULL;
return 0;
}
编译并执行,结果如下:
此时,StartConstruct()方法定义了其他buildPartX()方法调用的次序,为其他方法的执行提供了一个流程模板,这与我们在后面要学习的模板方法模式非常类似。对Director类的省略方式都不影响系统的灵活性和可扩展性,同时还简化了系统结构,但加重了抽象建造者类的职责,如果StartConstruct()方法较为复杂,待构建产品的组成部分较多,建议还是将StartConstruct()方法单独封装在Director中,这样做更符合“单一职责原则”
4、引入钩子方法的建造者模式
建造者模式除了逐步构建一个复杂产品对象外,还可以通过Director类来更加精细地控制产品的创建过程,例如增加一类称之为钩子方法(HookMethod)的特殊方法来控制是否对某个buildPartX()的调用,也就是判断产品中某个部件是否需要被建造。钩子方法的返回类型通常为boolean类型,方法名一般为isXXX(),钩子方法定义在抽象建造者类中。在抽象建造者类中提供钩子方法的默认实现,具体建造者类如果不需要建造某个部件,则该建造者类覆盖抽象建造者类的钩子方法。
暴风影音播放器是具体的产品,实现代码和C++设计模式之建造者模式(一)博客一样,这里就不再呈现。而抽象播放器模式类中定义了一系列的钩子方法,并提供了默认的实现,用于判断是否需要创建对应的部件。如果具体播放器模式不需要某个部件,则具体播放器模式覆盖对应的钩子方法。
播放模式.h头文件代码如下:
[cpp] view
plaincopy
#ifndef _PLAY_PATTERN_H_
#define _PLAY_PATTERN_H_
#include <iostream>
#include <string>
#include "Player.h"
using namespace std;
//抽象播放模式
class PlayPattern
{
protected:
//具体产品(播放器)
Player * m_pPlayer;
public:
PlayPattern()
{
m_pPlayer = new Player();
}
~PlayPattern()
{
if( NULL != m_pPlayer )
{
delete m_pPlayer;
m_pPlayer = NULL;
}
}
//制造播放窗口
virtual void BuildWindow() = 0;
//制造播放菜单
virtual void BuildMenu() = 0;
//制造播放列表
virtual void BuildPlayList() = 0;
//制造播放进度条
virtual void BuildControlBar() = 0;
//制造收藏列表
virtual void BuildCollectList() = 0;
//获取产品(播放器)
Player * GetPlayer()
{
return m_pPlayer;
}
//是否建造播放窗口(钩子方法)
virtual bool IsBuildWindow()
{
return true;
}
//是否建造播放菜单(钩子方法)
virtual bool IsBuildMenu()
{
return true;
}
//是否建造播放列表(钩子方法)
virtual bool IsBuildPlayList()
{
return true;
}
//是否建造播放进度条(钩子方法)
virtual bool IsBuildControlBar()
{
return true;
}
//是否建造收藏列表(钩子方法)
virtual bool IsBuildCollectList()
{
return true;
}
};
//完整播放模式
class FullPattern : public PlayPattern
{
public:
void BuildWindow();
void BuildMenu();
void BuildPlayList();
void BuildControlBar();
void BuildCollectList();
//完整播放模式不需要建造收藏列表
bool IsBuildCollectList()
{
return false;
}
};
//精简播放模式
class SimplePattern : public PlayPattern
{
public:
void BuildWindow();
void BuildMenu();
void BuildPlayList();
void BuildControlBar();
void BuildCollectList();
//精简播放模式不需要建造播放菜单
bool IsBuildMenu()
{
return false;
}
//精简播放模式不需要建造播放列表
bool IsBuildPlayList()
{
return false;
}
//精简播放模式不需要建造收藏列表
bool IsBuildCollectList()
{
return false;
}
};
//记忆播放模式
class MemoryPattern : public PlayPattern
{
public:
void BuildWindow();
void BuildMenu();
void BuildPlayList();
void BuildControlBar();
void BuildCollectList();
//记忆播放模式不需要建造播放菜单
bool IsBuildMenu()
{
return false;
}
//记忆播放模式不需要建造播放列表
bool IsBuildPlayList()
{
return false;
}
};
#endif
播放器模式Cpp实现代码如下:
[cpp] view
plaincopy
#include "PlayPattern.h"
//制造播放窗口
void FullPattern::BuildWindow()
{
m_pPlayer->SetWindow("主界面窗口");
}
//制造播放菜单
void FullPattern::BuildMenu()
{
m_pPlayer->SetMenu("主菜单");
}
//制造播放列表
void FullPattern::BuildPlayList()
{
m_pPlayer->SetPlayList("播放列表");
}
//制造播放进度条
void FullPattern::BuildControlBar()
{
m_pPlayer->SetControlBar("进度条");
}
//制造收藏列表
void FullPattern::BuildCollectList()
{
m_pPlayer->SetCollectList(" ");
}
////////////////精简模式///////////////////////////////
void SimplePattern::BuildWindow()
{
m_pPlayer->SetWindow("主界面窗口");
}
void SimplePattern::BuildMenu()
{
m_pPlayer->SetMenu(" ");
}
void SimplePattern::BuildPlayList()
{
m_pPlayer->SetPlayList(" ");
}
void SimplePattern::BuildControlBar()
{
m_pPlayer->SetControlBar("进度条");
}
void SimplePattern::BuildCollectList()
{
m_pPlayer->SetCollectList(" ");
}
/////////////////记忆模式////////////////////////////////
void MemoryPattern::BuildWindow()
{
m_pPlayer->SetWindow("主界面窗口");
}
void MemoryPattern::BuildMenu()
{
m_pPlayer->SetMenu(" ");
}
void MemoryPattern::BuildPlayList()
{
m_pPlayer->SetPlayList(" ");
}
void MemoryPattern::BuildControlBar()
{
m_pPlayer->SetControlBar("进度条");
}
void MemoryPattern::BuildCollectList()
{
m_pPlayer->SetCollectList("收藏列表");
}
在暴风影音播放器指导者ContructManage中,调用了一系列的钩子方法,用于判断在不同播放模式下,是否需要创建对应的部件。暴风影音播放器指挥者类.h头文件实现如下:
[cpp] view
plaincopy
#ifndef _CONTRUCT_MANAGE_H_
#define _CONTRUCT_MANAGE_H_
#include "PlayPattern.h"
#include "Player.h"
//建造管理器
class ContructManage
{
private:
//具体建造者
PlayPattern * m_pPlayPattern;
public:
//设计播放器模式(也就是设置具体建造者)
void SetPlayPattern(PlayPattern * pPlayPattern);
//封装建造过程,调用钩子方法,判断对应的部件是否需要建造
Player * Construct();
};
#endif
暴风影音播放器指挥者类Cpp文件实现如下:
[cpp] view
plaincopy
#include "ContructManage.h"
//设计播放器模式(也就是设置具体建造者)
void ContructManage::SetPlayPattern(PlayPattern * pPlayPattern)
{
m_pPlayPattern = pPlayPattern;
}
//封装建造过程,调用一系列钩子方法,判断对应的部件是否需要建造
Player * ContructManage::Construct()
{
bool bRetVal = true;
//根据需要建造播放窗口
bRetVal = m_pPlayPattern->IsBuildWindow();
if( true == bRetVal )
{
m_pPlayPattern->BuildWindow();
}
//根据需要建造播放菜单
bRetVal = m_pPlayPattern->IsBuildMenu();
if( true == bRetVal )
{
m_pPlayPattern->BuildMenu();
}
//根据需要建造播放列表
bRetVal = m_pPlayPattern->IsBuildPlayList();
if( true == bRetVal )
{
m_pPlayPattern->BuildPlayList();
}
//根据需要建造播放进度条
bRetVal = m_pPlayPattern->IsBuildControlBar();
if( true == bRetVal )
{
m_pPlayPattern->BuildControlBar();
}
//根据需要建造收藏列表
bRetVal = m_pPlayPattern->IsBuildCollectList();
if( true == bRetVal )
{
m_pPlayPattern->BuildCollectList();
}
//返回已经建造好的播放器
Player * pPlayer = m_pPlayPattern->GetPlayer();
return pPlayer;
}
测试程序实现代码如下:
[cpp] view
plaincopy
#include <iostream>
#include "ContructManage.h"
#include "PlayPattern.h"
#include "Player.h"
using namespace std;
int main()
{
/***********************创建建造管理器**********************/
ContructManage * pContructManage = new ContructManage();
Player * pPlayer = NULL;
/***********************完整播放模式************************/
PlayPattern * pFullPattern = new FullPattern();
cout << "完整播放模式:" << endl;
pContructManage->SetPlayPattern(pFullPattern);
pPlayer = pContructManage->Construct();
pPlayer->Display();
/***********************精简播放模式************************/
PlayPattern * pSimplePattern = new SimplePattern();
cout << "精简播放模式:" << endl;
pContructManage->SetPlayPattern(pSimplePattern);
pPlayer = pContructManage->Construct();
pPlayer->Display();
/***********************记忆播放模式************************/
PlayPattern * pMemoryPattern = new MemoryPattern();
cout << "记忆播放模式:" << endl;
pContructManage->SetPlayPattern(pMemoryPattern);
pPlayer = pContructManage->Construct();
pPlayer->Display();
/***********************销毁操作****************************/
cout << endl;
delete pFullPattern;
pFullPattern = NULL;
delete pSimplePattern;
pSimplePattern = NULL;
delete pMemoryPattern;
pMemoryPattern = NULL;
delete pContructManage;
pContructManage = NULL;
return 0;
}
编译并执行,结果如下:
通过引入钩子方法,我们可以在建造者指导者类中对复杂产品的构建进行精细的控制,不仅指定buildPartX()方法的执行顺序,还可以控制是否需要执行某个buildPartX()方法。
5、建造者模式总结
建造者模式的核心在于如何一步步构建一个包含多个组成部件的完整对象,使用相同的构建过程构建不同的产品,在软件开发中,如果我们需要创建复杂对象并希望系统具备很好的灵活性和可扩展性可以考虑使用建造者模式。
1.主要优点
建造者模式的主要优点如下:
(1) 在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。建造者模式封装了产品具体的创建流程,符合"封装变化原则"。
(2) 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。由于指挥者类针对抽象建造者编程,增加新的具体建造者无须修改原有类库的代码,系统扩展方便,符合“开闭原则”,也符合"针对抽象进行编程而不是针对具体编程原则"。
(3) 可以更加精细地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。
2.主要缺点
建造者模式的主要缺点如下:
(1) 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,例如很多组成部分都不相同,不适合使用建造者模式,因此其使用范围受到一定的限制。
(2) 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大,增加系统的理解难度和运行成本。
3.建造者模式的具体应用
(1)在游戏角色中,存在魔鬼、天使、英雄等角色。这些角色都包含相同的建造过程(建造头、脚、外观等),而每一个游戏角色建造方法各不相同。
(2)解析XML格式的配置文件时,需要解析配置文件的头部信息、数据体、尾部信息等。可以把解析的三个过程视为建造的三个过程。
(3)解析Rtf文档格式同样存在和解析XML格式的配置文件相同的情况。
(4)我们使用Email发送邮件的是否,需要填写邮件标题、收件人、邮件内容等信息。可以把填写邮件标题、收件人、邮件内容视为三个建造过程。
(5)我们在定义Socket网络通信协议的时候,需要定义数据祯,每祯由包头、包体、包尾组成。这样在通信的双方,就可以按照同样的格式进行收发信息。
(6)使用Gcc编译程序需要经历编译、汇编、链接等过程,最终才能形成可执行程序。
(7)我们使用美图、Photoshop软件美化图像时,得执行一系列操作(锐化、镜像等),最终才有一副绚丽的照片。
(8)在创建对话框程序过程中,会有一个向导提示每一步的创建过程。经历一系列的过程,最终才形成一个对话框。同样,在安装软件的过程中,也会出现向导让我们定制软件的某些外观或者功能。
(9)在定制Linux内核过程中,可以根据需要删减某些不需要的功能模块。定制出一个功能适中的操作系统,俗称内核裁剪,然后把裁剪后的Linux系统移植到嵌入式设备上(ARM等)。
(10)生活中的建造者模式应用: 桥梁建造、三峡工程建造、鸟巢水立方等一系列工程建造;361、安踏、九牧王一系列服装业建造;杂交水稻、转基因大米等粮食建造。
相关文章推荐
- 设计模式C++实现(3)——建造者模式
- C++设计模式实现--建造者
- C++设计模式之建造者模式(三)
- C++设计模式——建造者模式
- C++设计模式-Builder建造者模式
- 设计模式五(建造者模式,采用C++实现)
- 设计模式之建造者模式 c++实现和详细分析
- C++设计模式从0进击-4-建造者模式
- C++设计模式之建造者模式(一)
- 设计模式C++实现九:建造者模式
- c++ 23种设计模式之建造者模式
- 设计模式C++实现(6)——建造者模式
- 设计模式C++描述----07.建造者(Builder)模式
- C++设计模式----建造者模式
- 设计模式C++描述----07.建造者(Builder)模式
- //c++ 23种设计模式之建造者模式2
- C++设计模式之Builder(建造者)模式
- 设计模式C++实现(6)——建造者模式
- 设计模式C++实现(6)——建造者模式
- C++设计模式之建造者模式