【问题标题】:A known design pattern for dynamic factory一种已知的动态工厂设计模式
【发布时间】:2016-06-15 22:38:07
【问题描述】:

这有合适的名字吗?

public class SomethingFactory {
    private final String someParameter;

    public SomethingFactory(String someParameter) {
        this.someParameter = someParameter;
    }

    public Something create(String anotherParameter) {
        return new Something(someParameter, anotherParameter);
    }
}

public class Something {
    public final String someParameter;
    public final String anotherParameter;
    public Something(String someParameter, String anotherParameter) {
        this.someParameter = someParameter;
        this.anotherParameter = anotherParameter;
    }
}

与常规工厂的不同之处在于,您必须在运行时指定一个参数,以便在需要创建对象时进行 create()。

这样你可以在 Spring 上下文中创建一个单例工厂,例如,在那里配置前半部分参数,然后在运行时调用 create() 时完成其余参数。

如果你好奇,我为什么首先需要它:

我曾经在 Spring 上下文中拥有常规的单例对象,并且在每个请求的线程应用程序中都很好,但现在我的整个应用程序是非阻塞的,我不能使用 ThreadLocal 在整个请求处理过程中保留内容。例如,使用 Apache StopWatch 等工具保存时间信息。

我需要找到一种方法来在多线程、非阻塞环境中实现“请求范围”,而不必在我的代码的每个方法(这将是愚蠢的)中提供表示范围的对象。

所以我想让每个(服务)类在构造函数中使用这个范围对象,并在每个请求上创建这些类,但这与单例相违背。我们所说的单例就像是让用户登录的 UserService 或生成数字签名的 CryptoService。它们在 Spring 中配置一次,在需要时注入,一切正常。但现在我需要在需要它们的每个方法中创建这些服务类,而不是仅仅引用注入的单例实例。

所以我认为让我们将这些单例称为“模板”,当您需要一个实际实例时,您可以调用 create() 来提供所述范围对象。这样每个类都有范围对象,您只需将其提供给其他模板服务构造函数。完整的东西看起来像这样:

public class UserService {
    private final Scope scope;
    private final Template t;
    private UserService(Template t, Scope scope) {
        this.t = t;
        this.scope = scope;
    }

    public void login(String username) {
        scope.timings.probe("before calling database");
        t.database.doSomething(username);
        scope.timings.probe("after calling database");
    }

    public static class Template { /* The singleton configured in Spring */
        private Database database;
        public void setDatabase(Database database) { /* Injected by Spring */
            this.database = database;
        }

        public UserService create(Scope scope) {
            return new UserService(this, scope);
        }
    }
}

public class LoginHttpHandler { /* Also a Spring singleton */
    private UserService.Template userServiceT;

    public void setUserServiceT(UserService.Template userServiceT) { /* Injected by Spring */
        this.userServiceT = userServiceT;
    }

    public void handle(HttpContext context) { /* Called on every http request */
        userServiceT.create(context.scope).login("billgates");
    }
}

在 Spring 中,您只需描述一个 UserService.Template bean 及其所需的适当依赖项,然后在需要 UserService 时注入该 bean。

我只是称其为“模板”。但像往常一样,我觉得它已经完成了。有名字吗?

【问题讨论】:

标签: java spring design-patterns factory


【解决方案1】:

这几乎就是 Guice 的 AssistedInject 给出的例子:

public class RealPaymentFactory implements PaymentFactory {
  private final Provider<CreditService> creditServiceProvider;
  private final Provider<AuthService> authServiceProvider;

  @Inject
  public RealPaymentFactory(Provider<CreditService> creditServiceProvider, Provider<AuthService> authServiceProvider) {
    this.creditServiceProvider = creditServiceProvider;
    this.authServiceProvider = authServiceProvider;
  }

  public Payment create(Date startDate, Money amount) {
    return new RealPayment(creditServiceProvider.get(), authServiceProvider.get(), startDate, amount);
  }
}

public class RealPayment implements Payment {
  public RealPayment(
    CreditService creditService,  // from the Injector
    AuthService authService,  // from the Injector
    Date startDate, // from the instance's creator
    Money amount) // from the instance's creator
  {
    ...
  }
}

辅助注入用于“创建在构造时需要额外参数的类”。

此外,这类似于 partial application,因此您可以使用创建 UserServicePartialUserService

【讨论】:

    猜你喜欢
    • 2015-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-15
    • 1970-01-01
    • 2011-11-20
    相关资源
    最近更新 更多