当前位置:   article > 正文

设计模式的混合使用_设计模式混合使用

设计模式混合使用

设计模式本来就是一些成熟的使用方法,它的方法性和思想超越了具体的语言,在编码中,不是刻意而为的,而是先领会了才能使用,特别是一些模式的混合使用。

比如下面的代码就用到了观察者模式和访问者模式。

mdl的新型API中用了很多的设计模式,比如mdl中C++中的回调基本上多采用观察者模式将用户自定义事件插入到系统的回调函数列表里,比如视图监视器等。。。

  1. #include "stdafx.h"
  2. #include <vector>
  3. #include <string>
  4. #include <list>
  5. #include <stdexcept>
  6. #include <iostream>
  7. #include "temp.h"
  8. #include <boost/smart_ptr.hpp>
  9. #include <boost/lambda/lambda.hpp>
  10. #include <boost/lambda/bind.hpp>
  11. class Element;
  12. class Visitor
  13. {
  14. public:
  15. virtual void visit (Element* el) = 0;
  16. };
  17. class Element
  18. {
  19. public:
  20. virtual void accept (Visitor* visit) = 0;
  21. };
  22. class employee : public Element
  23. {
  24. public:
  25. employee(std::string name):_name(name){}
  26. virtual void accept (Visitor* vis)
  27. {
  28. vis->visit (this);
  29. }
  30. std::string getname()
  31. {
  32. return _name;
  33. }
  34. private:
  35. std::string _name;
  36. };
  37. class VisitorA : public Visitor
  38. {
  39. public:
  40. virtual void visit (Element* el)
  41. {
  42. employee* ep = dynamic_cast<employee*>(el);
  43. if(ep)
  44. {
  45. std::cout << "VisitorA : " << ep->getname ( ) << std::endl;
  46. }
  47. }
  48. };
  49. class VisitorB : public Visitor
  50. {
  51. public:
  52. virtual void visit (Element* el)
  53. {
  54. employee* ep = dynamic_cast<employee*>(el);
  55. if (ep)
  56. {
  57. std::cout << "VisitorB : " << ep->getname ( ) << std::endl;
  58. }
  59. }
  60. };
  61. class employees
  62. {
  63. std::list<employee*> l_emp;
  64. public:
  65. void Attach(employee* emp)
  66. {
  67. l_emp.push_back (emp);
  68. }
  69. void Detach(const employee* emp)
  70. {
  71. l_emp.remove (const_cast<employee*>(emp));
  72. }
  73. void accept(Visitor* vis)
  74. {
  75. using namespace boost::lambda;
  76. std::for_each (l_emp.begin ( ), l_emp.end ( ), bind (&Visitor::visit,vis,_1));
  77. }
  78. };
  79. int _tmain(int argc, _TCHAR* argv[])
  80. {
  81. employees emps;
  82. typedef boost::shared_ptr<employee> employeePtr;
  83. typedef boost::shared_ptr<Visitor> visitorPtr;
  84. employeePtr emp1 = boost::make_shared<employee>("kangshifu");
  85. employeePtr emp2 = boost::make_shared<employee>("lishifu");
  86. emps.Attach (emp1.get());
  87. emps.Attach (emp2.get());
  88. visitorPtr va = boost::make_shared<VisitorA> ( );
  89. visitorPtr vb = boost::make_shared<VisitorB> ( );
  90. emps.accept (va.get());
  91. emps.accept (vb.get());
  92. std::cout << "-----------------------------" << std::endl;
  93. emps.Detach (emp1.get ( ));
  94. emps.accept (va.get ( ));
  95. emps.accept (vb.get ( ));
  96. return 0;
  97. }



现在,我们看一个mdl中的一个实例,这个实例用到了观察者模式和单例模式。

(为了让代码更紧凑,使用了几个Boost组件,但可能增加了阅读的难度)

在mdl中可以用mdlLocate_setFunction挂一个用户函数来响应当选择集的变化event。但可惜的只能使用一个,如果以后想增加更多的事件或者改成另外的事件呢,就的重写这个函数,造成扩展性差,耦合度高。用观察者模式就解决了这个问题.

  1. #include "SelectTool.h"
  2. #include <boost/lambda/lambda.hpp>
  3. #include <boost/lambda/bind.hpp>
  4. #include <boost/shared_ptr.hpp>
  5. #include <boost/make_shared.hpp>
  6. #include <MicroStationAPI.h>
  7. #include <list>
  8. #include <algorithm>
  9. #include <boost/tuple/tuple.hpp>
  10. using namespace Bentley::Ustn;
  11. using namespace Bentley::Ustn::Element;
  12. class eventOnSelectChg
  13. {
  14. public:
  15. virtual void _OnChanged ( ) = 0;
  16. };
  17. class selecttool
  18. {
  19. selecttool ( ) {};
  20. ~selecttool ( ) {};
  21. public:
  22. static selecttool Intance;
  23. static StatusInt select_callbk
  24. (
  25. SelectionSetAction* action,
  26. UInt32 filePos,
  27. DgnModelRefP modelRef
  28. )
  29. {
  30. if(*action == SELECT_SS_CHANGED)
  31. {
  32. using namespace boost::lambda;
  33. std::for_each (Intance.m_evlist.begin ( ),
  34. Intance.m_evlist.end ( ),
  35. bind (&eventOnSelectChg::_OnChanged, _1));
  36. }
  37. return SUCCESS;
  38. }
  39. void install()
  40. {
  41. mdlLocate_setFunction (LOCATE_SELECT_CMD, selecttool::select_callbk);
  42. }
  43. void Attach(eventOnSelectChg* op)
  44. {
  45. m_evlist.push_back (op);
  46. }
  47. void Detach(eventOnSelectChg* op)
  48. {
  49. m_evlist.remove (op);
  50. }
  51. private:
  52. typedef std::list<eventOnSelectChg*> EventList;
  53. EventList m_evlist;
  54. };
  55. selecttool selecttool::Intance;
  56. boost::tuple<ElementId,int> GetFirstEle()
  57. {
  58. ISelectToolR tool = ISelectTool::GetTool ( );
  59. if (ISelectTool::GetTool ( ).IsActive ( ))
  60. {
  61. ElementAgenda agd;
  62. ISelectTool::GetTool ( ).BuildAgenda (agd);
  63. ElemAgendaEntry* entry = agd.GetFirstP ( );
  64. ElementId id = entry->GetElemRef ( )->GetElemID ( );
  65. int type = entry->GetElemRef ( )->GetElemType ( );
  66. return boost::make_tuple (id, type);
  67. }
  68. return boost::make_tuple (0, 0);;
  69. }
  70. class setwintitle : public eventOnSelectChg
  71. {
  72. public:
  73. virtual void _OnChanged ( )
  74. {
  75. ElementId id;
  76. int type;
  77. boost::tie (id, type) = GetFirstEle ( );
  78. char title[128];
  79. sprintf_s (title, 128, "Element ID : %lld", id);
  80. MSWindow* winp = mdlWindow_viewWindowGet (tcb->lstvw);
  81. mdlWindow_titleSet (winp, title);
  82. }
  83. };
  84. boost::shared_ptr<eventOnSelectChg> action0;
  85. extern"C" DLLEXPORT int MdlMain(int argc,char** argv)
  86. {
  87. action0 = boost::make_shared<setwintitle> ( );
  88. selecttool::Intance.Attach (action0.get ( ));
  89. selecttool::Intance.install ( );
  90. return EXIT_SUCCESS;
  91. }

程序实现了一个功能,当用户选择一个元素的时候,取得这个函数的id,并显示在当前视图的title上。如果想增加一个功能,当选择元素的时候,同时还要输出一条消息,来显示它的类型呢。这仅仅需要重新写一个类,从基类继承并将目标代码写到那个唯一的虚函数里来实现它,然后将这个类实例化,再attach即可。如下:


  1. class outputmsg : public eventOnSelectChg
  2. {
  3. public:
  4. virtual void _OnChanged ( )
  5. {
  6. ElementId id;
  7. int type;
  8. boost::tie (id, type) = GetFirstEle ( );
  9. char title[128];
  10. sprintf_s (title, 128, "Element type : %ld", type);
  11. mdlDialog_dmsgsPrint (title);
  12. }
  13. };
  14. boost::shared_ptr<eventOnSelectChg> action0;
  15. boost::shared_ptr<eventOnSelectChg> action1;
  16. extern"C" DLLEXPORT int MdlMain(int argc,char** argv)
  17. {
  18. action0 = boost::make_shared<setwintitle> ( );
  19. selecttool::Intance.Attach (action0.get ( ));
  20. action1 = boost::make_shared<outputmsg> ( );
  21. selecttool::Intance.Attach (action1.get ( ));
  22. selecttool::Intance.install ( );
  23. return EXIT_SUCCESS;
  24. }


如果想在运行的时候,决定使用什么样的功能,可以用mdl的命令号给这两个类Attach或者Detach,即可获得这样的灵活性。

完美的解决方案!


理解了以上的方法,再看MDL API中的那些回调的方法为啥要你继承一个类,实现虚方法,再加入监视器。

下面的代码为简单重构以后的版本,取消的全局变量和个别的函数名:

  1. #include "SelectTool.h"
  2. #include <boost/lambda/lambda.hpp>
  3. #include <boost/lambda/bind.hpp>
  4. #include <boost/shared_ptr.hpp>
  5. #include <boost/make_shared.hpp>
  6. #include <boost/foreach.hpp>
  7. #include <boost/tuple/tuple.hpp>
  8. #include <MicroStationAPI.h>
  9. #include <list>
  10. #include <algorithm>
  11. using namespace Bentley::Ustn;
  12. using namespace Bentley::Ustn::Element;
  13. class ActionOnSelectChg
  14. {
  15. public:
  16. virtual void _OnChanged ( ) = 0;
  17. };
  18. class selecttool
  19. {
  20. selecttool ( ) {};
  21. ~selecttool ( ) {};
  22. public:
  23. typedef boost::shared_ptr<ActionOnSelectChg> ActionType;
  24. static selecttool Instance;
  25. static StatusInt select_callbk
  26. (
  27. SelectionSetAction* action,
  28. UInt32 filePos,
  29. DgnModelRefP modelRef
  30. )
  31. {
  32. if (*action == SELECT_SS_CHANGED)
  33. {
  34. using namespace boost::lambda;
  35. BOOST_FOREACH (EventList::value_type& v, Instance.m_evlist)
  36. {
  37. v->_OnChanged ( );
  38. }
  39. }
  40. return SUCCESS;
  41. }
  42. void install()
  43. {
  44. mdlLocate_setFunction (LOCATE_SELECT_CMD, selecttool::select_callbk);
  45. }
  46. void Attach(ActionType op)
  47. {
  48. Detach (op);
  49. m_evlist.push_back (op);
  50. }
  51. void Detach(ActionType op)
  52. {
  53. m_evlist.remove (op);
  54. }
  55. private:
  56. typedef std::list<ActionType> EventList;
  57. EventList m_evlist;
  58. };
  59. selecttool selecttool::Instance;
  60. boost::tuple<ElementId,int> GetFirstEle()
  61. {
  62. ISelectToolR tool = ISelectTool::GetTool ( );
  63. if (ISelectTool::GetTool ( ).IsActive ( ))
  64. {
  65. ElementAgenda agd;
  66. ISelectTool::GetTool ( ).BuildAgenda (agd);
  67. ElemAgendaEntry* entry = agd.GetFirstP ( );
  68. ElementId id = entry->GetElemRef ( )->GetElemID ( );
  69. int type = entry->GetElemRef ( )->GetElemType ( );
  70. return boost::make_tuple (id, type);
  71. }
  72. return boost::make_tuple (0, 0);;
  73. }
  74. class setwintitle : public ActionOnSelectChg
  75. {
  76. public:
  77. virtual void _OnChanged ( )
  78. {
  79. ElementId id;
  80. boost::tie (id, boost::tuples::ignore) = GetFirstEle ( );
  81. char title[128];
  82. sprintf_s (title, 128, "Element ID : %lld", id);
  83. MSWindow* winp = mdlWindow_viewWindowGet (tcb->lstvw);
  84. mdlWindow_titleSet (winp, title);
  85. }
  86. };
  87. class outputmsg : public ActionOnSelectChg
  88. {
  89. public:
  90. virtual void _OnChanged ( )
  91. {
  92. int type;
  93. boost::tie (boost::tuples::ignore, type) = GetFirstEle ( );
  94. char title[128];
  95. sprintf_s (title, 128, "Element type : %ld", type);
  96. mdlDialog_dmsgsPrint (title);
  97. }
  98. };
  99. extern"C" DLLEXPORT int MdlMain(int argc,char** argv)
  100. {
  101. selecttool::ActionType action0 = boost::make_shared<setwintitle> ( );
  102. selecttool::Instance.Attach (action0);
  103. selecttool::ActionType action1 = boost::make_shared<outputmsg> ( );
  104. selecttool::Instance.Attach (action1);
  105. selecttool::Instance.install ( );
  106. return EXIT_SUCCESS;
  107. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/662312
推荐阅读
相关标签
  

闽ICP备14008679号