[关闭]
@Catyee 2017-07-12T09:29:43.000000Z 字数 2676 阅读 406

Effective Java 用静态工厂代替构造器

Java 经验之谈 高效开发



对于一个类,要获得它的一个实例,一般而言是提供一个共有的构造器。但是可以考虑用一个静态工厂来代替构造器。要注意的是,这里的静态工厂与设计模式中的工厂方法不同。

来看一看服务提供者框架:
服务提供者框架是指这样一个系统:多个服务提供者实现了某个服务,系统为用户提供多个实现,并把它们从多个实现中解耦出来。

服务提供者框架中有三个重要的组件:服务接口(Service Interface), 这是由提供者定义和实现的。提供者注册API(Provider Registration API),这是系统用来注册提供者的,因为具体的服务由提供者实现,所以实际上只有注册提供者之后才会有具体的服务。服务访问API(Service Access API),是用户用来获取服务实例的。还有一个可选的组件:服务提供者接口(Service Provider Interface)
这些提供者负责创建其服务实现的实例。如果没有服务提供者接口,实现就按照类名称注册,并通过反射方式进行实例化。

举一个实例:
服务接口(Service Interface):

  1. /**
  2. * Service Interface
  3. */
  4. public interface Service {
  5. // Service-specific methods go here
  6. }

服务提供者接口(Service Provider Interface):

  1. /**
  2. * Service Provider Interface
  3. */
  4. public interface Provider {
  5. Service newService();
  6. }
  1. /**
  2. * Noninstantiable class for service registration and access
  3. */
  4. public class Services {
  5. private Services() {
  6. } // Prevents instantiation (Item 4)
  7. // Maps service names to services
  8. private static final Map<String, Provider> providers = new ConcurrentHashMap<String, Provider>();
  9. public static final String DEFAULT_PROVIDER_NAME = "<def>";
  10. // Provider registration API
  11. public static void registerDefaultProvider(Provider p) {
  12. registerProvider(DEFAULT_PROVIDER_NAME, p);
  13. }
  14. public static void registerProvider(String name, Provider p) {
  15. providers.put(name, p);
  16. }
  17. // Service access API
  18. public static Service newInstance() {
  19. return newInstance(DEFAULT_PROVIDER_NAME);
  20. }
  21. public static Service newInstance(String name) {
  22. Provider p = providers.get(name);
  23. if (p == null)
  24. throw new IllegalArgumentException(
  25. "No provider registered with name: " + name);
  26. return p.newService();
  27. }
  28. }

这个类中包含提供者注册API和服务访问API。

最后是一个测试用例:

  1. public class Test {
  2. //定义提供者,每一个提供者实现了一钟服务
  3. private static Provider DEFAULT_PROVIDER = new Provider() {
  4. public Service newService() {
  5. return new Service() {
  6. @Override
  7. public String toString() {
  8. return "Default service";
  9. }
  10. };
  11. }
  12. };
  13. private static Provider COMP_PROVIDER = new Provider() {
  14. public Service newService() {
  15. return new Service() {
  16. @Override
  17. public String toString() {
  18. return "Complementary service";
  19. }
  20. };
  21. }
  22. };
  23. private static Provider ARMED_PROVIDER = new Provider() {
  24. public Service newService() {
  25. return new Service() {
  26. @Override
  27. public String toString() {
  28. return "Armed service";
  29. }
  30. };
  31. }
  32. };
  33. public static void main(String[] args) {
  34. // Providers would execute these lines
  35. //调用提供者注册API来注册提供者,注册完成之后,对应的提供者就会创建对应的服务
  36. Services.registerDefaultProvider(DEFAULT_PROVIDER);
  37. Services.registerProvider("comp", COMP_PROVIDER);
  38. Services.registerProvider("armed", ARMED_PROVIDER);
  39. // Clients would execute these lines
  40. //调用服务访问API来获得服务的实例
  41. Service s1 = Services.newInstance();
  42. Service s2 = Services.newInstance("comp");
  43. Service s3 = Services.newInstance("armed");
  44. System.out.printf("%s, %s, %s%n", s1, s2, s3);
  45. }
  46. }

理解:在测试用例中先定义一些提供者,之前说过服务是由提供者自己实现的,所以在定义这些提供者的时候要实现具体的服务。
在main函数中去真正使用服务的时候,首先要调用提供者注册API去对定义的提供者进行注册。注册完成之后才会有具体的服务。这个时候就可以通过服务访问API拿到某个提供者提供的具体服务了。

上面示例的运行结果:

  1. Default service, Complementary service, Armed service
  2. Process finished with exit code 0
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注