你的IMainCtrl看起来似乎是界面事件的接收器。CUIFactory创建界面,界面把事件传递到IMainCtrl,IMainCtrl再把时间传递到IPlayer,然后每一种IPlayer实现不同的音乐格式的播放。
不过CPlayerFactory和IPlayer那么设计似乎有点不妥,不知道是不是我对你的图的理解有偏差。我的意见是这样的:因为你的每一种IPlayer的实现是对应于一种文件格式的,但是文件格式需要将文件读进来之后才知道。这里有两种情况:1、你通过扩展名来判断;2、你通过文件的前几个字节来判断。我推荐第二种。
那么这个情况下,你需要的是一个映射,将文件的前若干个字节对应到一种IPlayer的实现上。那么你的CPlayerFactory就不应当那么设计。你的每一种IPlayer都要有一个规格相同的创建函数(普通函数)或者一个继承了IPlayerCreator的全局对象(可以是static),然后你将每一种创建函数或IPlayerCreator绑定到一个扩展名或文件的前若干个字节上面。然后CPlayerFactory通过检查文件名或读入文件的前几个字节来判断究竟要使用哪一种IPlayerCreator,最后才使用IPlayerCreator创建IPlayer。
那么这里我稍微做一下图:
class IPlayer
{
public:
virtual void Load(string FileName);
/*Play SetPosition Reset Pause等操作*/
virtual IPlayerCreator* GetCreator();/*GetCreator返回的是一个全局对象,只要是相同的IPlayer就返回相同的IPlayerCreator。主要用于当prototype或者释放自己用*/
};
class IPlayerCreator
{
public:
virtual IPlayer* CreatePlayer();
virtual void DestroyPlayer(IPlayer* Player);
/*Test函数通过阅读文件的内容(已经填入Buffer,可以不完全填入)来判断IPlayerCreator所创建的IPlayer是否能够播放这种文件*/
virtual bool Test(void* Buffer);
};
class CPlayerFactory
{
public:
/*注册一种PlayerCreator*/
void Register(IPlayerCreator* Creator);
/*通过文件来选择IPlayerCreator,这里使用责任链模式依次测试所有IPlayerCreator直到IPlayerCreator::Test返回true*/
IPlayerCreator* SelectCreator(string FileName);
};
这是我的观点,这种做法可以解决你『不能通过文件来构造Player』的弱点。
回复 更多评论