工厂方法模式(Factory method)以及与抽象工厂(abstract factory)的区别
2010-05-24 11:03
先看经典说法,
Define an interface for creating an object, but let subclasses decidewhich class to instantiate. Factory Method lets a class defer instantiation to subclasses. ----Gang of Four (定义一个创建对象的接口, 让子类决定用哪个类来实例化对象。工厂方法把类的实现放在子类中完成。)
Gang of Four把这一段看作是这个模式的目的(intent),但我看更像该模式的方 法(apporach)。因为连形式都说的很清楚了。
1. 一个接口。 2. 接口中有一个创建方法。
对这个接口的使用必然涉及工厂模式。它的使用方式是多种多样的。
我们来看一个例子, 1. public interface ImageReader { public DecodedImage getDecodedImage(); }
2. public class GifReader implements ImageReader { public DecodedImage getDecodedImage() { return decodedImage; } }
3. public class JpegReader implements ImageReader { // .... }
4. public class ImageReaderFactory { public static ImageReader getImageReader(InputStream is) { int imageType = determineImageType(is); switch(imageType) { case ImageReaderFactory.GIF: return new GifReader(is); case ImageReaderFactory.JPEG: return new JpegReader(is); // etc. } } }
5. public class client{ public void useImageReader(){ ImageReader ir = ImageReaderFactory.getImageReader(is); Decodedimage di = ir.getDecodedImage(); di.doSth(); } }
使用工厂方法模式,必须要有1,2或3,5这三个环节。1是包含有创建方法的接口, 2或3是对接口的实现,5是客户端对接口的使用。变化比较多的就是第四个环节, 也就是new子类的环节。这个例子是在static方法中调用new来用子类来实例化接 口.
我们再看一个例子,
public abstract class TemplateClient { public Map queryDatabase(String queryString) { RdfDatabase db = databaseFactory();
checkQueryIsValid(queryString);
return db.find(queryString); } public abstract RdfDatabase databaseFactory(); }
public class JenaClient extends TemplateClient { public RdfDatabase databaseFactory() { return new JenaDatabase(); } }
上面的例子中是在static方法中调用的new,而你完全可以根据具体情况在你想要 的任何地方做实例化工作,比如在另一个类中这样写:
TemplateClient t = new JenaClient(); RdfDatabase rdf = t.databaseFactory(); rdf.queryDatabase("select * from table");
你也可以在TemplateClient的子类JenaClient中这样使用,
public class JenaClient extends TemplateClient { public RdfDatabase databaseFactory() { return new JenaDatabase(); } //这样使用 public void use(){ queryDatabase("select * from table"); } }
在这个例子中,TemplateClient既扮演了客户端(客户端在这里是指是使用创建方 法的对象)的角色,又扮演了工厂模式中的接口的角色。这个例子中,工厂方法 模式配合了模板模式(模板模式参见..)
工厂模式极为常见,它变化万千,但不变的是,实际上可以归为一点,存在一个 创建接口。只要你实现这个接口、使用这个接口,不可避免的就会使用工厂方法 模式,即使你没有意识到这一点。
比如有个抽象接口A, 如下 interface A{ ProductB b = createB(); }
你如果使用这样的创建接口A,就不可避免的要涉及对接口A的引用,以及对接口 A的实例化以及对ProdctB的引用。你只要使用了接口A,你的一系列做法就会符合 是工厂方法模式。
抽象工厂模式所不同的是,接口A所创建的对象不是产品,而是用来创建产品的工 厂。如下:
interface A{ Factory f = createFactory(); }
抽象工厂模式就是用工厂方法模式来实现的。所以它们二者很像。其实工厂方法 模式更准确的写法应该是这样:
interface A{ 抽象对象B b = create具体对象B(); }
工厂方法模式不管抽象对象B是谁,这个对象是product也好,是工厂对象也好, 这都是工厂方法模式的应用,只是如果这个对象是工厂对象,则它会又延伸一套 抽象工厂模式。
抽象工厂也可以不用工厂方法模式配合,看这个例子,
public class client{ public void doSomething(){ MyAbstractFactory f = new MyConcreteFactory(); Product1 p1 = f.getProduct1(); Product2 p2 = f.getProduct2(); p1.doSomethingWith(p2); } }
这里用到了抽象工厂,MyAbstractFactory就是个抽象工厂。但抽象工厂的创建是 直接new出来来,如果你想换一个具体的工厂,你只能修改代码,该成这样,
MyAbstractFactory f = new MyAnotherConcreateFactory();
但如果配合上工厂方法模式,就可以变成这样,
public class client{ public void doSomething(){ MyAbstractFactory f = new MyConcreteFactory(); Product1 p1 = f.getProduct1(); Product2 p2 = f.getProduct2(); p1.doSomethingWith(p2); }
public abstract MyAbstractFactory createFactory(); }
public class ASubClass extends client{ public MyAbstractFactory createFactory(){ return new MyConcreteFactory(); } }
这是工厂方法模式,就像前面说的那样,它有一个创建接口(abstract createFactory()可以看做接口),有对这个接口的实现。它也是抽象工厂模式。 或者说,这种抽象工厂的创建,使用了工厂方法模式。
希望这篇文章能帮你从形式上理解工厂方法模式以及它和抽象工厂模式的区别。 关于抽象工厂的详细讲解,请参考http://hi.baidu.com |
|