重温 Thinking in Java 6 - Registered factories

Registered factories

 

A problem with generating objects of the Pets hiearachy is the fact that every time you add a new type of Pet to the hierarchy you must remember to add it to the entries in LiteralPetCreator.java. In a system where you add more classes on a regular basis this can become problematic.

You might think of adding a static initializer to each subclass, so that the initilizer would add its class to a list somewhere. Unfortunately, static initializers are only called when the class is first loaded, so you have a chicken-and-egg problem: The generator doesn't have the class in its list, so it can never create an object of that class, so the class won't get loaded and placed in the list.

Basically, you're forced to create the list yourself, by hand (unless you want to write a tool that searches through and analyzes your source code, then creates and compiles the list). So the best you can probably do is to put the list in one central, obvious place. The base class for the hierarchy of interest is probably the best place.

The other change we'll make here is to defer the creation of the object to the class itself, using the Factory Method design patter. A factory method can be called polymorphically, and creates an object of the appropriate type for you. In this very simple version, the factory method is the create() method in the Factory interface:

 

public interface Factory<T>{
	T create();
}
 
import java.util.*;

class Part {
	public String toString(){
		return getClass().getSimpleName();
	}
	
	static List<BaseFactory<? extends Part>> partFactories = new ArrayList<BaseFactory<? 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 BaseFactory<FuelFilter>{
		public FuelFilter create(){
			return new FuelFilter();
		}
	}
}

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

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

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

class Belt extends Part{
}

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

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

class PowerSteeringBelt extends Belt {
	public static class Factory implements BaseFactory<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());
		}
	}
}

/*
	Not all classes in the hierarchy should be instantiated; in this case Filter and Belt are just classified so you do not create an
	instance of either one, but only of their subclasses. If a class should be created by createRandom(), it contains an inner Factory
	class. The only way to reuse the name Factory as seen above is by qualifying BaseFactory.

	Although you can use Collections.addAll() to add the factories to the list, the compiler expresses its unhappiness with a warning
	about a "generic array creation" (which is supposed to be impossible, as you'll seen in the Generics chapter), so I reverted to
	calling add(). The createRandom() method randomly selects a factory object from partFactories and calls its create() to produce
	a new Part.
*/

 

Design Pattern - Factory

http://i8i8i8.iteye.com/admin/blogs/445941

 

你可能感兴趣的:(java)