??xml version="1.0" encoding="utf-8" standalone="yes"?>
MementoQ备望录Q模?/font>
]]>
Stratrgy应用比较q泛,比如, 公司l营业务变化? 可能有两U实现方?一个是U条曲线,一个是框图(bar),q是两种法,可以使用Strategy实现.
q里以字W串替代Z, 有一个文?我们需要读取后,希望替代其中相应的变?然后输出.关于替代其中变量的方法可能有多种Ҏ,q取决于用户的要?所以我们要准备几套变量字符替代Ҏ.
首先,我们建立一个抽象类RepTempRule 定义一些公用变量和Ҏ:
public abstract class RepTempRule{ protected String oldString=""; public void setOldString(String oldString){ this.oldString=oldString; } protected String newString=""; public String getNewString(){ return newString; } public abstract void replace() throws Exception; } |
在RepTempRule?有一个抽象方法abstract需要承明?q个replace里其实是替代的具体方?
我们现在有两个字W替代方?
1.文本中aaa替代成bbb;
2.文本中aaa替代成ccc;
对应的类分别是RepTempRuleOne RepTempRuleTwo
public class RepTempRuleOne extends RepTempRule{ |
public class RepTempRuleTwo extends RepTempRule{ public void replace() throws Exception{ newString=oldString.replaceFirst("aaa", "ccc") System.out.println("this is replace Two"); } } |
W二步:我们要徏立一个算法解决类Q用来提供客L可以自由选择法?/p>
public class RepTempRuleSolve {
private RepTempRule strategy; public RepTempRuleSolve(RepTempRule rule){ public String getNewContext(Site site,String oldString) { public void changeAlgorithm(RepTempRule newAlgorithm) { } |
调用如下:
public class test{ ...... public void testReplace(){ //使用W一套替代方?br /> RepTempRuleSolve solver=new RepTempRuleSolve(new RepTempRuleSimple()); //使用W二?/p> solver=new RepTempRuleSolve(new RepTempRuleTwo());
} ..... } |
我们辑ֈ了在q行期间Q可以自由切换算法的目的?/p>
实际整个Strategy的核心部分就是抽象类的?使用Strategy模式可以在用户需要变化时,修改量很?而且快?
Strategy和Factory有一定的cM,Strategy相对单容易理?q且可以在运行时刻自由切换。Factory重点是用来创建对象?/p>
Strategy适合下列场合:
1.以不同的格式保存文g;
2.以不同的法压羃文g;
3.以不同的法截获图象;
4.以不同的格式输出同样数据的图?比如曲线 或框图bar{?/p>
我们以类SampleZQ?如果我们要创建Sample的实例对?
Sample sample=new Sample();
可是Q实际情冉|Q通常我们都要在创建sample实例时做点初始化的工?比如
赋?查询数据库等。首先,我们惛_的是Q可以用Sample的构造函敎ͼq样
生成实例写? Sample sample=new Sample(参数);
但是Q如果创建sample实例时所做的初始化工作不是象赋DL单的事,可能
是很长一D代码,如果也写入构造函CQ那你的代码很难看了Q就需要Refactor重整Q?br />Z么说代码很难看,初学者可能没有这U感觉,我们分析如下Q初始化工作如果
是很长一D代码,说明要做的工作很多,很多工作装入一个方法中Q相当于很多鸡
蛋放在一个篮子里Q是很危险的Q这也是有背于Java面向对象的原则,面向对象?br />装(Encapsulation)和分z?Delegation)告诉我们Q尽量将长的代码分派“切剜y成
每段Q将每段再“封装”v?减少D和D之间偶合联pL?Q这P׃风险分散,
以后如果需要修改,只要更改每段Q不会再发生牵一动百的事情?br />在本例中Q首先,我们需要将创徏实例的工作与使用实例的工作分开, 也就是说Q?br />让创建实例所需要的大量初始化工作从Sample的构造函C分离出去?br />q时我们需要Factory工厂模式来生成对象了Q不能再用上面简单new Sample(参数)?br />q有,如果Sample有个l承如MySample, 按照面向接口~程,我们需要将Sample抽象成一?br />接口.现在Sample是接?有两个子cMySample 和HisSample .我们要实例化他们?如下:
Sample mysample=new MySample();
Sample hissample=new HisSample();
随着目的深?Sample可能q会"生出很多儿子出来", 那么我们要对q些儿子一个个
实例?更糟p的?可能q要对以前的代码q行修改:加入后来生出儿子的实?q在?br />l程序中是无法避免的.
但如果你一开始就有意识用了工厂模式,q些ȝ没有了.
工厂Ҏ
你会建立一个专门生产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?׃?br />Sample sampleA=Factory.creator(1);
q样,在整个就不涉及到Sample的具体子c?辑ֈ装效果,也就减少错误修改的机?
q个原理可以用很通俗的话来比?是具体事情做得多,容易范错误.q每个做
q具体工作的人都深有体会,相反,官做得越?说出的话抽象越W统,范错误可能?br />p?好象我们从编E序中也能悟Zh生道?呵呵.
使用工厂Ҏ要注意几个角Ԍ首先你要定义产品接口Q如上面的Sample,产品接口
下有Sample接口的实现类,如SampleA,其次要有一个factoryc,用来生成产品Sample?br />q一步稍微复杂一点,是在工厂类上进行拓展,工厂cM有承它的实现类
concreteFactory了?br />抽象工厂
工厂模式中有: 工厂Ҏ(Factory Method) 抽象工厂(Abstract Factory).
q两个模式区别在于需要创建对象的复杂E度上。如果我们创建对象的Ҏ变得复杂?
如上面工厂方法中是创Z个对象Sample,如果我们q有新的产品接口Sample2.
q里假设QSample有两个concretecSampleA和SamleBQ而Sample2也有两个concretec?br />Sample2A和SampleB2Q那么,我们将上例中Factory变成抽象c?共同部分封装在?br />象类?不同部分使用子类实现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,也许你会疑问Qؓ什么我
不可以用两个工厂方法来分别生Sample和Sample2?
抽象工厂q有另外一个关键要点,是因?SimpleFactory内,生Sample和生?br />Sample2的方法之间有一定联p,所以才要将q两个方法捆l在一个类中,q个工厂
cL其本w特征,也许刉过E是l一的,比如Q制造工艺比较简单,所以名U?br />叫SimpleFactory?br />在实际应用中Q工厂方法用得比较多一些,而且是和动态类装入器组合在一起应用,
举例
我们以Jive的ForumFactoryZQ这个例子在前面的Singleton模式中我们讨Q?br />现在再讨论其工厂模式:
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;
}
//以下使用了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;
....
}
因ؓ现在的Jive是通过数据库系l存放论坛帖子等内容数据,如果希望更改为通过文gpȝ实现,q个工厂ҎForumFactory提供了提供动态接?
private static String className = "com.jivesoftware.forum.database.DbForumFactory";
你可以用自己开发的创徏forum的方法代替com.jivesoftware.forum.database.DbForumFactory可?
在上面的一D代码中一q了三U模?除了工厂模式?q有Singleton单态模?以及proxy模式,proxy模式主要用来授权用户对forum的访?因ؓ讉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是典型的工厂ҎQcatDao是通过动态类装入器className获得CatalogDAOFactory具体实现子类Q这个实现子cdJava宠物店是用来操作catalog数据库,用户可以Ҏ数据库的cd不同Q定制自q具体实现子类Q将自己的子cdl与CATALOG_DAO_CLASS变量可以?/p>
由此可见Q工厂方法确实ؓpȝl构提供了非常灵zd大的动态扩展机Ӟ只要我们更换一下具体的工厂ҎQ系l其他地Ҏ需一点变换,有可能系l功能进行改头换面的变化?/p>
设计模式如何在具体项目中应用见《Java实用pȝ开发指南?/p>