什么时候停止封装?

时间:2008-11-01 17:47:48

标签: oop encapsulation

我在边界类上有一些事件处理程序,它管理给定泛型事务的持久性机制:

void MyBoundaryClass::MyEventHandler(...)
{
  //retrieve stuff from the UI
  //...
  //declare and initialize trasaction to persist
  SimpleTransaction myTransaction(.../*pass down stuff*/);
  //do some other checks
  //...
  //declare transaction persistor
  TransactionPersistor myPersistor(myTransaction, .../*pass down connection to DB and other stuff*/);
  //persist transaction
  try
  {
    myPersistor.Persist();
  }
  catch(...)
  {
    //handle errors
  }
}

使用某种TransactionManager来包装SimpleTransaction和TransactionPErsistor对象会更好吗?

是否有任何有用的经验法则可以理解我是否需要更高级别的封装?

目前我遵循的经验法则是“如果方法变得太大 - 做一些事情”。在处理边界事件处理程序时,有时很难在程序和面向对象之间找到适当的平衡。

有什么意见吗?

干杯

3 个答案:

答案 0 :(得分:3)

考虑到:

  • concept of encapsulation是关于定义容器的,
  • 面向对象设计基于消息传递的概念(方法的调用)

我认为 API 是一个很好的指示,表明新的高级封装的相关性(即新对象的定义)

如果这个新对象提供的服务(即API)是连贯的,并且在重新分组到一个特殊对象时更好地暴露给程序的其余部分,那么无论如何都要使用新对象。

否则,很可能是矫枉过正。

由于您通过创建新对象来展示 公共 API,因此测试的概念在该新对象中可能更容易实现(和其他一些模拟对象),而不是创建许多遗留对象来测试那些相同的操作。

在您的情况下,如果要测试事务,则必须实际测试MyBoundaryClass的MyEventHandler,以便从UI中检索数据。

但是,如果您定义了一个TransactionManager,那么您将有机会降低MyBoundaryClass中存在的不同架构级别的耦合(GUI与数据),并将数据管理导出到专用类中。登记/> 然后,您可以在独立测试场景中测试数据持久性,尤其关注限制值,数据库故障和非标称条件等。

测试场景可以帮助您优化不同对象的内聚Daok提到的重点)。如果您的测试简单且连贯,那么您的对象可能具有明确定义的服务边界。

因为可以认为Coupling and Cohesion are two cornerstones of OO Programming,所以可以根据它将要执行的一组动作来评估像TransactionManager这样的新类的内聚。

  

凝聚力意味着某个类执行一组密切相关的操作。另一方面,缺乏凝聚力意味着一个班级正在执行几个不相关的任务。随着越来越多的行为变得分散并最终出现在错误的地方,应用软件最终将变得无法管理。

如果您将在几个不同位置实现的行为重新组合到您的TransactionManager中,它应该没问题,只要它的公共API代表交易所涉及的明确步骤而不是像各种效用函数那样的“关于事务的东西”。一个名称本身不足以判断一个阶级的凝聚力。需要组合名称及其公共API。

例如,TransactionManager的一个有趣方面是完全封装Transaction的概念,即:

  • 几乎不为系统的其余部分所知,并且会降低其他类与“交易”之间的耦合
  • 通过围绕事务步骤(如initTransaction(),persistTransaction(),...)集中其API来强化TransactionManager的凝聚力,避免任何事务实例的任何getter或setter。

答案 1 :(得分:2)

阐述VonC的建议,请考虑以下准则:

  • 如果您希望在其他地方以相同的方式调用相同的函数,则将它们封装在新对象中是合理的。

  • 如果一个函数(或一个对象)提供了一组单独使用的工具,则将其重构为较小的组件是合理的。

VonC关于API的观点是一个很好的试金石:创建有效的接口对象经常变得明显。

答案 2 :(得分:1)

封装级别应直接链接到对象的内聚。您的对象必须执行单个任务,或者必须分成多个类并封装其所有行为和属性。

经验法则是时候测试你的对象了。如果您正在进行单元测试,并且您意识到您正在测试多个不同的东西(不是在相同的区域操作中),那么您可能会尝试将其拆分。

对于你的情况,我会用你对“TransactionManager”的想法进行封装。这样“TransactionManager”将处理事务的工作方式,而不是“MyBoundaryClass”。