??xml version="1.0" encoding="utf-8" standalone="yes"?> 转蝲Q?a >http://fly-net-cn.javaeye.com/blog/78611
q是一个很单的模式Q却被非常广泛的使用。之所以简单是因ؓ在这个模式中仅仅使用Cl承关系?br>
l承关系׃自n的缺P被专家们扣上?#8220;|恶”的帽子?#8220;使用委派关系代替l承关系”Q?#8220;量使用接口实现而不是抽象类l承”{等专家警告Q让我们q些菜鸟对?#8220;另眼相看”?br>
其实Q承还是有很多自n的优Ҏ(gu)在。只是被大家滥用的似乎缺Ҏ(gu)加明显了。合理的利用l承关系Q还是能对你的系l设计v到很好的作用的。而模板方法模式就是其中的一个用范例?br>
二、定义与l构
GOFl模板方法(Template MethodQ模式定义一个操作中的算法的骨架Q而将一些步骤gq到子类中。得子cd以不改变一个算法的l构卛_重定义该法的某些特定步骤。这里的?法的l构Q可以理解ؓ你根据需求设计出来的业务程。特定的步骤是指那些可能在内容上存在变数的环节?br>
可以看出来,模板Ҏ(gu)模式也是Z巧妙解决变化对系l带来的影响而设计的。用模板方法ɾpȝ扩展性增强,最化了变化对pȝ的媄响。这一点,在下面的举例中可以很明显的看出来?br>
来看下这个简单模式的l构吧:
1) AbstractClassQ抽象类Q:定义了一到多个的抽象Ҏ(gu)Q以供具体的子类来实现它们;而且q要实现一个模板方法,来定义一个算法的骨架。该模板Ҏ(gu)不仅调用前面的抽象方法,也可以调用其他的操作Q只要能完成自n的命?br>
2) ConcreteClassQ具体类Q:实现父类中的抽象Ҏ(gu)以完成算法中与特定子cȝ关的步骤?br>
下面是模板方法模式的l构图。直接把《设计模式》上的图拿过来用下:
三、D?/strong>
q是在我刚刚分析完源码的JUnit中找个例子吧。JUnit中的TestCase以及它的子类是一个模板方法模式的例子。在TestCaseq个?象类中将整个试的流E设|好了,比如先执行SetupҎ(gu)初始化测试前提,在运行测试方法,然后再TearDown来取消测试设|。但是你在 Setup、TearDown里面作些什么呢Q鬼才知道呢Q!因此Q而这些步骤的具体实现都gq到子类中去Q也是你实现的试cM?br>
来看下相关的源代码吧?br>
q是TestCase中,执行试的模板方法。你可以看到Q里面正像前面定义中所说的那样Q它制定?#8220;法”的框架——先执行setUpҎ(gu)来做下初始化Q然后执行测试方法,最后执行tearDown释放你得到的资源?br>
public void runBare() throws Throwable {
setUp();
try {
runTest();
}
finally {
tearDown();
}
}
q就是上面用的两个Ҏ(gu)。与定义中不同的是,q两个方法ƈ没有被实Cؓ抽象Ҏ(gu)Q而是两个I的无ؓҎ(gu)Q被UCؓ钩子Ҏ(gu)Q。这是因为在试中,我们q?不是必须要让试E序使用q两个方法来初始化和释放资源的。如果是抽象Ҏ(gu)Q则子类们必ȝ它一个实玎ͼ不管用到用不到。这昄是不合理的。用钩子方 法,则你在需要的时候,可以在子cM重写q些Ҏ(gu)?br>
protected void setUp() throws Exception {}
protected void tearDown() throws Exception {}
四、适用情况
Ҏ(gu)上面对定义的分析Q以及例子的说明Q可以看出模板方法适用于以下情况:
1) 一ơ性实C个算法的不变的部分,q将可变的行为留l子cL实现?br>
2) 各子cM公共的行为应被提取出来ƈ集中C个公qcM以避免代码重复。其实这可以说是一U好的编码习惯了?br>
3) 控制子类扩展。模板方法只在特定点调用操作Q这样就只允许在q些点进行扩展。比如上面runBareQ)Ҏ(gu)只在runTest前面适用setUp?法。如果你不愿子类来修改你的模板方法定义的框架Q你可以采用两种方式来做Q一是在API中不体现Z的模板方法;二、将你的模板Ҏ(gu)|ؓfinal可 以了?br>
可以看出Q用模板方法模式可以将代码的公p为提取出来,辑ֈ复用的目的。而且Q在模板Ҏ(gu)模式中,是由父类的模板方法来控制子类中的具体实现。这样你在实现子cȝ时候,Ҏ(gu)不需要对业务程有太多的了解?/td>
]]>
定义一l算法,每个算法都装hQƈ且它们之间可以互换。策略模式ɘq些法在客L调用它们的时候能够互不媄响地变化?
{略模式使开发h员能够开发出p多可替换的部分组成的软gQƈ且各个部分之间是p接的关系。弱q接的特性软gh更强的可扩展性,易于l护Q更重要的是Q它大大提高了Y件的可重用性?
Z说明{略模式Q我们将首先讨论一下在Swing中是如何利用{略模式来绘制组件边界的Q然后讨论在Swing中用策略模式带来的好处Q最后讨论如何在软g中实现策略模式?
Ҏ(gu)有的SwinglgQ例如按钮、列表单{,都还可以l制Ҏ(gu)。在Swing中提供了各种 Ҏ(gu)cdQ例如bevel、etched、line、titled{。Swinglg的边框是通过JComponentcLl制的,该类是所有Swing lg的基c,实现了所有Swinglg公共的功能。在JComponent中有一个paintBorder()Ҏ(gu)Q该Ҏ(gu)为组件绘制边框。Swing?开发h员可以象下面的例子中所C那hl制Ҏ(gu)Q?
|
h意上面的代码只是一U假设,事实上Swing的开发h员ƈ没有q样实现 paintBorderQ)Ҏ(gu)。在上面的代码中Q在JComponent中绘制边框的代码被直接写入了paintBorderQ)Ҏ(gu)中,q意味着 JComponent和绘制边框的功能被紧密地l合在了一赗很自然地大家会联想到如果需要实CU新的边框类型,开发h员必M改至三处代码:首先?加一个常量,该常量代表新d的边框的cd|其次需要在Switch语句中增加一个case语句Q最后开发h员需要实现paintXXXBorder Q)Ҏ(gu)Q其中XXX代表新边框的名称?
很显然要扩展上面paintBorder()Ҏ(gu)的功能是一件很困难的事情,不仅 仅是因ؓ开发h员需要增加一U新的边框类型,更麻烦的是开发h员很难修改JComponentcRJComponentcdl被~译CSwing的开?工具中,如果开发h员想修改它的话,必须获得Swing的源代码Q修改后重新~译Swing。同时在用户的计机上与需要用新~译的Swing API。另外所有的Swinglg都可以用开发h员新d的边框类型。有可能开发h员只希望新的Ҏ(gu)被某些组件用,但是现在开发h员无法对使用该边?的组件进行限制?
开发h员有更好的实现方法吗Q答案就是策略模式。通过{略模式Q可以将 JComponent和实现绘制边框的代码分离开来,q样开发h员在增加或修改绘制边框的代码使就不需要修改JComponent的代码。通过应用{略?式,开发h员将变化的概念(在这个例子中是绘制边框)装hQ然后通过一个Border接口QɽE序能够重用l制Ҏ(gu)的功能。下面让我们来看 JComponent是如何利用策略模式来实现l制Ҏ(gu)的功能的Q?
|
上面的paintBorder()Ҏ(gu)通过一个border对象l制了组件的Ҏ(gu)?q样border对象替代了前一个例子中的JComponent装了边框绘制的功能。我们还应该注意到JComponent一个对自己的引用传递给?Border.paintBorderQ)Ҏ(gu)Q这是因为Border的实例必ȝ道它对应的组件的信息Q这U方式通常被称为委托。通过q种方式Q一个对 象可以将功能委托l另一个对象来实现?
在JComponentcM引用了一个Border对象Q通过JComponent.getBorderQ)Ҏ(gu)可以获得该Border对象。下面的代码演示了如何设定和获得Border对象Q?
|
当开发h员通过JComponent.setBorderQ)Ҏ(gu)讑֮了一个组件的 Ҏ(gu)后,JComponentcdZ个属性更C件。如果新的边框和以前的边框不同的话,setBorderQ)Ҏ(gu)重新绘制边框?getBorderQ)Ҏ(gu)仅仅q回对Border对象的引用。图1昄了Border的类l构图:
通过cȝ构图我们可以看到QJComponentcM保存了一个对Border对象的引用。由于Border是一个接口,Swinglg可以使用M一个实CBorder接口的类?
现在我们已经知道了JComponent是如何利用策略模式来l制lg的边框的。下面让我们通过实现一个新的边框类型来试一下它的可扩展性?
?中是一个有三个JPanel对象的小E序Q每个JPanel对象有各自不同的Ҏ(gu)Q每个边框对应一个HandleBorder实例?
|
HandleBordercȝ承了 javax.swing.border.AbstractBordercdƈ重写了paintBorderQ)和getBorderInsetsQ)?HandleBorder是如何实现的其实q不重要Q重要的是由于Swing使用了策略模型,开发h员能够很方便地增加新的边框类型。下面的代码昄了如 何用HandleBordercR在q个例子中创Z三个JPanel对象QƈҎ(gu)个JPanel对象讑֮一个HandleBorder实例作ؓҎ(gu)?
|
q记得在上面的例子中曾提到在有些情况下,对组件的引用会作为参C递给 Border.paintBorderQ)Ҏ(gu)。虽然上面的HandleBordercL有保存对lg的引用,但是有些情况下Border接口的实现类?使用到对lg的引用ƈ从中获得关于lg的信息。例如在EtchedBorder中,paintBorderQ)Ҏ(gu)通过对组件的引用获得它对应的lg的阴 影和高光Ԍ
|
通过以下步骤Q开发h员可以很Ҏ(gu)地在软g中实现策略模型:
1Q对{略对象定义一个公共接口?
2Q编写策略类Q该cdC上面的公共接口?
3Q在使用{略对象的类中保存一个对{略对象的引用?
4Q在使用{略对象的类中,实现对策略对象的set和getҎ(gu)?
在SwingҎ(gu)的例子中Q公共接口是javax.swing.Border。策略类是LineBorder、EtchedBorder、HandleBorder{。而用策略对象的cLJComponent?
转蝲Q?a >http://fly-net-cn.javaeye.com/blog/78615