为什么'Manager'类中的'getter'方法不是静态的?

时间:2016-06-27 23:56:10

标签: java maintainability

在大多数情况下,传统的编程智慧似乎不鼓励使用静态方法。通常,我有这些'经理',例如UserManager,AppointmentManager e.t.c. 总是,经理中的一种方法是XXX getXXX(long xxxId),例如User getUser(long userId)。 我真的不明白为什么这不能成为静态方法。它看起来非常像工厂方法(la GoF工厂模式)。 很难放弃以下方便:

User user = UserManager.getUser(id);

并使用

UserManager userManager = new UserManager(); User user = userManager.getUser(userId);

代替。

P.S。我相信测试;我不是一个'模拟测试'的粉丝,所以除了嘲笑我还需要理由。

3 个答案:

答案 0 :(得分:6)

避免对象工厂中的静态方法的主要原因是能够保持状态。虽然静态方法可以将其状态保持在静态字段中,但这种方法很难保存和重置工厂的状态。

此外,无法编程到工厂的接口,因为静态方法不能用作接口实现。当您需要将对象的实现透明地切换到应用程序的其余部分时,这一点变得非常重要。

最后,无论是否使用模拟,静态方法都会使测试代码变得更加困难。您的测试很难验证您的工厂的某些方法是按特定顺序调用的。

答案 1 :(得分:1)

我认为Bob叔叔在他的清洁代码书中做了很好的解释(很棒的读btw)。但无论如何,他的观点是你不应该在任何想要利用多态性的地方使用静态(我认为这正是你想要的上述情况)。

在您的情况下,您有一个UserManager。绝不是一个完整的应用程序,对吧?您可能有一些使用UserManager的更复杂的东西。让我们假设你有自己的StackOverflow版本(当然不要这样做,stackoverflow很棒,不需要竞争)。

好的,我们有一个调用UserManager.getUser()的LoginService。这是一种不可改变的依赖性(因为我们不利用多态性)。如果UserManager.getUser()需要底层SQL数据库,那么猜猜你需要运行(或测试)LoginService .... SQL数据库!

public class LoginService {
   public boolean authenticate(String username, String password) {
      User user = UserManager.getUser(username); // hard dependency on implementation
      // other stuff
   }
} 

更普遍的解决方案是抽象可以在界面后面改变的东西。这样你可以换掉实现。 LoginService有一个应该测试的工作,并且实际上不应该依赖于特定的数据库实现。

public interface UserManager {
   User getUser(String id):
}

public class SQLUserManager implements UserManager {
   @Override
   public User getUser(String id) { // SQL stuff }
}

class LoginService {
   public LoginService(UserManager userManager) {
      this.userManager = userManager;
   }

   public boolean authenticate(String username, String password) {
      User user = userManager.getUser(username);
      // other stuff
   }
} 

现在,LoginService可以1)独立于UserManager的使用进行测试,2)如果用户实现发生变化,可以单独进行测试。

不是嘲笑而是测试组件而不需要设置整个应用程序堆栈。

答案 2 :(得分:0)

通常不建议静态保持状态,而是支持使用依赖注入。 正如dasblinkenlight所提到的,静态方法无法实现接口 。 使用静态使得不可能有多个类的实例 如果您需要两个不同的用户管理器指向不同的数据源,您必须进行重大的重新分解。