MFC最佳实践和模块化

时间:2012-10-26 19:06:23

标签: c++ oop winapi modularity

在MFC中,提供的某些机制允许程序员绕过模块化和封装以及信息隐藏,这可以说是面向对象框架最理想的特性。

其中一个(众多)示例是Owner Draw控件: 您可以选择在子控件子类中实现DrawItem并在该子类中执行该控件的所有绘制,使其看起来更模块化:

class CustomButton: CButton{
     // --- Lots of stuff, DECLARE_DYNAMIC etc

     virtual void DrawItem(LPDRAWITEMSTRUCT lpdis){
          // Drawing code for this button in the button's subclass
     }
};

...或者您可以选择通过OnDrawItem处理父窗口类中的WM_DRAWITEM消息

class MainFrame: CFrameWnd{
     // --- Lots of stuff, DECLARE_DYNAMIC etc

     CustomButton button; 

     afx_msg void OnDrawItem(LPDRAWITEMSTRUCT lpdis, UINT id){

          if(id == CUSTOM_BUTTON_ID){     
               // Drawing code for this button in the button's subclass
          }
     }
};

在后面的情况中,控件的绘制在控件子类之外,这意味着"OOP data structures tend to carry their own operators around with them"被破坏的概念..对吗?

所以我的问题是:哪一个被认为是'最佳实践'?必须存在第二个存在的原因 - 任何人都可以提出一种破坏模块化将是更好选择的情况吗?

2 个答案:

答案 0 :(得分:1)

这个问题似乎在问,什么时候让一个包含一个或多个子对象的父对象来处理针对孩子的消息,而不是仅仅将消息传递给让孩子处理它的孩子。< / p>

具体示例是MFC窗口类,其中包含其他窗口对象(在本例中为按钮)的窗口对象正在处理绘制消息,而不是仅将消息传递给要处理的子对象。

基本答案取决于它。在某些情况下,您可能正在编写一个窗口对象,并且作为其中一部分,您正在使用子控件的绘制行为,以便更改子控件的外观。例如,如果您有一组按钮,您希望根据父窗口中的信息更改其外观,则可能需要覆盖子控件的绘图以更改外观。

这类似于通过允许父窗口向子控件提供绘图对象而具有允许多种不同类型的外观的按钮对象。结果是孩子会有一个默认的绘画行为,父母会通过提供绘图对象而过度骑行。

请参阅此article in wikipedia on the Strategy pattern或此article on Strategy pattern with side links for other patterns,其中提供了有关此类编程问题的简要讨论。另一个例子可能是Chain of Responsibility pattern

在这个具体的例子中,父母不是向孩子提供绘图描述对象,而是仅仅截取绘图消息并自己进行绘图。

如果可以在不影响子控件的其他功能的情况下更改子控件的外观,那么这不会是一个糟糕的方法,尽管它可能会使正在进行维护或其他更改的程序员感到困惑。然而,在其他情况下可以看到这种过度骑行行为,例如窗口裁剪,其中裁剪某些窗口组件的绘图,以便不绘制将在窗口区域之外的组件的任何部分。

因此,让父对象拦截并处理以父对象的子对象为目标的消息的方法提供了很大的灵活性,允许各种父母根据父母想要完成的内容来改变孩子的特定行为。

然而,这种灵活性确实有代价。

答案 1 :(得分:-1)

如果在第二种情况下,CUSTOM_BUTTON_ID是控件内部使用的某些数据,那么这将是次优的OOP。这违反了David Parnas所定义的信息隐藏概念(http://www.cs.umd.edu/class/spring2003/cmsc838p/Design/criteria.pdf)。如果内部信息发生变化,父窗口将受到更改的影响,并且本身需要更改为匹配。这就是信息隐藏促进模块化的方式;它将数据与需要它的东西捆绑在一起(并将其隐藏在那些不需要它的东西中)。

根据评论,这是一个不好的例子,因为没有违反信息隐藏的情况,因为CUSTOM_BUTTON_ID实际上是父窗口包含和使用的数据,而不是控件。控件的绘制仍在控件内完成;父窗口只调用控件的Draw方法。

相关问题