工厂模式Q根据调用数据返回某个类的一个实例,此类可以是多个类的某一个类Q通常Q这些类满共同的规则或父类。调用者只兛_(j)Q是否满xU规范和是否可供自己正常调用?br />
厂模式定?提供创徏对象的接?
Z使用?
工厂模式是我们最常用的模式了(jin),著名的Jive论坛 ,大量用了(jin)工厂模式Q工厂模式在JavaE序pȝ可以说是随处可见?/p>
Z么工厂模式是如此常用Q因为工厂模式就相当于创建实例对象的newQ我们经常要Ҏ(gu)cClass生成实例对象Q如A a=new A() 工厂模式也是用来创徏实例对象的,所以以后new时就要多个心(j)|是否可以考虑实用工厂模式Q虽然这样做Q可能多做一些工作,但会(x)l你pȝ带来更大的可扩展性和量的修改量?/p>
我们以类SampleZQ?如果我们要创建Sample的实例对?
Sample sample=new Sample();
可是Q实际情冉|Q通常我们都要在创建sample实例时做点初始化的工?比如赋?查询数据库等?/p>
首先Q我们想到的是,可以使用Sample的构造函敎ͼq样生成实例写?
Sample sample=new Sample(参数);
但是Q如果创建sample实例时所做的初始化工作不是象赋DL(fng)单的事,可能是很长一D代码,如果也写入构造函CQ那你的代码很难看了(jin)Q就需要Refactor重整Q?/p>
Z么说代码很难看,初学者可能没有这U感觉,我们分析如下Q初始化工作如果是很长一D代码,说明要做的工作很多,很多工作装入一个方法中Q相当于很多鸡蛋放在一个篮子里Q是很危险的Q这也是有背于Java面向对象的原则,面向对象的封?Encapsulation)和分z?Delegation)告诉我们Q尽量将长的代码分派“切割”成每D,每D再“装”h(减少D和D之间偶合联pL?Q这P׃(x)风险分散,以后如果需要修改,只要更改每段Q不?x)再发生牵一动百的事情?/p>
在本例中Q首先,我们需要将创徏实例的工作与使用实例的工作分开, 也就是说Q让创徏实例所需要的大量初始化工作从Sample的构造函C分离出去?/p>
q时我们需要Factory工厂模式来生成对象了(jin)Q不能再用上面简单new Sample(参数)。还?如果Sample有个l承如MySample, 按照面向接口~程,我们需要将Sample抽象成一个接?现在Sample是接?有两个子cMySample 和HisSample .我们要实例化他们?如下:
Sample mysample=new MySample();
Sample hissample=new HisSample();
随着目的深?Sample可能q会(x)"生出很多儿子出来", 那么我们要对q些儿子一个个实例?更糟p的?可能q要对以前的代码q行修改:加入后来生出儿子的实?q在传统E序中是无法避免?
但如果你一开始就有意识用了(jin)工厂模式,q些ȝ(ch)没有了(jin).
工厂Ҏ(gu)
你会(x)建立一个专门生产Sample实例的工?
public class Factory{
public static Sample creator(int which){
//getClass 产生Sample 一般可使用动态类装蝲装入cR?br />
if (which==1)
return new SampleA();
else if (which==2)
return new SampleB();
}
}
|
那么在你的程序中,如果要实例化Sample?׃?/p>
Sample sampleA=Factory.creator(1);
q样,在整个就不涉?qing)到Sample的具体子c?辑ֈ装效果,也就减少错误修改的机?q个原理可以用很通俗的话来比?是具体事情做得多,容易范错误.q每个做q具体工作的人都深有体会(x),相反,官做得越?说出的话抽象越W统,范错误可能性就少.好象我们从编E序中也能?zhn)Zh生道?呵呵.
使用工厂Ҏ(gu) 要注意几个角Ԍ首先你要定义产品接口Q如上面的Sample,产品接口下有Sample接口的实现类,如SampleA,其次要有一个factoryc,用来生成产品SampleQ如下图Q最双是生产的对象SampleQ?/p>
q一步稍微复杂一点,是在工厂类上进行拓展,工厂cM有承它的实现类concreteFactory?strong>?/em>
抽象工厂
工厂模式中有: 工厂Ҏ(gu)(Factory Method) 抽象工厂(Abstract Factory).
q两个模式区别在于需要创建对象的复杂E度上。如果我们创建对象的Ҏ(gu)变得复杂?如上面工厂方法中是创Z个对象Sample,如果我们q有新的产品接口Sample2.
q里假设QSample有两个concretecSampleA和SamleBQ而Sample2也有两个concretecSample2A和SampleB2
那么Q我们就上例中Factory变成抽象c?共同部分封装在抽象cM,不同部分使用子类实现Q下面就是将上例中的Factory拓展成抽象工?
public abstract class Factory{
public abstract Sample creator();
public abstract Sample2 creator(String name);
}
public class SimpleFactory extends Factory{
public Sample creator(){
.........
return new SampleA
}
public Sample2 creator(String name){
.........
return new Sample2A
}
}
public class BombFactory extends Factory{
public Sample creator(){
......
return new SampleB
}
public Sample2 creator(String name){
......
return new Sample2B
}
}
|
从上面看C个工厂各自生产出一套Sample和Sample2,也许你会(x)疑问Qؓ(f)什么我不可以用两个工厂方法来分别生Sample和Sample2?
抽象工厂q有另外一个关键要点,是因?SimpleFactory内,生Sample和生产Sample2的方法之间有一定联p,所以才要将q两个方法捆l在一个类中,q个工厂cL其本w特征,也许刉过E是l一的,比如Q制造工艺比较简单,所以名U叫SimpleFactory?br />
在实际应用中Q工厂方法用得比较多一些,而且是和动态类装入器组合在一起应用,
举例
我们以Jive的ForumFactoryZQ这个例子在前面的Singleton模式中我们讨Q现在再讨论其工厂模?
public abstract class ForumFactory {
private static Object initLock = new Object();
private static String className = "com.jivesoftware.forum.database.DbForumFactory";
private static ForumFactory factory = null;
public static ForumFactory getInstance(Authorization authorization) {
//If no valid authorization passed in, return null.
if (authorization == null) {
return null;
}
//以下使用?jin)Singleton 单态模?br />
if (factory == null) {
synchronized(initLock) {
if (factory == null) {
......
try {
//动态{载类
Class c = Class.forName(className);
factory = (ForumFactory)c.newInstance();
}
catch (Exception e) {
return null;
}
}
}
}
//Now, q回 proxy.用来限制授权对forum的访?br />
return new ForumFactoryProxy(authorization, factory,
factory.getPermissions(authorization));
}
//真正创徏forum的方法由l承forumfactory的子cd完成.
public abstract Forum createForum(String name, String description)
throws UnauthorizedException, ForumAlreadyExistsException;
....
}
|
因ؓ(f)现在的Jive是通过数据库系l存放论坛帖子等内容数据,如果希望更改为通过文gpȝ实现,q个工厂Ҏ(gu)ForumFactory提供了(jin)提供动态接?
private static String className = "com.jivesoftware.forum.database.DbForumFactory";
你可以用自己开发的创徏forum的方法代替com.jivesoftware.forum.database.DbForumFactory可?
在上面的一D代码中一q?jin)三U模?除了(jin)工厂模式?q有Singleton单态模?以及(qing)proxy模式,proxy模式主要用来授权用户对forum的访?因ؓ(f)讉Kforum有两Uh:一个是注册用户 一个是游客guest,那么那么相应的权限就不一?而且q个权限是诏I整个系l的,因此建立一个proxy,cM|关的概?可以很好的达到这个效?
看看Java宠物店中的CatalogDAOFactory:
public class CatalogDAOFactory {
/**
* 本方法制定一个特别的子类来实现DAO模式?br />
* 具体子类定义是在J2EE的部|描q器中?br />
*/
public static CatalogDAO getDAO() throws CatalogDAOSysException {
CatalogDAO catDao = null;
try {
InitialContext ic = new InitialContext();
//动态装入CATALOG_DAO_CLASS
//可以定义自己的CATALOG_DAO_CLASSQ从而在无需变更太多代码
//的前提下Q完成系l的巨大变更?/p>
String className =(String) ic.lookup(JNDINames.CATALOG_DAO_CLASS);
catDao = (CatalogDAO) Class.forName(className).newInstance();
} catch (NamingException ne) {
throw new CatalogDAOSysException("
CatalogDAOFactory.getDAO: NamingException while
getting DAO type : "n" + ne.getMessage());
} catch (Exception se) {
throw new CatalogDAOSysException("
CatalogDAOFactory.getDAO: Exception while getting
DAO type : "n" + se.getMessage());
}
return catDao;
}
}
|
CatalogDAOFactory是典型的工厂Ҏ(gu)QcatDao是通过动态类装入器className获得CatalogDAOFactory具体实现子类Q这个实现子cdJava宠物店是用来操作catalog数据库,用户可以Ҏ(gu)数据库的cd不同Q定制自q具体实现子类Q将自己的子cdl与CATALOG_DAO_CLASS变量可以?/p>
由此可见Q工厂方法确实ؓ(f)pȝl构提供?jin)非常灵zd大的动态扩展机Ӟ只要我们更换一下具体的工厂Ҏ(gu)Q系l其他地Ҏ(gu)需一点变换,有可能系l功能进行改头换面的变化?/p>
设计模式如何在具体项目中应用?a target="_blank">《Java实用pȝ开发指南?/a>