消除VISITOR模式中的循环依赖
在我的那篇《VISITOR模式--《敏捷软件开发》读书笔记(三)》中,我用一个C++的小例子说明了设计模式中的VISITOR模式。在例子代码中,我们可以发现:为了使VISITOR类CVisitor通过编译,它就必须知道它要访问的类(CTRectangle,CTSquare,CTCircle, CTText ,CTView )的定义;而这些被访问的类要通过编译,它们必须知道类CVisitor的定义。这样就形成了循环依赖。如下面的类图(带箭头的虚线表示依赖关系): 可以看到,由于循环依赖,visitor类和被访问的类之间的依赖关系都是双向的,这张类图看上去跟蜘蛛网差不多。
class
CVisitor
{ public : virtual ~ CVisitor(){} }; 实际上,这个VISITOR的基类什么都不做,它只是具体类型信息的载体。虽然这样,类CVisitor却非常重要,因为它为VISITOR类提供了RTTI(Run-Time Type Identification)能力。我们可以用dynamic_cast来把CVisitor的指针转换为我们想要的具体的VISITOR类对象的指针。
class
CRectangleVisitor
{ public : virtual void VisitRectangle(CTRectangle * ) = 0 ; }; class CSquareVisitor { public : virtual void VisitSquare(CTSquare * ) = 0 ; }; class CCircleVisitor { public : virtual void VisitCircle(CTCircle * ) = 0 ; }; class CTextVisitor { public : virtual void VisitText(CTText * ) = 0 ; }; class CViewVisitor { public : virtual void VisitView(CTView * ) = 0 ; }; 这些小型的抽象VISITOR类只定义了访问的接口函数,由具体的VISITOR类来实现这些函数。
class
CContext
{ public : virtual ~ CContext(){} virtual void Accept(CVisitor & v) = 0 ; }; class CTRectangle: public CContext { public : void Accept(CVisitor & v) { if (CRectangleVisitor * pVisitor = dynamic_cast < CRectangleVisitor *> ( & v)) pVisitor -> VisitRectangle( this ); } }; class CTSquare: public CContext { public : void Accept(CVisitor & v) { if (CSquareVisitor * pVisitor = dynamic_cast < CSquareVisitor *> ( & v)) pVisitor -> VisitSquare( this ); } }; class CTCircle: public CContext { public : void Accept(CVisitor & v) { if (CCircleVisitor * pVisitor = dynamic_cast < CCircleVisitor *> ( & v)) pVisitor -> VisitCircle( this ); } }; class CTText: public CContext { public : void Accept(CVisitor & v) { if (CTextVisitor * pVisitor = dynamic_cast < CTextVisitor *> ( & v)) pVisitor -> VisitText( this ); } }; class CTView: public CContext { public : ~ CTView() { while ( ! m_vContext.empty()) { CContext * pContext = (CContext * )m_vContext.back(); m_vContext.pop_back(); deletepContext; } } void Accept(CVisitor & v) { for (vector < CContext *> ::iteratori = m_vContext.begin();i != m_vContext.end(); ++ i) { ( * i) -> Accept(v); } if (CViewVisitor * pVisitor = dynamic_cast < CViewVisitor *> ( & v)) pVisitor -> VisitView( this ); } void Add(CContext * pContext) { m_vContext.push_back(pContext); } private : vector < CContext *> m_vContext; }; 上面的代码跟原来的不同之处就是:每个Accept方法里面多了一个if语句。在这个if语句中,通过dynamic_cast将传入的参数visitor转换成我们需要的visitor,然后再调用具体的访问函数。
class
CShowContextVisitor:
public CVisitor, public CRectangleVisitor, public CSquareVisitor, public CCircleVisitor, public CTextVisitor, public CViewVisitor { public : CShowContextVisitor() : m_iRectangleCount(0), m_iSquareCount(0), m_iCircleCount(0), m_iTextCount(0) {} void VisitRectangle(CTRectangle * pRectangle) { cout << " ARectangleisShowed! " << endl; m_iRectangleCount ++ ; } void VisitSquare(CTSquare * pSquare) { cout << " ASquareisShowed! " << endl; m_iSquareCount ++ ; } void VisitCircle(CTCircle * pircle) { cout << " ACircleisShowed! " << endl; m_iCircleCount ++ ; } void VisitText(CTText * pText) { cout << " ATextisShowed! " << endl; m_iTextCount ++ ; } void VisitView(CTView * pView) { cout << " AViewisShowed! " << endl; cout << " Rectanglecount: " << m_iRectangleCount << endl; cout << " Squarecount: " << m_iSquareCount << endl; cout << " Circlecount: " << m_iCircleCount << endl; cout << " Textcount: " << m_iTextCount << endl; } private : int m_iRectangleCount; int m_iSquareCount; int m_iCircleCount; int m_iTextCount; }; 从上面的代码可以看出,这个类CShowContextVisitor跟原来那篇文章中的实现没有区别,唯一的区别就是:它是从VISITOR的基类CVisitor和那些小型的抽象VISITOR类继承的。这样就可以保证在Accept函数中用dynamic_cast可以动态转换为我们需要的具体VISITOR类,从而调用相应的访问函数。 从图中可以看出,原来的循环依赖已经被消除! (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |