Thingking in Java 注册工厂

来源:互联网 发布:windows 2008 ad 管理 编辑:程序博客网 时间:2024/05/18 09:22

生成Pete继承结构中的对象存在着一个问题,即每次向该继承结构添加新的Pet类型时,必须将其添加为LiteralPetCreator.java中的项。如果在系统中已经存在了继承结构的常规的基础,然后在其上要添加更多的类,那么就有可能会出现问题。

 

   您可能会考虑在每个子类中添加静态初始化器,以使得该初始化器可以将它的类添加到某个List中。

 

   遗憾的是,静态初始化器只有在类首先被加载的情况下才能被调用,因此您就碰上了“先有鸡还是先有蛋”的问题:生成器在其列表中不包含这个类,因此它永远不能创建这个类的对象,而这个类也就不能被加载并置于这个列表中。

 

   这主要是因为,您被强制要求自己去手工创建这个列表(除非您想编写一个工具,它可以全面搜索和分析源代码,然后创建和编译这个列表)。

 

   因此,您最佳的做法是,将这个列表置于一个位于中心的、位置明显的地方,而我们感兴趣的继承结构的基类可能就是这个最佳位置。

 

   这里我们需要做的其他修改就是使用工厂方法设计模式,将对象的创建工作交给类自己去完成。工厂方法可以被多态地调用,从而为您创建恰当类型的对象。

 

   在下面这个非常简单的版本中,工厂方法就是Factory接口中的create()方法:

 

   //: typeinfo/factory/Factory.java
   package typeinfo.factory;
   public interface Factory<T> { T create(); } ///:~

 

   泛型参数T使得create*()可以在每种Factory实现中返回不同的类型。这也充分利用了协变返回类型。

 

   在下面的示例中,基类Part包含一个工厂对象的列表。对于应这个由createRandom()方法产生的类型,它们的工厂都被添加到了partFactories List中,从而被注册到了基类中:

 

   //: typeinfo/RegisteredFactories.java
   // Registering Class Factories in the base class.

   import typeinfo.factory.*;
   import java.util.*;

   class Part {
     public String toString() {
       return getClass().getSimpleName();
     }
     static List<Factory<? extends Part>> partFactories =
       new ArrayList<Factory<? extends Part>>(); 
     static {
       // Collections.addAll() gives an "unchecked generic
       // array creation ... for varargs parameter" warning.

       partFactories.add(new FuelFilter.Factory());
       partFactories.add(new AirFilter.Factory());
       partFactories.add(new CabinAirFilter.Factory());
       partFactories.add(new OilFilter.Factory());
       partFactories.add(new FanBelt.Factory());
       partFactories.add(new PowerSteeringBelt.Factory());
       partFactories.add(new GeneratorBelt.Factory());
     }
     private static Random rand = new Random(47);
     public static Part createRandom() {
       int n = rand.nextInt(partFactories.size());
       return partFactories.get(n).create();
     }
   } 

   class Filter extends Part {}

   class FuelFilter extends Filter {
     // Create a Class Factory for each specific type:
     public static class Factory
     implements typeinfo.factory.Factory<FuelFilter> {
       public FuelFilter create() { return new FuelFilter(); }
     }
   }

   class AirFilter extends Filter {
     public static class Factory
     implements typeinfo.factory.Factory<AirFilter> {
       public AirFilter create() { return new AirFilter(); }
     }
   } 

   class CabinAirFilter extends Filter {
     public static class Factory
     implements typeinfo.factory.Factory<CabinAirFilter> {
       public CabinAirFilter create() {
         return new CabinAirFilter();
       }
     }
   }

   class OilFilter extends Filter {
     public static class Factory
     implements typeinfo.factory.Factory<OilFilter> {
       public OilFilter create() { return new OilFilter(); }
     }
   } 

   class Belt extends Part {}

   class FanBelt extends Belt {
     public static class Factory
     implements typeinfo.factory.Factory<FanBelt> {
       public FanBelt create() { return new FanBelt(); }
     }
   }

   class GeneratorBelt extends Belt {
     public static class Factory
     implements typeinfo.factory.Factory<GeneratorBelt> {
       public GeneratorBelt create() {
         return new GeneratorBelt();
       }
     }
   } 

   class PowerSteeringBelt extends Belt {
     public static class Factory
     implements typeinfo.factory.Factory<PowerSteeringBelt> {
       public PowerSteeringBelt create() {
         return new PowerSteeringBelt();
       }
     }
   } 

   public class RegisteredFactories {
     public static void main(String[] args) {
       for(int i = 0; i < 10; i++)
         System.out.println(Part.createRandom());
     }
   }

    /* 输出:
   GeneratorBelt
   CabinAirFilter
   GeneratorBelt
   AirFilter
   PowerSteeringBelt
   CabinAirFilter
   FuelFilter
   PowerSteeringBelt
   PowerSteeringBelt
   FuelFilter
   *///:~

 

   并非所有在继承结构中的类都应该被实例化,在本例中,Filter和Belt只是分类标识,因此您不应该创建它们的实例,而只应该创建它们的子类的实例。

 

   如果某个类应该由createRandom()方法创建,那么它就包含一个内部Factory类。如上所示,重用名字Factory的唯一方式就是限定typeinfo.factory.Factory。

 

   尽管您可以使用Collections.addAll()来向列表中添加工厂,但是这样做编译器就会表达它的不满,抛出一条有关“创建泛型数组”的警告,因此我们转而使用add()。createRandom()方法从partFactories中随机地选取一个工厂对象,然后调用其Create()方法,从而产生一个新的Part。