Active Object模式

点击打开链接

Active Object模式通常和command命令模式一起使用。这是一个非常古老的模式。我们先来看一个例子。

[cpp]  view plain copy
  1. // Test.cpp : Defines the entry point for the console application.  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5.   
  6. #include <list>  
  7. #include <memory>  
  8.   
  9. class Command  
  10. {  
  11. public:  
  12.     virtual void exec() = 0;  
  13. };  
  14.   
  15. class Copy : public Command  
  16. {  
  17. public:  
  18.     virtual void exec() override  
  19.     {  
  20.         printf("Do copy...\n");  
  21.     }  
  22. };  
  23.   
  24. class Move : public Command  
  25. {  
  26. public:  
  27.     virtual void exec() override  
  28.     {  
  29.         printf("Do move...\n");  
  30.     }  
  31. };  
  32.   
  33. class ActiveObjectEngine  
  34. {  
  35. public:  
  36.     void addCommand(std::unique_ptr<Command> cmd)  
  37.     {  
  38.         m_Commands.push_back(std::move(cmd));  
  39.     }  
  40.   
  41.     void run()  
  42.     {  
  43.         while (!m_Commands.empty())  
  44.         {  
  45.             const std::unique_ptr<Command>& cmd = m_Commands.front();  
  46.             cmd->exec();  
  47.             m_Commands.pop_front();  
  48.         }  
  49.     }  
  50. private:  
  51.     std::list<std::unique_ptr<Command>> m_Commands;  
  52. };  
  53.   
  54. int _tmain(int argc, _TCHAR* argv[])  
  55. {  
  56.     std::unique_ptr<Command> c1(new Copy());  
  57.     std::unique_ptr<Command> c2(new Move());  
  58.   
  59.     ActiveObjectEngine engine;  
  60.   
  61.     engine.addCommand(std::move(c1));  
  62.     engine.addCommand(std::move(c2));  
  63.   
  64.     engine.run();  
  65.   
  66.     return 0;  
  67. }  

上面的代码基本分两部分:

1. Command类

2. ActiveObjectEngine类

ActiveObjectEngine里面维护了一个列表,存放所有的Command,在run()函数里面,把每一个命令都运行一遍,然后删除。

那么这么做有什么作用呢?

比如,我们想是想一个SleepCommand总是延迟一定时间后执行。我们先尝试搞一个SleepCopy类:

[cpp]  view plain copy
  1. class SleepCopy : public Command  
  2. {  
  3. public:  
  4.     SleepCopy(ActiveObjectEngine& e, DWORD dwDelay) : m_Engine(e), m_dwStartTime(0), m_dwDelay(dwDelay)  
  5.     {}  
  6.   
  7.     SleepCopy(const SleepCopy& cmd) : m_Engine(cmd.m_Engine), m_dwStartTime(cmd.m_dwStartTime), m_dwDelay(cmd.m_dwDelay)  
  8.     {  
  9.     }  
  10.   
  11.     virtual void exec() override  
  12.     {  
  13.         if (m_dwStartTime == 0)  
  14.         {  
  15.             m_dwStartTime = ::GetTickCount();  
  16.             std::unique_ptr<Command> newCmd(new SleepCopy(*this));  
  17.             m_Engine.addCommand(std::move(newCmd));  
  18.         }  
  19.         else  
  20.         {  
  21.             DWORD dwUsed = ::GetTickCount() - m_dwStartTime;  
  22.             if (dwUsed >= m_dwDelay)  
  23.             {  
  24.                 printf("Do sleep copy..., delayed: %d ms\n", dwUsed);  
  25.             }  
  26.             else  
  27.             {  
  28.                 std::unique_ptr<Command> newCmd(new SleepCopy(*this));  
  29.                 m_Engine.addCommand(std::move(newCmd));  
  30.             }  
  31.         }  
  32.     }  
  33. private:  
  34.     DWORD m_dwStartTime;  
  35.     DWORD m_dwDelay;  
  36.     ActiveObjectEngine& m_Engine;  
  37. };  

这个类比前面两个Command略显复杂。主要思想就是,保存一个起始时间,然后在exec函数里面,来检查一下,如果已经到了延时的时间,那么就触发动作,如果没有,那么就创建一个新的command放到ActiveObject对象里面。这样,ActiveObjectEngine的run函数又会跑一次。直到最终延时时间到,触发动作为止。


其实,我们仔细看一下上面的代码,ActiveObjectEngine就是循环依次调用Command。每次调用完毕,就把对应的command对象从列表里面删除。

如果某个对象需要多次被调用,那么可以在exec函数里面处理一下,比如上面的SleepCopy用到的技巧。反正关键就是,如果想到ActiveObjectEngine再调用一次,那么就往它的列表里面插入一个对象。

从ActiveObjectEngine的角度来看,就是每次调用完对象exec()后,就删除,然后对象的exec()可以自己根据情况处理,如果需要再调用一次,那么就再往ActiveObjectEngine里面增加一个对象(或者重新加入当前对象)。

整个过程都是单线程,从每个Command对象来看,其实是可以实现每次调用只处理一部分工作,然后再把对象加入Engine,等待下一次处理。这就好比是用单线程模拟了多线程环境。每次循环都处理掉一部分工作,直到所有任务完成,Engine也就完成目的了。

ActiveObject模式可以很好的时候命令的轮询工作,然后可以在单线程环境里面实现多线程(多任务)的功能。很古老又很好用的一种思想,很多地方可以使用它。值得好好研究一下。在某些场合有意想不到的效果。起码模拟出来的多线程是运行在单线程环境里面的,这可以减少很多因为多线程环境带来的问题,比如同步。。。

完整代码:

[cpp]  view plain copy
  1. // Test.cpp : Defines the entry point for the console application.  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5.   
  6. #include <list>  
  7. #include <memory>  
  8. #include <windows.h>  
  9.   
  10. class Command  
  11. {  
  12. public:  
  13.     virtual void exec() = 0;  
  14. };  
  15.   
  16. class ActiveObjectEngine  
  17. {  
  18. public:  
  19.     void addCommand(std::unique_ptr<Command> cmd)  
  20.     {  
  21.         m_Commands.push_back(std::move(cmd));  
  22.     }  
  23.   
  24.     void run()  
  25.     {  
  26.         while (!m_Commands.empty())  
  27.         {  
  28.             const std::unique_ptr<Command>& cmd = m_Commands.front();  
  29.             cmd->exec();  
  30.             m_Commands.pop_front();  
  31.         }  
  32.     }  
  33. private:  
  34.     std::list<std::unique_ptr<Command>> m_Commands;  
  35. };  
  36.   
  37. class Copy : public Command  
  38. {  
  39. public:  
  40.     virtual void exec() override  
  41.     {  
  42.         printf("Do copy..., tick count: %d\n", ::GetTickCount());  
  43.     }  
  44. };  
  45.   
  46. class Move : public Command  
  47. {  
  48. public:  
  49.     virtual void exec() override  
  50.     {  
  51.         printf("Do move..., tick count: %d\n", ::GetTickCount());  
  52.     }  
  53. };  
  54.   
  55. class SleepCopy : public Command  
  56. {  
  57. public:  
  58.     SleepCopy(ActiveObjectEngine& e, DWORD dwDelay) : m_Engine(e), m_dwStartTime(0), m_dwDelay(dwDelay)  
  59.     {}  
  60.   
  61.     SleepCopy(const SleepCopy& cmd) : m_Engine(cmd.m_Engine), m_dwStartTime(cmd.m_dwStartTime), m_dwDelay(cmd.m_dwDelay)  
  62.     {  
  63.     }  
  64.   
  65.     virtual void exec() override  
  66.     {  
  67.         if (m_dwStartTime == 0)  
  68.         {  
  69.             m_dwStartTime = ::GetTickCount();  
  70.             std::unique_ptr<Command> newCmd(new SleepCopy(*this));  
  71.             m_Engine.addCommand(std::move(newCmd));  
  72.         }  
  73.         else  
  74.         {  
  75.             DWORD dwUsed = ::GetTickCount() - m_dwStartTime;  
  76.             if (dwUsed >= m_dwDelay)  
  77.             {  
  78.                 printf("Do sleep copy..., delayed: %d ms\n", dwUsed);  
  79.             }  
  80.             else  
  81.             {  
  82.                 std::unique_ptr<Command> newCmd(new SleepCopy(*this));  
  83.                 m_Engine.addCommand(std::move(newCmd));  
  84.             }  
  85.         }  
  86.     }  
  87. private:  
  88.     DWORD m_dwStartTime;  
  89.     DWORD m_dwDelay;  
  90.     ActiveObjectEngine& m_Engine;  
  91. };  
  92.   
  93.   
  94.   
  95. int _tmain(int argc, _TCHAR* argv[])  
  96. {  
  97.     ActiveObjectEngine engine;  
  98.   
  99.     std::unique_ptr<Command> c1(new Copy());  
  100.     std::unique_ptr<Command> c2(new Move());  
  101.     std::unique_ptr<Command> c3(new SleepCopy(engine, 5000));  
  102.   
  103.     engine.addCommand(std::move(c1));  
  104.     engine.addCommand(std::move(c2));  
  105.     engine.addCommand(std::move(c3));  
  106.   
  107.     engine.run();  
  108.   
  109.     return 0;  
  110. }  

猜你喜欢

转载自blog.csdn.net/chexlong/article/details/46516981
今日推荐