工廠方法模式(Factory method)以及與抽象工廠(abstract factory)的區(qū)別
2010-05-24 11:03
先看經(jīng)典說法,
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 (定義一個創(chuàng)建對象的接口, 讓子類決定用哪個類來實例化對象。工廠方法把類的實現(xiàn)放在子類中完成。)
Gang of Four把這一段看作是這個模式的目的(intent),但我看更像該模式的方 法(apporach)。因為連形式都說的很清楚了。
1. 一個接口。 2. 接口中有一個創(chuàng)建方法。
對這個接口的使用必然涉及工廠模式。它的使用方式是多種多樣的。
我們來看一個例子, 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這三個環(huán)節(jié)。1是包含有創(chuàng)建方法的接口, 2或3是對接口的實現(xiàn),5是客戶端對接口的使用。變化比較多的就是第四個環(huán)節(jié), 也就是new子類的環(huán)節(jié)。這個例子是在static方法中調(diào)用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方法中調(diào)用的new,而你完全可以根據(jù)具體情況在你想要 的任何地方做實例化工作,比如在另一個類中這樣寫:
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既扮演了客戶端(客戶端在這里是指是使用創(chuàng)建方 法的對象)的角色,又扮演了工廠模式中的接口的角色。這個例子中,工廠方法 模式配合了模板模式(模板模式參見..)
工廠模式極為常見,它變化萬千,但不變的是,實際上可以歸為一點,存在一個 創(chuàng)建接口。只要你實現(xiàn)這個接口、使用這個接口,不可避免的就會使用工廠方法 模式,即使你沒有意識到這一點。
比如有個抽象接口A, 如下 interface A{ ProductB b = createB(); }
你如果使用這樣的創(chuàng)建接口A,就不可避免的要涉及對接口A的引用,以及對接口 A的實例化以及對ProdctB的引用。你只要使用了接口A,你的一系列做法就會符合 是工廠方法模式。
抽象工廠模式所不同的是,接口A所創(chuàng)建的對象不是產(chǎn)品,而是用來創(chuàng)建產(chǎn)品的工 廠。如下:
interface A{ Factory f = createFactory(); }
抽象工廠模式就是用工廠方法模式來實現(xiàn)的。所以它們二者很像。其實工廠方法 模式更準(zhǔn)確的寫法應(yīng)該是這樣:
interface A{ 抽象對象B b = create具體對象B(); }
工廠方法模式不管抽象對象B是誰,這個對象是product也好,是工廠對象也好, 這都是工廠方法模式的應(yīng)用,只是如果這個對象是工廠對象,則它會又延伸一套 抽象工廠模式。
抽象工廠也可以不用工廠方法模式配合,看這個例子,
public class client{ public void doSomething(){ MyAbstractFactory f = new MyConcreteFactory(); Product1 p1 = f.getProduct1(); Product2 p2 = f.getProduct2(); p1.doSomethingWith(p2); } }
這里用到了抽象工廠,MyAbstractFactory就是個抽象工廠。但抽象工廠的創(chuàng)建是 直接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(); } }
這是工廠方法模式,就像前面說的那樣,它有一個創(chuàng)建接口(abstract createFactory()可以看做接口),有對這個接口的實現(xiàn)。它也是抽象工廠模式。 或者說,這種抽象工廠的創(chuàng)建,使用了工廠方法模式。
希望這篇文章能幫你從形式上理解工廠方法模式以及它和抽象工廠模式的區(qū)別。 關(guān)于抽象工廠的詳細(xì)講解,請參考http://hi.baidu.com |
|