【原创&交流】Comamnd模式和Factory模式在一次代码重构中的应用
如何应用设计模式,是一个见仁见智的问题,可能也没有一定之规。以我的水平也谈得不一定好。前段时间重构了公司软件中的二维图形交互方面的代码,总结了一些经验供大家分享,期待起一个抛砖引玉的作用。
该软件是基于MFC界面框架开发的。MFC的Doc-View架构本质上是一种MVC架构。随着软件功能开发越来越多,图形的二维显示及各种浏览命令、编辑命令的实现集中在视图类(即View)。视图类的代码越来用臃肿(将近上万行的代码),它的维护更新和升级以后都将大成问题。一个例证就是在各种键盘鼠标消息响应函数写无数的case分支语句来处理各种命令,类似于:
void CMyView::OnLButtonDown(){ switch(m_Cmd) { case Cmd_Browse: { …… break; } case Cmd_Draw_Line: { …… break; } default: break; }}
void CDrawView::OnLButtonDown(UINT nFlags, CPoint point){ if (!m_bActive) return; CDrawTool* pTool = CDrawTool::FindTool(CDrawTool::c_drawShape); if (pTool != NULL) pTool->OnLButtonDown(this, nFlags, point);}void CDrawView::OnLButtonUp(UINT nFlags, CPoint point){ if (!m_bActive) return; CDrawTool* pTool = CDrawTool::FindTool(CDrawTool::c_drawShape); if (pTool != NULL) pTool->OnLButtonUp(this, nFlags, point);}void CDrawView::OnMouseMove(UINT nFlags, CPoint point){ if (!m_bActive) return; CDrawTool* pTool = CDrawTool::FindTool(CDrawTool::c_drawShape); if (pTool != NULL) pTool->OnMouseMove(this, nFlags, point);}
// 图形类型枚举变量enum DrawShape{ selection, line, rect, roundRect, ellipse, poly};// 绘制工具基类class CDrawTool{// Constructorspublic: CDrawTool(DrawShape nDrawShape);// Overridables virtual void OnLButtonDown(CDrawView* pView, UINT nFlags, const CPoint& point); virtual void OnLButtonDblClk(CDrawView* pView, UINT nFlags, const CPoint& point); virtual void OnLButtonUp(CDrawView* pView, UINT nFlags, const CPoint& point); virtual void OnMouseMove(CDrawView* pView, UINT nFlags, const CPoint& point); virtual void OnEditProperties(CDrawView* pView); virtual void OnCancel();// Attributes DrawShape m_drawShape; static CDrawTool* FindTool(DrawShape drawShape); static CPtrList c_tools; static CPoint c_down; static UINT c_nDownFlags; static CPoint c_last; static DrawShape c_drawShape;};// 绘制矩形类class CRectTool : public CDrawTool{// Constructorspublic: CRectTool(DrawShape drawShape);// Implementation virtual void OnLButtonDown(CDrawView* pView, UINT nFlags, const CPoint& point); virtual void OnLButtonDblClk(CDrawView* pView, UINT nFlags, const CPoint& point); virtual void OnLButtonUp(CDrawView* pView, UINT nFlags, const CPoint& point); virtual void OnMouseMove(CDrawView* pView, UINT nFlags, const CPoint& point);};
CDrawTool* CDrawTool::FindTool(DrawShape drawShape){ POSITION pos = c_tools.GetHeadPosition(); while (pos != NULL) { CDrawTool* pTool = (CDrawTool*)c_tools.GetNext(pos); if (pTool->m_drawShape == drawShape) return pTool; } return NULL;}
enum cmd_type{ Cmd_NoOpertin, // 无操作 Cmd_ViewAll, // 全图显示 …};// 命令类基类class CBaseComand{ public: CBaseComand(CMyView *pView); virtual ~ CBaseComand(); virtual void Execute(); // 外部调用方法 //private: CMyView *pView; // 保存视图类指针,方便访问视图类的数据}class CViewAllCmd : public CBaseComand{ public: CViewAllCmd(CMyView *pView); virtual ~ CViewAllCmd (); void Execute(); // 外部调用方法 //private: CMyView *pView; // 保存视图类指针,方便访问视图类的数据}
CBaseComand* CCmdFactory::CreateCmd(CMyView *pView,cmd_type type){ switch(type) { case Cmd_ViewAll: return new CViewAllCmd(pView); …… }}