使用静态类替代客户端工厂或依赖注入和gin?

3
在GWT MVP中,我的Presenter通常有很多私有成员(事件总线、RPC、使用GWT.create()创建的消息包等)。我们一直在使用“ClientFactory”来生成视图作为单例,这样它们就不会在每次需要时重新创建。该工厂还可以提供RPC、事件总线和其他资源。
我可以在GWT doc中阅读到,该工厂的主要目的是通过应用程序访问所需的对象。使用ClientFactory的第二个优点是,您可以将其与GWT延迟绑定一起使用,以根据user.agent或其他属性使用不同的实现类。 我的问题是:如果我不需要也从未需要使用deferred binding的不同实现来创建工厂,那么我是否可以仅使用静态类和方法来检索我的依赖项,而不是使用客户端工厂或Gin?我无法真正理解Gin相比于这种解决方案的优势,也不知道在某些(并非显而易见的)情况下它会否给我带来麻烦。我通常会避免在服务器端代码中使用静态类,因为它是多线程的,但在客户端单线程的代码中,我看不出会出现问题。然而,似乎大多数人都使用Gin或其他解决方案...
1个回答

3
static的问题并不在于线程,而是全局状态和单例模式。在GWT中使用MVP的主要原因之一是为了能够在无需依赖浏览器环境的情况下测试您的Presenter,因为它们不会直接依赖于GWT.create()或JSNI(两者都需要浏览器环境来运行)。请注意,GWT.create()现在可以在纯Java中使用,并且一些项目(如gwt-mockito或gwt-test-utils)使用字节码操作使其仍然可以运行。但即使没有MVP,这仍然是个问题:
全局状态和单例模式会影响测试:
- 您的测试用例不是隔离的(它们依赖于全局状态,因此同时运行的两个测试用例共享相同的状态,因此它们不在一个受控环境中运行) - 您不能直接使用模拟/伪造/存根或其他测试替身,因为系统被测试对象直接使用单例模式而不是依赖于由环境传递的某些对象(测试和生产环境中的对象不同)
请参见http://misko.hevery.com/code-reviewers-guide/flaw-brittle-global-state-singletons/

谢谢您的回答。我明白我们需要有可测试的Presenter(这就是为什么我们必须编写所有这些接口),并且拥有全局状态是不好的实践。但在我们的情况下,我只需要检查我的视图、RPC、消息等接口的方法是否按时调用。由于我正在测试Presenter而不是视图、RPC或消息包,因此我不必关心它们的状态或它们的实例是否是单例。我能否使用PowerMock来模拟我的静态工厂并避免您所说的问题? - Olivier Tonglet
可能我对PowerMock不够了解。据我所知,这与gwt-test-util的作用差不多;而且仅仅因为你可以这样做,并不意味着你应该这样做... 基本思想是,你的Presenter依赖于某些东西,这些东西应该被提供给它(Demeter法则),并且需要根据环境提供相应的实现(Liskov替换原则)。 (从技术上讲,虽然不太强大,但您也可以将工厂放在单独的JAR中并切换测试的JAR;或者在工厂中使用布尔开关切换到“测试模式”;但是工厂违反了Demeter法则) - Thomas Broyer
如果我不需要不同的实现,那么使用布尔参数类是否是一个选项(例如,如果我曾经需要布尔参数类)。在这种情况下,我应该得出结论,使用客户端工厂或Gin是否过度杀伤?如果我感到有必要在某个时候拥有不同的实现,我总是可以将需要检索的少量资源/类恢复到Gin或客户端工厂。为了避免样板代码,经验法则是控制以这种方式处理的类的数量,并强烈反对从一开始就盲目地连接所有内容。再次感谢您的回答。 - Olivier Tonglet
通常我会尽量避免使用“魔法”(反射、字节码重写等),我认为使用注入的依赖项(手动或使用类似 GIN 的工具)可以使代码更清晰易懂(最小惊讶原则:“哦,是的,在测试中,我们重写了那个类以执行略微不同的操作”)。虽然这比使用 PowerMock 和静态工厂更冗长,但我们有 IDE 来帮助生成和维护样板代码。你的情况可能有所不同。 - Thomas Broyer
字节码是库的问题,而不是我们的问题。所以我理解你的建议是使用Gin(你说它比模拟+静态工厂更容易使用,看起来接近淘汰)。我也知道需要特殊的IDE工具来处理所有必要的样板文件。这让我有点害怕使用Gin,但我会仔细研究一下。再次感谢你的建议。 - Olivier Tonglet
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接