将大型方法分解为较小方法时适当的访问级别实践?

时间:2011-07-19 20:02:21

标签: java class-design

所以我是一个相对较新的程序员,我还在学习,并遇到了一些问题(如果我的标签稍微偏离,那么道歉)。在早期,我有机会阅读一篇文章,讨论将包含大量代码的方法分解为许多较小的,明确命名的方法的调用的优点。总的来说,我觉得这样做的代码看起来更整洁,并且确保单元测试更容易。但是,我对是否将所有这些新方法公开或私有都有些担忧。将它们设为私有似乎是正确的做法,因为其余的代码通常不需要访问这些方法。但是,单元测试私有方法可能会很混乱。这是最好的做法吗?

我现在在做什么:

 public class WashingMachine {
      public Load wash(Load load) {
           // Removes one sock from load
           for (ClothingItem item : load.getItems()) {
                if (item.getType().equalsIgnoreCase("sock") {
                     load.removeItem(item);
                     .. // logic for sending sock to proper dimension
                     break;
                }
           }
           // rest of logic for cleaning clothes
      }
 }

变成:

 public class WashingMachine {
      // Wash a load of laundry
      public Load wash(Load load) {
           // Removes one sock from load
           removeSock(load.getItems());
           // rest of logic for cleaning clothes
           ..
      }

      // Oh no, I can't unit test this easily!
      private void removeSock(List<ClothingItem> items) {
           ...
      }
 }

2 个答案:

答案 0 :(得分:5)

将您的公共方法视为您希望允许任何人使用的功能。

这些功能中的一些可能很复杂,而且你是对的,该功能应该分成不同的方法。问题是,“他们有什么样的访问权限?”

好吧,如果它们是公开的,现在外部类可以访问您真正不需要的内部功能。即使它不会破坏任何东西,当你开始处理大型项目(拥有更大的团队)时,通过公开它,其他程序员可能会使用该功能,这现在阻止你改变它。

例如,以汽车类比。假设您的方法是accelerate()。这可能会调用releaseGas()。但是,您不希望任何人在外部释放气体。它只应在受控环境中调用。

然后是受保护的访问权限。受保护的访问权限适用于可以通过扩展类来覆盖的方法。这些应该是执行与内部功能相关的特定工作块的方法。再次以汽车为例,可能会有使用特殊类型气体的RaceCar clas,因此它希望提供自己的释放气体的方法。这是releaseGas受保护的原因。

至于测试,你应该主要测试你的公共合同。这是其他课程使用的,最后,这才是真正重要的。您的内部方法是您的功能的内部方法,将通过测试您的公共合同进行测试。这也意味着您的类应首先根据其外部用途进行设计,并围绕该类进行测试。 (即使采用测试驱动的开发,随着您获得经验,这也会变得更容易。)

当然,有时这些内部方法足够复杂,他们需要自己进行单元测试。但是,您不需要对它们进行保护。在这种情况下,您可以将它们设为默认访问权限。 (既不公开也不受保护)。只要您的单元测试在同一个包中,您就可以调用它们。

更好的是,如果您知道您不希望任何人扩展它,但您需要对其进行测试,请将其设为protected final或仅final。这仍然允许调用它,但至少可以防止它被覆盖。

编辑:

Ryan的评论如下。如果你的类变得足够复杂,需要测试它的内部方法,那么它们应该被提取到它们自己的类中,然后可以独立地进行单元测试。

总的来说,您的测试应该是测试您单独单位的公共合同。

答案 1 :(得分:1)

我认为你应该根据将要调用它的(主要的,不是测试的)代码来设计你的类。如果没有人需要拨打WashingMachine.removeSock(),我会留下private

对于单元测试,确定这意味着你无法在WashingMachine内测试这一个单独的逻辑 - 但你仍然可以测试wash()方法,如果这就是使用WashingMachine的其他组件可见,您真正需要关注的是测试。

可以编写粒度的单元测试并关注细节。