板桥里h http://www.jdon.com 2002/05/05
Interpreter解释器模式定?
定义语言的文?,q且建立一个解释器来解释该语言中的句子.
Interpreterg使用面不是很q?它描qC一个语a解释器是如何构成?在实际应用中,我们可能很少L造一个语a的文?我们q是来简单的了解一?
首先要徏立一个接?用来描述共同的操?
public interface AbstractExpression {
void interpret( Context context );
}
再看看包含解释器之外的一些全局信息
public interface Context { }
AbstractExpression的具体实现分两种:l结W表辑ּ和非l结W表辑ּ:
对于文法中没一条规?非终l符表达式都必须?
板桥里h http://www.jdon.com 2002/05/05Q{载请保留Q?/p>
Visitor讉K者模式定?/b>
作用于某个对象群中各个对象的操作. 它可以你在不改变这些对象本w的情况?定义作用于这些对象的新操?
在Java?Visitor模式实际上是分离了collectionl构中的元素和对q些元素q行操作的行?
Z使用Visitor?
Java的Collection(包括Vector和Hashtable)是我们最l常使用的技?可是Collection好象是个黑色大染~?本来有各U鲜明类型特征的对象一旦放入后,再取出时,q些cd消׃.那么我们势必要用If来判??
Iterator iterator = collection.iterator()
while (iterator.hasNext()) {
Object o = iterator.next();
if (o instanceof Collection)
messyPrintCollection((Collection)o);
else if (o instanceof String)
System.out.println("'"+o.toString()+"'");
else if (o instanceof Float)
System.out.println(o.toString()+"f");
else
System.out.println(o.toString());
}
在上例中,我们使用?instanceof来判?o的类?
很显?q样做的~点代码If else if 很繁?我们可以用Visitor模式解决?
如何使用Visitor?
针对上例,定义接口叫Visitable,用来定义一个Accept操作,也就是说让Collection每个元素具备可访问?
被访问者是我们Collection的每个元素Element,我们要ؓq些Element定义一个可以接受访问的接口(讉K和被讉K是互动的,只有讉K?被访问者如果表CZƢ迎,讉K者就不能讉K),取名为VisitableQ也可取名ؓElement?/p>
public interface Visitable { public void accept(Visitor visitor); } |
被访问的具体元素l承q个新的接口VisitableQ?/p>
public class StringElement implements Visitable public String getValue(){
|
上面是被讉K者是字符串类型,下面再徏立一个Floatcd的:
public class FloatElement implements Visitable public Float getValue(){
|
我们设计一个接口visitor讉K者,在这个接口中,有一些访问操作,q些讉K操作是专门访问对象集合Collection中有可能的所有类Q目前我们假定有三个行ؓQ访问对象集合中的字W串cdQ访问对象集合中的FloatcdQ访问对象集合中的对象集合类型。注意最后一个类型是集合嵌套Q通过q个嵌套实现可以看出使用讉K模式的一个优炏V?/p>
接口visitor讉K者如下:
public interface Visitor |
讉K者的实现:
public class ConcreteVisitor implements Visitor public void visitString(StringElement stringE) { } |
在上面的visitCollection我们实现了对Collection每个元素讉K,只用了一个判断语?只要判断其是否可以访?
StringElement只是一个实玎ͼ可以拓展为更多的实现Q整个核心奥妙在acceptҎ中,在遍历CollectionӞ通过相应的acceptҎ调用具体cd的被讉K者。这一步确定了被访问者类型,
如果是StringElementQ而StringElement则回调访问者的visiteStringҎQ这一步实C行ؓ操作Ҏ?/p>
客户端代码:
Visitor visitor = new ConcreteVisitor(); Collection list = new ArrayList(); |
客户端代码中的list对象集合中放|了多种数据cdQ对对象集合中的讉K不必象一开始那P使用instance of逐个判断Q而是通过讉K者模式y妙实C?/p>
x,我们完成了Visitor模式基本l构.
使用Visitor模式的前?/b>
使用讉K者模式是对象结构中(Collection) 中的对象cd很少改变?/p>
在两个接口Visitor和Visitable?保Visitable很少变化,也就是说Q确保不能老有新的Element元素cd加进来,可以变化的是讉K者行为或操作Q也是Visitor的不同子cd以有多种,q样使用讉K者模式最方便.
如果对象集合中的对象集合l常有变? 那么不但Visitor实现要变化,Visistable也要增加相应行ؓQGOF?不如在这些对象类中直接逐个定义操作Q无需使用讉K者设计模式?/p>
但是在Java中,Java的Reflect技术解决了q个问题Q因此结合reflect反射机制Q可以得访问者模式适用范围更广了?/p>
Reflect技术是在运行期间动态获取对象类型和Ҏ的一U技?具体实现参考Javaworld?a target="_blank">英文原文.
板桥里h http://www.jdon.com 2002/03/30
Strategy{略模式是属于设计模式中 对象行ؓ型模?主要是定义一pd的算?把这些算法一个个装成单独的c?
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.以不同的法截获图象;
板桥里h http://www.jdon.com 2002/05/05
Mediator中介者模式定?
用一个中介对象来装一pd关于对象交互行ؓ.
Z使用Mediator?
各个对象之间的交互操作非常多;每个对象的行为操作都依赖彼此Ҏ,修改一个对象的行ؓ,同时会涉及到修改很多其他对象的行?如果使用Mediator模式,可以使各个对象间的耦合松散,只需兛_?Mediator的关p?使多对多的关pd成了一对多的关p?可以降低pȝ的复杂?提高可修Ҏ展?
如何使用?
首先 有一个接?用来定义成员对象之间的交互联pL?
public interface Mediator { } |
Meiator具体实现,真正实现交互操作的内?
public class ConcreteMediator implements Mediator { //假设当前有两个成? ... } |
再看看另外一个参与?成员,因ؓ是交互行?都需要双Ҏ供一些共同接?q种要求在Visitor Observer{模式中都是相同?
public class Colleague { public class ConcreteColleague1 { } public class ConcreteColleague2 { } |
每个成员都必ȝ道Mediator,q且?Mediator联系,而不是和其他成员联系.
x,Mediator模式框架完成,可以发现Mediator模式规定不是很多,大体框架也比较简?但实际用v来就非常灉|.
Mediator模式在事仉动类应用中比较多,例如界面设计GUI.;聊天,消息传递等,在聊天应用中,需要有一个MessageMediator,专门负责request/reponse之间d的调?
MVC是J2EE的一个基本模?View Controller是一UMediator,它是Jsp和服务器上应用程序间的Mediator.
板桥里h http://www.jdon.com 2002/04/21(转蝲请保?
Chain of Responsibility定义
Chain of Responsibility(CoR) 是用一pdc?classes)试图处理一个请求request,q些cM间是一个松散的耦合,唯一共同Ҏ在他们之间传递request. 也就是说Q来了一个请求,Acd处理Q如果没有处理,׃递到Bcd理,如果没有处理Q就传递到Ccd理,p栯一个链?chain)一样传递下厅R?/p>
如何使用?
虽然q一D|如何使用CoR,但是也是演示什么是CoR.
有一个Handler接口:
public interface Handler{
public void handleRequest();
}
q是一个处理request的事例, 如果有多Urequest,比如 h帮助 h打印 或请求格式化Q?br />
最先想到的解决Ҏ是:在接口中增加多个hQ?br />public interface Handler{
public void handleHelp();
public void handlePrint();
public void handleFormat();
}
具体是一D实现接口Handler代码Q?br />public class ConcreteHandler implements Handler{
private Handler successor;
public ConcreteHandler(Handler successor){
this.successor=successor;
}
public void handleHelp(){
//具体处理hHelp的代?br /> ...
}
public void handlePrint(){
//如果是print 转去处理Print
successor.handlePrint();
}
public void handleFormat(){
//如果是Format 转去处理format
successor.handleFormat();
}
}
一共有三个q样的具体实现类Q上面是处理help,q有处理Print 处理Formatq大概是我们最常用的编E思\?/p>
虽然思\单明了,但是有一个扩展问题,如果我们需要再增加一个请求requestU类,需要修Ҏ口及其每一个实现?/p>
W二Ҏ:每Urequest都变成一个接口,因此我们有以下代?Q?/p>
public interface HelpHandler{
public void handleHelp();
}
public interface PrintHandler{
public void handlePrint();
}
public interface FormatHandler{
public void handleFormat();
}
public class ConcreteHandler
implements HelpHandler,PrintHandler,FormatHandlet{
private HelpHandler helpSuccessor;
private PrintHandler printSuccessor;
private FormatHandler formatSuccessor;
public ConcreteHandler(HelpHandler helpSuccessor,PrintHandler printSuccessor,FormatHandler formatSuccessor)
{
this.helpSuccessor=helpSuccessor;
this.printSuccessor=printSuccessor;
this.formatSuccessor=formatSuccessor;
}
public void handleHelp(){
.......
}
public void handlePrint(){this.printSuccessor=printSuccessor;}
public void handleFormat(){this.formatSuccessor=formatSuccessor;}
}
q个办法在增加新的请求request情况下,只是节省了接口的修改量,接口实现ConcreteHandlerq需要修攏V而且代码昄不简单美丽?/p>
解决Ҏ3: 在Handler接口中只使用一个参数化ҎQ?br />public interface Handler{
public void handleRequest(String request);
}
那么Handler实现代码如下Q?br />public class ConcreteHandler implements Handler{
private Handler successor;
public ConcreteHandler(Handler successor){
this.successor=successor;
}
public void handleRequest(String request){
if (request.equals("Help")){
//q里是处理Help的具体代?br /> }else
//传递到下一?br /> successor.handle(request);
}
}
}
q里先假设request是StringcdQ如果不是怎么办?当然我们可以创徏一个专门类Request
最后解x?接口Handler的代码如下:
public interface Handler{
public void handleRequest(Request request);
}
Requestcȝ定义:
public class Request{
private String type;
public Request(String type){this.type=type;}
public String getType(){return type;}
public void execute(){
//request真正具体行ؓ代码
}
}
那么Handler实现代码如下Q?br />public class ConcreteHandler implements Handler{
private Handler successor;
public ConcreteHandler(Handler successor){
this.successor=successor;
}
public void handleRequest(Request request){
if (request instanceof HelpRequest){
//q里是处理Help的具体代?br /> }else if (request instanceof PrintRequst){
request.execute();
}else
//传递到下一?br /> successor.handle(request);
}
}
}
q个解决Ҏ是CoR, 在一个链?都有相应职责的类,因此?b>Chain of Responsibility.
CoR的优点:
因ؓ无法预知来自外界Q客LQ的h是属于哪U类型,每个cd果碰到它不能处理的请求只要放弃就可以?/p>
~点是效率低Q因Z个请求的完成可能要遍历到最后才可能完成Q当然也可以用树的概念优化?在Java AWT1.0中,对于鼠标按键事情的处理就是用CoR,到Java.1.1以后Q就使用Observer代替CoR
扩展性差Q因为在CoR中,一定要有一个统一的接口Handler.局限性就在这里?/p>
与Command模式区别Q?/strong>
Command 模式需要事先协商客L和服务器端的调用关系Q比?1 代表 start 2 代表 move {,q些 都是装?request 中,到达服务器端再分解?/p>
CoR 模式无需q种事先U定Q服务器端可以?CoR 模式q行客户端请求的猜测Q一个个猜测 试验?
板桥里h http://www.jdon.com 2002/4/23/Q{载请保留Q?/p>
Command模式是最让我疑惑的一个模?我在阅读了很多代码后,才感觉隐U掌握其大概原理,我认为理解设计模式最主要是掌握v原理构?q样才对自己实际~程有指g?Command模式实际上不是个很具?规定很多的模?正是q个灉|?让h有些confuse.
Command定义
n 来自客L的请求传入一个对象,无需了解q个hȀzȝ 动作或有x受这个请求的处理l节?/p>
q是一U两台机器之间通讯联系性质的模式,cM传统q程?a?CallBack功能?
优点Q?br />解耦了发送者和接受者之间联pR?发送者调用一个操作,接受者接受请求执行相应的动作Q因Z用Command模式解耦,发送者无需知道接受者Q何接口?/p>
不少Command模式的代码都是针对图形界面的,它实际就是菜单命?我们在一个下拉菜单选择一个命令时,然后会执行一些动?
这些命令封装成在一个类?然后用户(调用?再对q个c进行操?q就是Command模式,换句话说,本来用户(调用?是直接调用这些命令的,如菜单上打开文档(调用?,q接指向打开文档的代?使用Command模式,是在这两者之间增加一个中间?这U直接关pL?同时两者之间都隔离,基本没有关系?
昄q样做的好处是符合封装的Ҏ?降低耦合?Command是将对行行封装的典型模式,Factory是将创徏q行装的模?
从Command模式,我也发现设计模式一?通病":好象喜欢简单的问题复杂? 喜欢在不同类中增加第三?当然q样做有利于代码的健壮?可维护?q有复用?
如何使用?
具体的Command模式代码各式各样,因ؓ如何装命o,不同pȝ,有不同的做法.下面事例是将命o装在一个Collection的List?M对象一旦加入List?实际上装入了一个封闭的黑盒?对象的特性消׃,只有取出?才有可能模糊的分辨出:
public interface Command { public abstract void execute ( ); } |
public class Engineer implements Command { public void execute( ) { //do Engineer's command } } public class Programmer implements Command { public class Politician implements Command { |
按照通常做法,我们可以直接调用这三个Command,但是使用Command模式,我们要将他们装h,扔到黑盒子List里去:
public class producer{ } |
q三个命令进入List中后,已经失去了其外表特征,以后再取?也可能无法分辨出谁是Engineer 谁是Programmer?看下面客L如何调用Command模式:
public class TestCommand { } |
由此可见,调用者基本只和接口打交道,不合具体实现交互,q也体现了一个原?面向接口~程,q样,以后增加W四个具体命令时,׃必修改调用者TestCommand中的代码?
理解了上面的代码的核心原?在用中,应该各人有自己Ҏ?特别是在如何分离调用者和具体命o?有很多实现方?上面的代码是使用"从Listq一?的做?q种做法只是Z演示.
使用Command模式的一个好理由q因为它能实现Undo功能.每个具体命o都可以记住它刚刚执行的动?q且在需要时恢复.
Command模式在界面设计中应用q泛.Java的Swing中菜单命令都是用Command模式,׃Java在界面设计的性能上还有欠~?因此界面设计具体代码我们׃讨论,|络上有很多q样的示?
参?
http://www.patterndepot.com/put/8/command.pdf
http://www.javaworld.com/javaworld/javatips/jw-javatip68.html
设计模式如何在具体项目中应用?a target="_blank">《Java实用pȝ开发指南?/font>
板桥里h http://www.jdon.com 2002/4/6/
State模式的定?/b> : 不同的状?不同的行?或者说,每个状态有着相应的行?
何时使用
?
State模式在实际用中比较?适合"状态的切换".因ؓ我们l常会用If elseif else q行状态切? 如果针对状态的q样判断切换反复出现,我们p联想到是否可以采取State模式?
不只是根据状?也有Ҏ属?如果某个对象的属性不?对象的行为就不一?q点在数据库pȝ中出现频率比较高,我们l常会在一个数据表的尾?加上property属性含义的字段,用以标识记录中一些特D性质的记?q种属性的改变(切换)又是随时可能发生?有可能要用State.
是否使用?
在实际?cM开关一L状态切换是很多?但有时ƈ不是那么明显,取决于你的经验和对系l的理解深度.
q里要阐q的?开兛_换状? ? 一般的状态判?是有一些区别的, " 一般的状态判?也是?if..elseifl构,例如:
if (which==1) state="hello";
else if (which==2) state="hi";
else if (which==3) state="bye";
q是一?" 一般的状态判?,state值的不同是根据which变量来决定的,which和state没有关系.如果Ҏ:
if (state.euqals("bye")) state="hello";
else if (state.euqals("hello")) state="hi";
else if (state.euqals("hi")) state="bye";
q就?"开兛_换状?,是将state的状态从"hello"切换?hi",再切换到""bye";在切换到"hello",好象一个旋转开?q种状态改变就可以使用State模式?
如果单纯有上面一U将"hello"-->"hi"-->"bye"-->"hello"q一个方向切?也不一定需要用State模式,因ؓState模式会徏立很多子c?复杂?但是如果又发生另外一个行?上面的切换方向反过来切?或者需要Q意切?需要State?
L下例:
public class Context{ private Color state=null; public void push(){ //如果当前red状?切换到blue public void pull(){ if (state==Color.green) state=Color.blue; } |
在上例中,我们有两个动作push推和pull?q两个开兛_?改变了Context颜色,x,我们需要用State模式优化?
另外注意:但就上例,state的变?只是单的颜色赋?q个具体行ؓ是很单的,State适合巨大的具体行?因此?本?实际使用中也不一定非要用State模式,q会增加子类的数?单的变复?
例如: 银行帐户, l常会在Open 状态和Close状态间转换.
例如: l典的TcpConnection, Tcp的状态有创徏 侦听 关闭三个,q且反复转换,其创?侦听 关闭的具体行Z是简单一两句p完成?适合使用State
例如:信箱POP帐号, 会有四种状? start HaveUsername Authorized quit,每个状态对应的行ؓ应该是比较大?适合使用State
例如:在工L挑选不同工?可以看成在不同工具中切换,适合使用State.?具体l图E序,用户可以选择不同工具l制Ҏ 直线 曲线,q种状态切换可以用State.
如何使用
State需要两U类型实体参?
1.state manager 状态管理器 ,是开?,如上面例子的Context实际是一个state manager, 在state manager中有对状态的切换动作.
2.用抽象类或接口实现的父类,,不同状态就是承这个父cȝ不同子类.
以上面的ContextZ.我们要修改它,建立两个cd的实?
W一? 首先建立一个父c?
public abstract class State{ public abstract void handlepush(Context c); } |
父类中的Ҏ要对应state manager中的开兌?在state manager?本例是Context?有两个开兛_作push推和pull?那么在状态父cMp有具体处理这两个动作:handlepush() handlepull(); 同时q需要一个获取push或pulll果的方法getcolor()
下面是具体子cȝ实现:
public class BlueState extends State{ public void handlepush(Context c){ } //ҎpullҎ"如果是blue状态的切换到red" ; } public abstract void getcolor(){ return (Color.blue)} }
|
同样 其他状态的子类实现如blue一?
W二? 要重新改写State manager 也就是本例的Context:
public class Context{ private Sate state=null; //我们原来的 Color state Ҏ了新建的State state; //setState是用来改变state的状?使用setState实现状态的切换 } public void push(){ //状态的切换的细节部?在本例中是颜色的变化,已经装在子cȝhandlepush中实?q里无需兛_ }
public void pull(){ state.handlepull(this); } }
|
x,我们也就实现了State的refactoryingq程.
以上只是相当单的一个实?在实际应用中,handlepush或handelpull的处理是复杂?
状态模式优点:
Q?Q?装转换q程Q也是转换规则
Q?Q?枚D可能的状态,因此Q需要事先确定状态种cR?br />
状态模式可以允许客L改变状态的转换行ؓQ而状态机则是能够自动改变状态,状态机是一个比较独立的而且复杂的机Ӟ具体可参考一个状态机开源项目:http://sourceforge.net/projects/smframework/
状态模式在工作或游戏{各U系l中有大量用,甚至是这些系l的核心功能设计Q例如政府OA中,一个批文的状态有多种Q未办;正在办理Q正在批C;正在审核Q已l完成等各种状态,使用状态机可以装q个状态的变化规则Q从而达到扩充状态时Q不必涉及到状态的使用者?/p>
在网l游戏中Q一个游戏活动存在开始;开玩;正在玩;输赢{各U状态,使用状态模式就可以实现游戏状态的LQ而游戏状态决定了游戏的各个方面,使用状态模式可以对整个游戏架构功能实现起到军_的主g用?/p>
状态模式实?/strong>Q?br />使用状态模式前Q客L外界需要介入改变状态,而状态改变的实现是琐或复杂的?/p>
使用状态模式后Q客L外界可以直接使用事gEvent实现Q根本不必关心该事gD如何状态变化,q些是由状态机{内部实现?/p>
q是一UEvent-condition-StateQ状态模式封装了condition-State部分?/p>
每个状态Ş成一个子c,每个状态只兛_它的下一个可能状态,从而无形中形成了状态{换的规则。如果新的状态加入,只涉及它的前一个状态修改和定义?/p>
状态{换有几个Ҏ实现Q一个在每个状态实现next()Q指定下一个状态;q有一U方法,讑֮一个StateOwnerQ在StateOwner讑֮stateEnter状态进入和stateExit状态退为?/p>
状态从一个方面说明了程Q流E是随时间而改变,状态是截取程某个旉片?/p>
参考资?
相关文章Q?/p>
the State and Stategy
How to implement state-dependent behavior
The state patterns
]]>
板桥里h http://www.jdon.com 2002/3/16
Java深入C定程?׃可避免的到设计模式(design pattern)q一概念,了解设计模式,自己对java中的接口或抽象类应用有更q理解.设计模式在java的中型系l中应用q泛,遵@一定的~程模式,才能使自q代码便于理解,易于交流,Observer(观察?模式是比较常用的一个模?其在界面设计中应用q泛,而本站所x的是Java在电子商务系l中应用,因此想从电子商务实例中分析Observer的应?
虽然|上商店形式多样,每个站点有自q特色,但也有其一般的共?单就"商品的变?以便及时通知订户"q一?是很多网上商店共有的模式,q一模式cMObserver patern观察者模?
具体的说,如果|上商店中商品在名称 h{方面有变化,如果pȝ能自动通知会员,是|上商店区别传统商店的一大特?q就需要在商品product中加入Observerq样角色,以便productl节发生变化?Observer能自动观察到q种变化,q能q行及时的update或notify动作.
Java的APIqؓ为我们提供现成的Observer接口Java.util.Observer.我们只要直接使用它就可以.
我们必须extends Java.util.Observer才能真正使用?
1.提供Add/Delete observer的方?
2.提供通知(notisfy) 所有observer的方?
//产品c?可供Jsp直接使用UseBean调用 该类主要执行产品数据库插?更新 public class product extends Observable{ private String name; public String getName(){ return name;} } public float getPrice(){ return price;} } } |
我们注意?在productcM 的setXXXҎ?我们讄?notify(通知)Ҏ, 当Jsp表单调用setXXX(如何调用见我?a target="_blank">另外一文?/font>),实际上就触发了notisfyObserversҎ,q将通知相应观察者应该采取行动了.
下面看看q些观察者的代码,他们I竟采取了什么行?
//观察者NameObserver主要用来对品名U?name)q行观察?br />public class NameObserver implements Observer{ private String name=null; public void update(Observable obj,Object arg){ name=(String)arg; } } } //观察者PriceObserver主要用来对品h?price)q行观察?br />public class PriceObserver implements Observer{ private float price=0; public void update(Observable obj,Object arg){ price=((Float)arg).floatValue(); } } } |
Jsp中我们可以来正式执行q段观察者程?
<jsp:useBean id="product" scope="session" class="Product" />
<jsp:useBean id="nameobs" scope="session" class="NameObserver" />
<jsp:useBean id="priceobs" scope="session" class="PriceObserver" /> <% }else{ %> //request.getRequestURI()是生本jsp的程序名,是自己调用自己 <input type=hidden name="save" value="1"> </form> <% %>
|
执行改JspE序,会出C个表单录入界? 需要输入品名U?产品h, ҎSubmit?q是执行该jsp?br />if (request.getParameter("save")!=null)之间的代?
׃q里使用了数据javabeans的自动赋值概?实际E序自动执行了setName setPrice语句.你会在服务器控制C发现下面信息::
NameObserver :name changet to ?????(Jsp表单中输入的产品名称)
PriceObserver :price changet to ???(Jsp表单中输入的产品h);
q说明观察者已l在行动?!!
同时你会在执行jsp的浏览器端得C?
产品数据变动 保存! q已l自动通知客户
上文׃使用jsp概念,隐含很多自动动作,现将调用观察者的Java代码写如?
public class Test { public static void main(String args[]){ Product product=new Product(); //加入观察?br />product.addObserver(nameobs); product.setName("子U了"); } }
|
你会在发C面信?:
NameObserver :name changet to 子U了
PriceObserver :price changet to 9.22
q说明观察者在行动?!!
设计模式如何在具体项目中应用?a target="_blank">《Java实用pȝ开发指南?/font>
板桥里h http://www.jdon.com 2002/05/05
Template模板模式定义:
定义一个操作中法的骨?一些步骤的执行延迟到其子类?
使用Java的抽象类Ӟq怼使用到Template模式,因此Template模式使用很普?而且很容易理解和使用?/p>
public abstract class Benchmark { /** * 下面操作是我们希望在子类中完?br /> */ public abstract void benchmark(); /** for (int i = 0; i < count; i++) |
在上例中,我们希望重复执行benchmark()操作,但是对benchmark()的具体内Ҏ有说?而是延迟到其子类中描q?
public class MethodBenchmark extends Benchmark { /** * 真正定义benchmark内容 */ public void benchmark() { for (int i = 0; i < Integer.MAX_VALUE; i++){ System.out.printtln("i="+i); } } } |
x,Template模式已经完成,是不是很?
我们UrepeatҎ为模板方法, 它其中的benchmark()实现被gq到子类MethodBenchmark中实CQ?/p>
看看如何使用:
Benchmark operation = new MethodBenchmark();
long duration = operation.repeat(Integer.parseInt(args[0].trim()));
System.out.println("The operation took " + duration + " milliseconds");
也许你以前还疑惑抽象cL什么用,现在你应该彻底明白了? 至于q样做的好处,很显然啊,扩展性强,以后Benchmark内容变化,我只要再做一个承子cd可以,不必修改其他应用代码.
板桥里h http://www.jdon.com 2002/05/05
Memento备望录模式定?
memento是一个保存另外一个对象内部状态拷贝的对象.q样以后可以将该对象恢复到原先保存的状?
Memento模式相对也比较好理解,我们看下列代?
public class Originator { private int number; private File file = null; public Originator(){} // 创徏一个Memento // 恢复到原始?br /> public void setMemento(Memento m){ }
|
我们再看看Mementoc?
private class Memento implements java.io.Serializable{ private int number; private File file = null; public Memento( Originator o){ number = o.number; } }
|
可见 Memento中保存了Originator中的number和file的? 通过调用Originator中number和file值改变的?通过调用setMemento()Ҏ可以恢复.
Memento模式的缺Ҏ耗费?如果内部状态很?再保存一?无意要浪费大量内?
Memento模式在Jsp+Javabean中的应用
在Jsp应用?我们通常有很多表单要求用戯?比如用户注册,需要输入姓名和Email{? 如果一些表用h有填写或者填写错?我们希望在用h"提交Submit"?通过JspE序?发现实有未填写目,则在该项目下U字昄警告或错?同时,q要昄用户刚才已经输入的表?
如下图中 First Name是用户已l输?Last Name没有输入,我们则提C红字警?:
q种技术的实现,是利用了Javabean的scope="request"或scope="session"Ҏ?也就是Memento模式.
具体CZ和代码见 JavaWorld的英文原?/font> , Javabean表单输入Ҏ参见我的另?a target="_blank">一文?
板桥里h http://www.jdon.com 2002/05/01
Bridge模式定义 :
抽象和行ؓ划分开?各自独立,但能动态的l合?/p>
M事物对象都有抽象和行Z分,例如人,人是一U抽象,人分男h和女人等Qh有行为,行ؓ也有各种具体表现Q所以,“h”与“h的行为”两个概念也反映了抽象和行ؓ之分?/p>
在面向对象设计的基本概念中,对象q个概念实际是由属性和行ؓ两个部分l成的,属性我们可以认为是一U静止的Q是一U抽象,一般情况下Q行为是包含在一个对象中Q但是,在有的情况下Q我们需要将q些行ؓ也进行归c,形成一个ȝ行ؓ接口Q这是桥模式的用处?/p>
Z么?
不希望抽象部分和行ؓ有一U固定的l定关系Q而是应该可以动态联pȝ?/p>
如果一个抽象类或接口有多个具体实现(子类、concrete subclass),q些子类之间关系可能有以下两U情?
1. q多个子cM间概忉|q列?如前面D?打桩,有两个concrete class:方Ş桩和圆Ş?q两个Ş状上的桩是ƈ列的,没有概念上的重复?br />
2.q多个子cM中有内容概念上重?那么需要我们把抽象共同部分和行为共同部分各自独立开?原来是准备放在一个接口里,现在需要设计两个接口:抽象接口和行为接口,分别攄抽象和行?
例如,一杯咖啡ؓ?子类实现cMؓ四个Q中杯加奶、大杯加奶?中杯不加奶、大杯不加奶?/p>
但是Q我们注意到Q上面四个子cM有概念重叠,可从另外一个角度进行考虑Q这四个cd际是两个角色的组合:抽象 和行为,其中抽象为:中杯和大杯;行ؓ为:加奶 不加Ӟ如加汁 加苹果汁Q?
实现四个子类在抽象和行ؓ之间发生了固定的l定关系Q如果以后动态增加加葡萄汁的行ؓQ就必须再增加两个类Q中杯加葡萄汁和大杯加葡萄汁。显然?扩展性极差?/p>
那我们从分离抽象和行为的角度Q用Bridge模式来实现?/p>
如何实现?
以上面提到的咖啡 Z. 我们原来打算只设计一个接?抽象c?,使用Bridge模式?我们需要将抽象和行为分开,加奶和不加奶属于行ؓ,我们它们抽象成一个专门的行ؓ接口.
先看看抽象部分的接口代码:
public abstract class Coffee { CoffeeImp coffeeImp; public void setCoffeeImp() { this.CoffeeImp = CoffeeImpSingleton.getTheCoffeImp(); } public CoffeeImp getCoffeeImp() {return this.CoffeeImp;} public abstract void pourCoffee(); } |
其中CoffeeImp 是加不加奶的行ؓ接口,看其代码如下:
public abstract class CoffeeImp { public abstract void pourCoffeeImp(); } |
现在我们有了两个抽象c?下面我们分别对其q行l承,实现concrete class:
//中杯 //大杯 |
上面分别是中杯和大杯的具体实?下面再对行ؓCoffeeImpq行l承:
//加奶 //不加?br />public class FragrantCoffeeImp extends CoffeeImp |
Bridge模式的基本框架我们已l搭好了,别忘记定义中q有一?动态结?我们现在可以喝到臛_四种咖啡:
1.中杯加奶
2.中杯不加?br />3.大杯加奶
4.大杯不加?/p>
看看是如何动态结合的,在用之?我们做个准备工作,设计一个单态类(Singleton)用来hold当前的CoffeeImp:
public class CoffeeImpSingleton { private static CoffeeImp coffeeImp; public CoffeeImpSingleton(CoffeeImp coffeeImpIn) {this.coffeeImp = coffeeImpIn;} public static CoffeeImp getTheCoffeeImp() { return coffeeImp; } } |
看看中杯加奶 和大杯加?是怎么出来?
//拿出牛奶
CoffeeImpSingleton coffeeImpSingleton = new CoffeeImpSingleton(new MilkCoffeeImp());
//中杯加奶
MediumCoffee mediumCoffee = new MediumCoffee();
mediumCoffee.pourCoffee();
//大杯加奶
SuperSizeCoffee superSizeCoffee = new SuperSizeCoffee();
superSizeCoffee.pourCoffee();
注意: Bridge模式的执行类如CoffeeImp和Coffee是一对一的关p? 正确创徏CoffeeImp是该模式的关?
Bridge模式在EJB中的应用
EJB中有一个Data Access Object (DAO)模式,q是商业逻辑和具体数据资源分开?因ؓ不同的数据库有不同的数据库操?操作不同数据库的行为独立抽象成一个行为接口DAO.如下:
1.Business Object (cMCoffee)
实现一些抽象的商业操作:如寻找一个用户下所有的订单
涉及数据库操作都使用DAOImplementor.
2.Data Access Object (cMCoffeeImp)
一些抽象的Ҏ据库资源操作
3.DAOImplementor 如OrderDAOCS, OrderDAOOracle, OrderDAOSybase(cMMilkCoffeeImp FragrantCoffeeImp)
具体的数据库操作,?INSERT INTO "{语?OrderDAOOracle是Oracle OrderDAOSybase是Sybase数据?
4.数据?(Cloudscape, Oracle, or Sybase database via JDBC API)
板桥里h http://www.jdon.com 2002/05/02
Flyweight模式定义:
避免大量拥有相同内容的小cȝ开销(如耗费内存),使大家共享一个类(元类).
Z么?
面向对象语言的原则就是一切都是对?但是如果真正使用h,有时对象数可能显得很庞大,比如,字处理Y?如果以每个文字都作ؓ一个对?几千个字,对象数就是几?无疑耗费内存,那么我们q是?求同存异",扑ևq些对象的共同?设计一个元c?装可以被共享的c?另外,q有一些特性是取决于应?context),是不可共享的,q也Flyweight中两个重要概念内部状态intrinsic和外部状态extrinsic之分.
说白?是先捏一个的原始模型,然后随着不同场合和环?再生各L征的具体模型,很显?在这里需要生不同的新对?所以Flyweight模式中常出现Factory模式.Flyweight的内部状态是用来׃n?Flyweight factory负责l护一个Flyweight pool(模式?来存攑ֆ部状态的对象.
Flyweight模式是一个提高程序效率和性能的模?会大大加快程序的q行速度.应用场合很多:比如你要从一个数据库中读取一pd字符?q些字符串中有许多是重复?那么我们可以这些字W串储存在Flyweight?pool)?
如何使用?
我们先从Flyweight抽象接口开?
public interface Flyweight //用于本模式的抽象数据cd(自行设计) |
下面是接口的具体实现(ConcreteFlyweight) ,qؓ内部状态增加内存空? ConcreteFlyweight必须是可׃n?它保存的M状态都必须是内?intrinsic),也就是说,ConcreteFlyweight必须和它的应用环境场合无?
public class ConcreteFlyweight implements Flyweight { private IntrinsicState state; public void operation( ExtrinsicState state ) { //具体操作 } } |
当然,q不是所有的Flyweight具体实现子类都需要被׃n?所以还有另外一U不׃n的ConcreteFlyweight:
public class UnsharedConcreteFlyweight implements Flyweight { public void operation( ExtrinsicState state ) { } } |
Flyweight factory负责l护一个Flyweight?存放内部状?,当客Lh一个共享Flyweight?q个factory首先搜烦池中是否已经有可适用?如果?factory只是单返回送出q个对象,否则,创徏一个新的对?加入到池?再返回送出q个对象.?/p>
public class FlyweightFactory { Flyweight flyweight = (Flyweight) flyweights.get(key); if( flyweight == null ) { return flyweight; |
x,Flyweight模式的基本框架已l就l?我们看看如何调用:
FlyweightFactory factory = new FlyweightFactory();
Flyweight fly1 = factory.getFlyweight( "Fred" );
Flyweight fly2 = factory.getFlyweight( "Wilma" );
......
从调用上?好象是个Ua的Factory使用,但奥妙就在于Factory的内部设计上.
Flyweight模式在XML{数据源中应?/b>
我们上面已经提到,当大量从数据源中d字符?其中肯定有重复的,那么我们使用Flyweight模式可以提高效率,以唱片CDZ,在一个XML文g?存放了多个CD的资?
每个CD有三个字D?
1.出片日期(year)
2.歌唱者姓名等信息(artist)
3.q曲目 (title)
其中,歌唱者姓名有可能重复,也就是说,可能有同一个演p的多个不同时期 不同曲目的CD.我们?歌唱者姓?作ؓ可共享的ConcreteFlyweight.其他两个字段作ؓUnsharedConcreteFlyweight.
首先看看数据源XML文g的内?
<cd> <cd> <cd> ....... </collection> |
虽然上面举例CD只有3?CD可看成是大量重复的小c?因ؓ其中成分只有三个字段,而且有重复的(歌唱者姓?.
CD是cM上面接口 Flyweight:
private String title; |
?歌唱者姓?作ؓ可共享的ConcreteFlyweight:
public class Artist { //内部状?br /> private String name; // note that Artist is immutable. Artist(String n){ |
再看看Flyweight factory,专门用来刉上面的可共享的ConcreteFlyweight:Artist
public class ArtistFactory { Hashtable pool = new Hashtable(); Artist result; |
当你有几千张甚至更多CD?Flyweight模式节省更多空?׃n的flyweight多,I间节省也就大.
板桥里h http://www.jdon.com 2002/04/27Q{载请保留Q?/p>
Composite模式定义:
对象以树Şl构l织h,以达成“部分-整体?的层ơ结构,使得客户端对单个对象和组合对象的使用h一致?
Composite比较Ҏ理解Q想到Composite应该想到树形结构图。组合体内这些对象都有共同接?当组合体一个对象的Ҏ被调用执行时QComposite遍?Iterator)整个树Şl构,L同样包含q个Ҏ的对象ƈ实现调用执行。可以用牵一动百来Ş宏V?/p>
所以Composite模式使用到Iterator模式Q和Chain of Responsibility模式cM?/p>
Composite好处:
1.使客L调用单,客户端可以一致的使用l合l构或其中单个对象,用户׃必关p自己处理的是单个对象还是整个组合结构,q就化了客户端代码?br />2.更容易在l合体内加入对象部g. 客户端不必因为加入了新的对象部g而更改代码?/p>
如何使用Composite?
首先定义一个接口或抽象c,q是设计模式通用方式了,其他设计模式Ҏ口内部定义限制不多,Composite却有个规定,那就是要在接口内部定义一个用于访问和理Compositel合体的对象们(或称部gComponentQ?
下面的代码是以抽象类定义Q一般尽量用接口interface,
public abstract class Equipment { private String name; //实h public abstract double netPrice(); //折扣h public abstract double discountPrice(); //增加部gҎ public boolean add(Equipment equipment) { return false; } //删除部gҎ public boolean remove(Equipment equipment) { return false; } //注意q里Q这里就提供一U用于访问组合体cȝ部gҎ?br /> public Iterator iter() { return null; } public Equipment(final String name) { this.name=name; } } |
抽象cEquipment是Component定义Q代表着l合体类的对象们,Equipment中定义几个共同的Ҏ?/p>
public class Disk extends Equipment { public Disk(String name) { super(name); } //定义Disk实h? public double netPrice() { return 1.; } //定义了disk折扣h?.5 Ҏ?br /> public double discountPrice() { return .5; } } |
Disk是组合体内的一个对象,或称一个部Ӟq个部g是个单独元素( Primitive)?br />q有一U可能是Q一个部件也是一个组合体Q就是说q个部g下面q有'儿子'Q这是树形结构中通常的情况,应该比较Ҏ理解。现在我们先要定义这个组合体Q?/p>
abstract class CompositeEquipment extends Equipment //注意q里Q这里就提供用于讉K自己l合体内的部件方法?br /> //上面dIsk 之所以没有,是因为Disk是个单独(Primitive)的元? |
上面CompositeEquipmentl承了Equipment,同时己里面的对象们提供了外部讉K的方?重蝲了Iterator,Iterator是Java的Collection的一个接口,是Iterator模式的实?
我们再看看CompositeEquipment的两个具体类:盘盒Chassis和箱子CabinetQ箱子里面可以放很多东西Q如底板Q电源盒Q硬盘盒{;盘盒里面可以放一些小讑֤Q如盘 软驱{。无疑这两个都是属于l合体性质的?/p>
public class Chassis extends CompositeEquipment { public Chassis(String name) { super(name); } public double netPrice() { return 1.+super.netPrice(); } public double discountPrice() { return .5+super.discountPrice(); } } public class Cabinet extends CompositeEquipment |
x我们完成了整个Composite模式的架构?/p>
我们可以看看客户端调用Composote代码:
Cabinet cabinet=new Cabinet("Tower");
Chassis chassis=new Chassis("PC Chassis");
//PC Chassis装到Tower?(盘盒装到箱子里)
cabinet.add(chassis);
//一?0GB的硬盘装?PC Chassis (硬盘装到盘盒里)
chassis.add(new Disk("10 GB"));
//调用 netPrice()Ҏ;
System.out.println("netPrice="+cabinet.netPrice());
System.out.println("discountPrice="+cabinet.discountPrice());
上面调用的方法netPrice()或discountPrice()Q实际上Composite使用Iterator遍历了整个树形结?L同样包含q个Ҏ的对象ƈ实现调用执行.
Composite是个很y妙体现智慧的模式Q在实际应用中,如果到树Şl构Q我们就可以试是否可以使用q个模式?/p>
以论坛ؓ例,一个版(forum)中有很多帖子(message),q些帖子有原始脓Q有对原始脓的回应脓Q是个典型的树Şl构Q那么当然可以用Composite模式Q那么我们进入Jive中看看,是如何实现的.
Jive解剖
在Jive?ForumThread是ForumMessages的容器container(l合?.也就是说QForumThreadcM我们上例中的 CompositeEquipment.它和messages的关pd图:
[thread]
|- [message]
|- [message]
|- [message]
|- [message]
|- [message]
我们在ForumThread看到如下代码Q?br />
public interface ForumThread { .... public void addMessage(ForumMessage parentMessage, ForumMessage newMessage) throws UnauthorizedException; public void deleteMessage(ForumMessage message) } |
cMCompositeEquipment, 提供用于讉K自己l合体内的部件方? 增加 删除 遍历.
l合我的其他模式中对Jive的分析,我们已经基本大体理解了Jive论坛体系的框Ӟ如果你之前不理解设计模式Q而直接去看Jive源代码,你肯定无法看懂?/p>
参考文章:
板桥里h http://www.jdon.com 2002/04/28
装饰模式:Decorator常被译?装饰",我觉得翻译成"Ҏ?更Ş象点,Ҏ?decorator)是用来刷Ҏ?那么被刷Ҏ的对象我们称decoratee.q两U实体在Decorator模式中是必须?
Decorator定义:
动态给一个对象添加一些额外的职责,p在墙上刷Ҏ.使用Decorator模式相比用生成子cL式达到功能的扩充昑־更ؓ灉|.
Z么用Decorator?
我们通常可以使用l承来实现功能的拓展,如果q些需要拓展的功能的种cdJ多,那么势必生成很多子类,增加pȝ的复杂?同时,使用l承实现功能拓展,我们必须可预见这些拓展功?q些功能是编译时q定了,是静态的.
使用Decorator的理由是:q些功能需要由用户动态决定加入的方式和时?Decorator提供?x即用"的方?在运行期间决定何时增加何U功?
如何使用?
举Adapter中的打桩CZ,在Adapter中有两种c?方Ş?圆Ş?Adapter模式展示如何l合使用q两个类,在Decorator模式?我们是要在打桩时增加一些额外功?比如,挖坑 在桩上钉木板{?不关心如何用两个不相关的类.
我们先徏立一个接?
public interface Work } |
接口Work有一个具体实?插入方Ş桩或圆Ş?q两个区别对Decorator是无所?我们以插入方形桩Z:
public class SquarePeg implements Work{ public void insert(){ System.out.println("方Ş桩插?); } } |
现在有一个应?需要在桩打入前,挖坑,在打入后,在桩上钉木板,q些额外的功能是动?可能随意增加调整修改,比如,可能又需要在打桩之后钉架?只是比喻).
那么我们使用Decorator模式,q里方Ş桩SquarePeg是decoratee(被刷Ҏ?,我们需要在decoratee上刷?Ҏ",q些Ҏ是那些额外的功?
public class Decorator implements Work{ private Work work; //在构造器中用组合new方式,引入Work对象; others.add("钉木?); public void insert(){ newMethod();}
public void otherMethod() } |
在上例中,我们把挖坑和钉木杉K排在了打桩insert前面,q里只是举例说明额外功能ơ序可以L安排.
好了,Decorator模式出来?我们看如何调?
Work squarePeg = new SquarePeg();
Work decorator = new Decorator(squarePeg);
decorator.insert();
Decorator模式x完成.
如果你细?会发?上面调用cM我们d文g时的调用:
FileReader fr = new FileReader(filename);
BufferedReader br = new BufferedReader(fr);
实际上Java 的I/O API是使用Decorator实现?/font>,I/O变种很多,如果都采取承方?会产生很多子类,昄相当J琐.
Jive中的Decorator实现
在论坛系l中,有些特别的字是不能出现在论坛中如"打倒XXX",我们需要过滤这?反动"的字?不让他们出现或者高亮度昄.
在IBM Java专栏中专?a target="_blank">谈Jive的文?/font>?有谈及Jive中ForumMessageFilter.java使用了Decorator模式,其实,该程序ƈ没有真正使用Decorator,而是提示?针对特别论坛可以设计额外增加的过滤功?那么可以重lForumMessageFilter作ؓDecorator模式?
所?我们在分辨是否真正是Decorator模式,以及会真正用Decorator模式,一定要把握好Decorator模式的定?以及其中参与的角?Decoratee 和Decorator).
板桥里h http://www.jdon.com 2002/04/21
适配器模式定?
两个不兼容的类U合在一起用,属于l构型模?需要有Adaptee(被适配?和Adaptor(适配?两个w䆾.
Z使用?
我们l常到要将两个没有关系的类l合在一起?W一解决Ҏ是:修改各自cȝ接口Q但是如果我们没有源代码Q或者,我们不愿意ؓ了一个应用而修改各自的接口?怎么?
使用AdapterQ在q两U接口之间创Z个合接?淯?.
如何使用?
实现Adapter方式,其实"think in Java"?cd?一节中已经提到,有两U方式:l合(composition)和?inheritance).
假设我们要打桩,有两U类Q方形桩 圆Ş?
public class SquarePeg{
public void insert(String str){
System.out.println("SquarePeg insert():"+str);
}
}
public class RoundPeg{
public void insertIntohole(String msg){
System.out.println("RoundPeg insertIntoHole():"+msg);
}
}
现在有一个应?需要既打方形桩,又打圆Ş?那么我们需要将q两个没有关pȝcȝ合应?假设RoundPeg我们没有源代?或源代码我们不想修改,那么我们使用Adapter来实现这个应?
public class PegAdapter extends SquarePeg{
private RoundPeg roundPeg;
public PegAdapter(RoundPeg peg)(this.roundPeg=peg;)
public void insert(String str){ roundPeg.insertIntoHole(str);}
}
在上面代码中,RoundPeg属于Adaptee,是被适配?PegAdapter是Adapter,Adaptee(被适配者RoundPeg)和Target(目标SquarePeg)q行适配.实际上这是将l合Ҏ(composition)和?inheritance)Ҏl合q用.
PegAdapter首先l承SquarePegQ然后用new的组合生成对象方式,生成RoundPeg的对象roundPegQ再重蝲父类insert()Ҏ。从q里,你也了解使用new生成对象和用extendsl承生成对象的不?前者无需对原来的cM?甚至无需要知道其内部l构和源代码.
如果你有些Java使用的经验,已经发现Q这U模式经怋用?/p>
q一步?/b>
上面的PegAdapter是承了SquarePeg,如果我们需要两边承,即承SquarePeg 又承RoundPeg,因ؓJava中不允许多承,但是我们可以实现(implements)两个接口(interface)
public interface IRoundPeg{
public void insertIntoHole(String msg);
}
public interface ISquarePeg{
public void insert(String str);
}
下面是新的RoundPeg 和SquarePeg, 除了实现接口q一区别Q和上面的没什么区别?br />public class SquarePeg implements ISquarePeg{
public void insert(String str){
System.out.println("SquarePeg insert():"+str);
}
}
public class RoundPeg implements IRoundPeg{
public void insertIntohole(String msg){
System.out.println("RoundPeg insertIntoHole():"+msg);
}
}
下面是新的PegAdapter,叫做two-way adapter:
public class PegAdapter implements IRoundPeg,ISquarePeg{
private RoundPeg roundPeg;
private SquarePeg squarePeg;
// 构造方?br /> public PegAdapter(RoundPeg peg){this.roundPeg=peg;}
// 构造方?br /> public PegAdapter(SquarePeg peg)(this.squarePeg=peg;)
public void insert(String str){ roundPeg.insertIntoHole(str);}
}
q有一U叫Pluggable Adapters,可以动态的获取几个adapters中一个。用Reflection技术,可以动态的发现cM的PublicҎ?br />
板桥里hbanq http://www.jdon.com 2002/04/21/
理解q用设计模?能够培养我们良好的面向对象编E习?同时在实际应用中,可以如鱼得水,享受游刃有余的乐?
代理模式是比较有用途的一U模?而且变种较多,应用场合覆盖从小l构到整个系l的大结?Proxy是代理的意?我们也许有代理服务器{概?代理概念可以解释?在出发点到目的地之间有一道中间层,意ؓ代理.
设计模式中定?/b>: 为其他对象提供一U代理以控制对这个对象的讉K.
Z么要使用Proxy?
1.授权机制 不同U别的用户对同一对象拥有不同的访问权?如Jive论坛pȝ?׃用Proxyq行授权机制控制,讉K论坛有两Uh:注册用户和游?未注册用?,Jive中就通过cMForumProxyq样的代理来控制q两U用户对论坛的访问权?
2.某个客户端不能直接操作到某个对象,但又必须和那个对象有所互动.
举例两个具体情况:
(1)如果那个对象是一个是很大的图?需要花费很长时间才能显C出?那么当这个图片包含在文档中时,使用~辑器或览器打开q个文档,打开文档必须很迅?不能{待大图片处理完?q时需要做个图片Proxy来代替真正的囄.
(2)如果那个对象在Internet的某个远端服务器?直接操作q个对象因ؓ|络速度原因可能比较?那我们可以先用Proxy来代曉K个对?
M原则?对于开销很大的对?只有在用它时才创徏,q个原则可以为我们节省很多宝늚Java内存. 所?有些为Java耗费资源内存,我以和程序编制思\也有一定的关系.
如何使用Proxy?
?a >Jive论坛pȝZ,讉K论坛pȝ的用h多种cd:注册普通用?论坛理?pȝ理?游客,注册普通用h能发a;论坛理者可以管理他被授权的论坛;pȝ理者可以管理所有事务等,q些权限划分和管理是使用Proxy完成?
Forum是Jive的核心接?在Forum中陈列了有关论坛操作的主要行?如论坛名U?论坛描述的获取和修改,帖子发表删除~辑{?
在ForumPermissions中定义了各种U别权限的用?
public class ForumPermissions implements Cacheable {
/** /** /** /** /** /** /** /** /** ..... public boolean isSystemOrForumAdmin() { ..... } |
因此,Forum中各U操作权限是和ForumPermissions定义的用L别有关系?作ؓ接口Forum的实?ForumProxy正是这U对应关p联pv?比如,修改Forum的名U?只有论坛理者或pȝ理者可以修?代码如下:
public class ForumProxy implements Forum { private ForumPermissions permissions; public void setName(String name) throws UnauthorizedException, ... } |
而DbForum才是接口Forum的真正实?以修改论坛名UCؓ?
public class DbForum implements Forum, Cacheable { public void setName(String name) throws ForumAlreadyExistsException { ....
} |
凡是涉及到对论坛名称修改q一事g,其他E序都首先得和ForumProxy打交?由ForumProxy军_是否有权限做某一样事?ForumProxy是个名副其实?|关","安全代理pȝ".
在^时应用中,无可避免总要涉及到系l的授权或安全体p?不管你有无意识的使用Proxy,实际你已l在使用Proxy?
我们l箋l合Jive谈入׃?下面要涉及到工厂模式?如果你不了解工厂模式,L我的另外一文?设计模式之Factory
我们已经知道,使用Forum需要通过ForumProxy,Jive中创Z个Forum是用Factory模式,有一个ȝ抽象cForumFactory,在这个抽象类?调用ForumFactory是通过getInstance()Ҏ实现,q里使用了Singleton(也是设计模式之一,׃介绍文章很多,我就不写?看这?/a>),getInstance()q回的是ForumFactoryProxy.
Z么不q回ForumFactory,而返回ForumFactory的实现ForumFactoryProxy?
原因是明昄,需要通过代理定是否有权限创建forum.
在ForumFactoryProxy中我们看C码如?
public class ForumFactoryProxy extends ForumFactory {
protected ForumFactory factory; public ForumFactoryProxy(Authorization authorization, ForumFactory factory, public Forum createForum(String name, String description) |
ҎcreateForumq回的也是ForumProxy, Proxyp一道墙,其他E序只能和Proxy交互操作.
注意到这里有两个Proxy:ForumProxy和ForumFactoryProxy. 代表两个不同的职?使用Forum和创建Forum;
至于Z么将使用对象和创建对象分开,q也是ؓ什么用Factory模式的原因所?是ؓ?装" "分派";换句话说,可能功能单一?方便l护修改.
Jive论坛pȝ中其他如帖子的创建和使用,都是按照Forumq个思\而来?
以上我们讨论了如何用Proxyq行授权机制的访?Proxyq可以对用户隐藏另外一U称为copy-on-write的优化方?拯一个庞大而复杂的对象是一个开销很大的操?如果拯q程?没有对原来的对象有所修改,那么q样的拷贝开销没有必?用代理gq这一拯q程.
比如:我们有一个很大的Collection,具体如hashtable,有很多客L会ƈ发同时访问它.其中一个特别的客户端要q行q箋的数据获?此时要求其他客户端不能再向hashtable中增加或删除 东东.
最直接的解x案是:使用collection的lock,让这特别的客L获得q个lock,q行q箋的数据获?然后再释放lock.
public void foFetches(Hashtable ht){
synchronized(ht){
//具体的连l数据获取动?.
}
}
但是q一办法可能锁住Collection会很长时?q段旉,其他客户端就不能讉K该Collection?
W二个解x案是cloneq个Collection,然后让连l的数据获取针对clone出来的那个Collection操作.q个Ҏ前提?q个Collection是可clone?而且必须有提供深度clone的方?Hashtable提供了对自qcloneҎ,但不是Key和value对象的clone,关于Clone含义可以参?a target="_blank">专门文章.
public void foFetches(Hashtable ht){
Hashttable newht=(Hashtable)ht.clone();
}
问题又来?׃是针对clone出来的对象操?如果原来的母体被其他客户端操作修改了, 那么对clone出来的对象操作就没有意义?
最后解x?我们可以{其他客L修改完成后再q行clone,也就是说,q个特别的客L先通过调用一个叫clone的方法来q行一pd数据获取操作.但实际上没有真正的进行对象拷?直至有其他客L修改了这个对象Collection.
使用Proxy实现q个Ҏ.q就是copy-on-write操作.
Proxy应用范围很广,现在行的分布计方式RMI和Corba{都是Proxy模式的应?
更多Proxy应用,?a target="_blank">http://www.research.umbc.edu/~tarr/cs491/lectures/Proxy.pdf
Sun公司?Explore the Dynamic Proxy APIDynamic Proxy Classes
板桥里h http://www.jdon.com 2002/4/6/Q{载请保留Q?/p>
Facade模式的定?/b> : 为子pȝ中的一l接口提供一个一致的界面.
Facade一个典型应用就是数据库JDBC的应?如下例对数据库的操作:
public class DBCompare { Connection conn = null; |
上例是Jsp中最通常的对数据库操作办?
在应用中,l常需要对数据库操?每次都写上述一D代码肯定比较麻?需要将其中不变的部分提炼出?做成一个接?q就引入了facade外观对象.如果以后我们更换Class.forName中的<driver>也非常方?比如从Mysql数据库换到Oracle数据?只要更换facade接口中的driver可?
我们做成了一?a target="_blank">Facade接口,使用该接?上例中的E序可以更改如?
public class DBCompare { |
可见非常?所有程序对数据库访问都是用改接口,降低pȝ的复杂?增加了灵zL?
如果我们要用连接池,也只要针对facade接口修改可?
׃囑֏以看? facade实际上是个理系l间关系,降低pȝ间耦合度的一个常用的办法,也许你已l不知不觉在使用,管不知道它是facade.
板桥里h http://www.jdon.com 2002/05/07
单态定?/strong>:
Singleton模式主要作用是保证在Java应用E序中,一个类Class只有一个实例存在?
在很多操作中Q比如徏立目?数据库连接都需要这L单线E操作?/p>
q有, singleton能够被状态化; q样Q多个单态类在一起就可以作ؓ一个状态仓库一样向外提供服务,比如Q你要论坛中的帖子计数器Q每ơ浏览一ơ需要计敎ͼ单态类能否保持住这个计敎ͼq且能synchronize的安全自动加1Q如果你要把q个数字怹保存到数据库Q你可以在不修改单态接口的情况下方便的做到?/p>
另外斚wQSingleton也能够被无状态化。提供工h质的功能,
Singleton模式׃ؓ我们提供了这样实现的可能。用Singleton的好处还在于可以节省内存Q因为它限制了实例的个数Q有利于Java垃圾回收Qgarbage collectionQ?br />
我们常常看到工厂模式中类装入?class loader)中也用Singleton模式实现?因ؓ被装入的cd际也属于资源?br />
如何使用?
一般Singleton模式通常有几UŞ?
public class Singleton { private Singleton(){} //在自己内部定义自׃个实例,是不是很奇怪? private static Singleton instance = new Singleton(); //q里提供了一个供外部讉K本class的静态方法,可以直接讉K
|
W二UŞ?
public class Singleton {
private static Singleton instance = null; }
|
使用Singleton.getInstance()可以讉K单态类?/p>
上面W二中Ş式是lazy initializationQ也是说第一ơ调用时初始SingletonQ以后就不用再生成了?/p>
注意到lazy initialization形式中的synchronizedQ这个synchronized很重要,如果没有synchronizedQ那么用getInstance()是有可能得到多个Singleton实例。关于lazy initialization的Singleton有很多涉及double-checked locking (DCL)的讨论,有兴者进一步研I?/p>
一般认为第一UŞ式要更加安全些?br />
使用Singleton注意事项Q?br />有时在某些情况下Q用Singletonq不能达到Singleton的目的,如有多个Singleton对象同时被不同的c装入器装蝲Q在EJBq样的分布式pȝ中用也要注意这U情况,因ؓEJB是跨服务器,跨JVM的?/p>
我们以SUN公司的宠物店源码(Pet Store 1.3.1)的ServiceLocatorZE微分析一下:
在Pet Store中ServiceLocator有两U,一个是EJB目录下;一个是WEB目录下,我们查这两个ServiceLocator会发现内容差不多Q都是提供EJB的查询定位服务,可是Z么要分开呢?仔细研究对这两种ServiceLocator才发现区别:在WEB中的ServiceLocator的采取Singleton模式QServiceLocator属于资源定位Q理所当然应该使用Singleton模式。但是在EJB中,Singleton模式已经失去作用Q所以ServiceLocator才分成两U,一U面向WEB服务的,一U是面向EJB服务的?/p>
Singleton模式看v来简单,使用Ҏ也很方便Q但是真正用好,是非怸ҎQ需要对Java的类 U程 内存{概忉|相当的了解?/p>
MQ如果你的应用基于容器,那么Singleton模式用或者不用,可以使用相关替代技术?/p>
q一步深入可参考:
Double-checked locking and the Singleton pattern
When is a singleton not a singleton?