动态工厂

时间:2016-06-15 22:38:07

标签: java spring design-patterns factory

这是否有正确的名称?

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;
    }
}

与常规工厂的不同之处在于,无论何时需要创建对象,都必须在运行时指定一个参数来创建()。

通过这种方式,您可以在Spring上下文中创建单例工厂,在那里配置前半部分参数,然后在调用create()时在运行时完成其余参数。

如果您感到好奇,为什么我首先需要它?

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

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

所以我想让我们让每个(服务)类在构造函数中获取这个范围对象,让我们在每个请求中创建这些类,但这违背了单例。我们正在谈论的单身人士就像是记录用户的UserService,或者是生成数字签名的CryptoService。它们在Spring中配置一次,需要时注入,一切都还可以。但是现在我需要在他们需要的每个方法中创建这些服务类,而不是仅仅引用注入的单例实例。

所以我想我们会把那些单身人士称为"模板"无论何时需要实际实例,都可以调用create()来提供所述范围对象。这样每个类都有scope对象,你只需要继续将它提供给其他模板服务构造函数。完整的东西看起来像这样:

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。

我只是称之为"模板"。但总是像我一样,我觉得它已经完成了。它有什么名字吗?

1 个答案:

答案 0 :(得分:0)

这几乎是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
  {
    ...
  }
}

辅助注射用于在构建时创建需要额外参数的类&#34;

此外,这与partial application类似,因此您可以使用PartialUserService创建UserService