CATEGORY / Development

应用工厂模式解决实际问题

Permanent Link: http://wutiam.net/notes/84

我前段时间去面试时的一道题目,问题如下:

有一个脚本文件,每行有一句指令或空行,指令格式:

Command[,Param[,Value]]

其中Parameter 和 Value 非必须。设计一套解析指令的类,高效且易于扩展(尽可能降低代码内部耦合性)。

当时虽然都想到了,不过满脑混沌,没有完整明白地表达出来。本来想去公司再看看代码是怎么实现的,昨天在网上闲逛的时候忽然看到了这篇笔记,那就顺便也整理了下自己的思路,结合实际温故理论。

假设有“移动(Move)”、“攻击(Attack)”等几个指令;建立一个工厂类,并将所有指令类预先注册到工厂中,由工厂调用每个指令类的静态成员函数 CreateInstance() 来实现指令类实例的创建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
class Command
{
public:
    virtual ~Command(void) {}
 
    virtual void Excute(void) = 0;
 
protected:
    Command(const std::string& strParam, const std::string& strValue)
        : m_strParam(strParam)
        , m_strValue(strValue)
    {
    }
 
private:
    // this constructor is prohibited
    Command(void) {}
 
private:
    std::string m_strParam;
    std::string m_strValue;
};
 
class CmdMove : public Command
{
public:
    // static member function used by factory
    static Command* CreateInstance(const std::string& strParam, const std::string& strValue)
    {
        return (Command*)new CmdMove(strParam, strValue);
    }
 
    virtual ~CmdMove(void) {}
 
    virtual void Excute(void)
    {
        // TODO
    }
 
protected:
    CmdMove(const std::string& strParam, const std::string& strValue)
        : Command(strParam, strValue)
    {
        // TODO
    }
 
private:
    CmdMove(void) {}
};
 
class CmdAttack : public Command
{
public:
    static Command* CreateInstance(const std::string& strParam, const std::string& strValue)
    {
        return (Command*)new CmdAttack(strParam, strValue);
    }
 
    virtual ~CmdAttack(void) {}
 
    virtual void Excute(void)
    {
        // TODO
    }
 
protected:
    CmdAttack(const std::string& strParam, const std::string& strValue)
        : Command(strParam, strValue)
    {
        // TODO
    }
 
private:
    CmdAttack(void) {}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// the format of the function used by factory
typedef Command* (*CreateCmdInstanceFunc)(const std::string&);
 
class CommandFactory
{
public:
    static CommandFactory* GetInstance(void)
    {
        static CommandFactory cfInstance;
 
        return &cfInstance;
    }
 
    virtual ~CommandFactory(void) {}
 
    void RegCommand(std::string& strCmdName, CreateCmdInstanceFunc func)
    {
        m_mapCommands[strCmdName] = func;
    }
 
    void ExcuteCommand(const std::string& strCmdName, const std::string& strParam, const std::string& strValue)
    {
        Command* pCmd = m_mapCommands[strCmdName](strParam, strValue);
 
        pCmd->Excute();
 
        delete pCmd; pCmd = NULL;
    }
 
private:
    CommandFactory(void) {}
 
private:
    std::map m_mapCommands;
};

由于工厂类同时使用了单例模式(Singleton),在应用程序的预处理阶段通过调用:

1
CommandFactory::GetInstance()->RegCommand(std::string("MOVE"), CmdMove::CreateInstance);

便可完成指令的注册。在脚本文件解析阶段通过调用:

1
CommandFactory::GetInstance()->ExcuteCommand(strCmdName, strParam, strValue);

便可完成对应指令的操作。

以上代码不包含容错处理,不足在于所有 Command 的子类都需要约定定义一个静态类成员函数(CreateInstance())用于该指令实例的创建,不知是否还有更完美的解决方案?

2 Comments / Trackbacks / Pingbacks

Leave a Reply

:) :wink: 8-O :lol: :-D 8) :-| :mrgreen: :oops: :-o :-? :( :twisted: :cry: more »