java - Guice 谜题 : Batch scoped Encapsulated Context

标签 java scope guice

我们正准备开始在我们的保险数据转换平台中使用 Guice,我遇到了一个有趣的场景,在 Guice 文档或我发现的任何帖子中似乎都没有直接解决。

我们的平台在几个重要领域使用封装上下文 (EC) 模式。例如,假设我们正在处理一组 10 个策略。每当我们开始处理一个新策略时,我们希望构造一个 PolicyContext对象并初始化诸如策略编号、状态和公司之类的属性。这个PolicyContext是转换过程中涉及的许多类的依赖项。

请注意 PolicyContext (以及我们应用程序中的其他 *Context 对象)是一个紧密关注特定域区域的值对象(代表基本的、普遍需要的策略信息)。我很想知道你们中的模式专家是否仍然认为这是一种反模式(正如 Misko Hevery 在 http://misko.hevery.com/2008/07/18/breaking-the-law-of-demeter-is-like-looking-for-a-needle-in-the-haystack/ 中所讨论的那样),即使这些是纯粹的值(value)对象并且当然不代表“厨房水槽”。 ”

目前,我们正在管理 PolicyContext以最糟糕的方式:我们有一个静态全局变量 policyContext , 和 policyContext.initialize(String company, String state, String policyNum)每当我们开始处理新策略时都会调用它。

我的目标是让 Guice 以架构上优化的方式管理这些上下文对象,以便从概念上讲,每当我们开始处理新策略时:

  • Guice 抛弃旧的 PolicyContext .
  • Guice 构造了一个新的、不可变的 PolicyContext (无臭初始化方法)使用company/state/policyNum来自数据库的参数。
  • Guice 注入(inject)已经构建好的 PolicyContext进入所有需要它的类。

  • 这是我的暂定方法:
  • 创建自定义范围——类似于 http://code.google.com/p/google-guice/wiki/CustomScopes 上的 Guice 批处理范围示例-- 批处理的边界是由外部确定的。有了这个范围,我们开始处理一个新的策略,我们可以 1) 结束前一个“批处理”并开始一个新的。 :有什么原因我不能完全按照上述 URL 中列出的方式使用 Guice 批处理范围示例?
  • 由于PolicyContext没有依赖项,我们将对所有构造函数参数使用 AssistedInject(这似乎有点奇怪)。假设我们采用这种方法并生成 PolicyContextFactory ,因此在我们开始处理新策略的地方,我们将拥有如下代码:
    …
    scope.exit();
    scope.enter();
    @Inject private PolicyContextFactory policyContextFactory; 
    policyContextFactory.create(company, state, policyNum); // the parameters come from a database record.
    // Note that we don’t need to actually store the created instance; it will be injected elsewhere into various class constructors.
    …
    

  • 这看起来是最优的吗?我知道可能有更简单的方法(例如,每当我们处理新策略时,创建一个新的 PolicyContext 特定注入(inject)器,这实际上创建了一个新的 PolicyContext )。然而,这是架构的核心方面,所以我真的不想妥协。

    我知道,另一种选择是在这种情况下避免使用 DI,而只使用静态 PolicyContextManager带有单独 create 的类和 get方法,其中前一种方法是丢弃当前 PolicyContext 的工厂并创建/存储一个新的,而后一种方法只返回“Activity ”PolicyContext )。但是我的代码最终会执行手动 DI,因为我将编写大量代码,例如 methodThatNeedsPolicyContext(PolicyContextManager.get(), …) .由于我们无论如何都打算开始使用 Guice,所以这种方法似乎不是最佳的。

    顺便说一句,对于那些试图深入了解 DI 的人,我强烈推荐 Dhanji Prasanna 的“依赖注入(inject)”。这本书专注于 Guice 和 Spring,绝对是必不可少的,因为它比我遇到的任何其他东西都要深入得多。

    谢谢你的帮助!

    最佳答案

    看来您的链接 SimpleScope 几乎完全符合您的需求,因为您希望避免传递您的上下文,并且您的自定义范围将确保任何 @PolicyScoped绑定(bind)(大概只有您的上下文及其内容)已经准备好(“种子”)。您还将获得一些不错的多线程功能,尽管您可以通过将静态引用转换为静态 ThreadLocal 来获得这些功能。

    您必须在 enter 之间完全注入(inject)策略范围的对象图。和 exit电话,或任何你选择的名字。请注意,如果您将 PolicyContext 注入(inject)构造函数或字段(将其保存到对象的状态),那么您的对象实例现在特定于该策略。这似乎很明显,但又是一个队友漫不经心地注入(inject)或缓存 dueDateCalculator可能没有意识到它被隐式构造为仅适用于政策 #8675-309 的到期日期计算器,并且它将为政策 #5550-187 提供错误的答案。特别是任何@Singleton需要策略范围依赖的对象应该使用提供者,否则即使您退出范围,单例也会“记住”策略;这是一个“范围扩大注入(inject)”的例子,Prasanna discusses it at length .

    你可能会发现坚持让你的队友永远不要注入(inject) PolicyContext 会更简单。直接而不是总是注入(inject) Provider<PolicyContext> (您 get for free if PolicyContext is injectable )。这使您不必再考虑在构造对象时哪个策略处于 Activity 状态,而是信任您在该对象的方法运行时收到的 PolicyContext。

    如果一个对象没有依赖关系,则不需要 Guice 来创建它——这只是矫枉过正。一旦对象产生了如此多的依赖项以至于手动构建很痛苦,就很容易将对象的创建移动到 Guice。除非你必须这样做,否则不要这样做。

    最后,关于封装上下文,我碰巧相信 EC 模式是一种有效的重构,只要上下文没有逻辑并且整个对象包适用于上下文出现的地方。如果您可以向我辩护说 Context 中的每个项目在您注入(inject)上下文的时间中有 80% 被使用,那么代码可能更短且更易于遵循并且您赢了。请记住,依赖注入(inject)的好处之一是添加或删除依赖项非常容易,因此从注入(inject)一个单独绑定(bind)的 Context 属性到注入(inject)两个单独的 Context 属性再到直接注入(inject)整个 Context 变得非常容易(并且重复尽可能多的上下文)。

    不过,这只是我的看法。希望能帮助到你!

    关于java - Guice 谜题 : Batch scoped Encapsulated Context,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13847558/

    相关文章:

    java - 9位除以11的和为10时返回 'X'

    java - Guice -如何在扩展抽象模块的类中注入(inject)依赖项 - Java

    java - 如果我的运行类是 junit,如何初始化 guice?

    java - 如何使用 Guice 注入(inject)索引(和特定于类的)字符串

    c - 变量的多个实例(静态、非静态)

    javascript - 传入的 jQuery 插件设置范围

    java - Chrome 原生消息传递 Chrome 扩展

    java - 重复键更新时的 Derby JavaDB 查询

    java - Java中的快速队列

    java - Java中的变量声明和初始化