模式与XP(好文转)

发布时间: 2007-05-21 09:45    作者: 未知    来源: 未知    浏览:    评论

这是Test Case在JUnit框架1.0版本中的样子(为了简化,我们忽略了注释和很多方法):

public abstract class TestCase implements Test {

private String fName;

public TestCase(String name) {

fName= name;

}

public void run(TestResult result) {

result.startTest(this);

setUp();

try {

runTest();

}

catch (AssertionFailedError e) {

result.addFailure(this, e);

}

catch (Throwable e) {

result.addError(this, e);

}

tearDown();

result.endTest(this);

}

public TestResult run() {

TestResult result= defaultResult();

run(result);

return result;

}

protected void runTest() throws Throwable {

Method runMethod= null;

try {

runMethod= getClass().getMethod(fName, new Class[0]);

} catch (NoSuchMethodException e) {

e.fillInStackTrace();

throw e;

}

try {

runMethod.invoke(this, new Class[0]);

}

catch (InvocationTargetException e) {

e.fillInStackTrace();

throw e.getTargetException();

}

catch (IllegalAccessException e) {

e.fillInStackTrace();

throw e;

}

}

public int countTestCases() {

return 1;

}

}

新的需求要求允许测试重复进行、或在它们各自的线程中进行、或以上两者。

没有经验的程序员通常在遇到这样的新需求时进行子类型化。但是在这里,因为知道TestCase对象将需要能够在同一个线程中重复运行、或在各自独立的线程中重复运行,所以程序员知道:他们需要考虑得更多。

一种实现方法是:将所有的功能都添加给TestCase本身。许多开发者——尤其是那些不了解设计模式的开发者——将会这样做,而不考虑这会使他们的类变得臃肿。他们必须添加功能,所以他们将功能添加到任何可以添加的地方。下面的代码可能就是他们的实现:

public abstract class TestCase implements Test {

private String fName;

private int fRepeatTimes;

public TestCase(String name) {

this(name, 0);

}

public TestCase(String name, int repeatTimes) {

fName = name;

fRepeatTimes = repeatTimes;

}

public void run(TestResult result) {

for (int i=0; i < fRepeatTimes; i++) {

result.startTest(this);

setUp();

try {

runTest();

}

catch (AssertionFailedError e) {

result.addFailure(this, e);

}

catch (Throwable e) {

result.addError(this, e);

}

tearDown();

result.endTest(this);

}

}

public int countTestCases() {

return fRepeatTimes;

}

}

请注意run(TestResult result)方法变大了一些。他们还为TestCase类添加了另外的构造子。到目前为止,这还不算什么大事。并且,我们可以说:如果这就是所有必须做的事情,那么使用Decorator模式就是多余的。

现在,如果要让每个TestCase对象在其自己的线程中运行又怎样呢?这里也有一个可能的实现:

public abstract class TestCase implements Test {

private String fName;

private int fRepeatTimes;

private boolean fThreaded;

public TestCase(String name) {

this(name, 0, false);

}

public TestCase(String name, int repeatTimes) {

this(name, repeatTimes, false);

}

public TestCase(String name, int repeatTimes, boolean threaded) {

fName = name;

fRepeatTimes = repeatTimes;

fThreaded = threaded;

}

public void run(TestResult result) {

if (fThreaded) {

final TestResult finalResult= result;

final Test thisTest = this;

Thread t= new Thread() {

public void run() {

for (int i=0; i < fRepeatTimes; i++) {

finalResult.startTest(thisTest);

setUp();

try {

runTest();

}

catch (AssertionFailedError e) {

finalResult.addFailure(thisTest, e);

}

catch (Throwable e) {

finalResult.addError(thisTest, e);

}

tearDown();

finalResult.endTest(thisTest);

}

}

};

t.start();

result = finalResult;

} else {

for (int i=0; i < fRepeatTimes; i++) {

result.startTest(this);

setUp();

try {

runTest();

}

catch (AssertionFailedError e) {

result.addFailure(this, e);

}

catch (Throwable e) {

result.addError(this, e);

}

tearDown();

result.endTest(this);

}

}

}

public int countTestCases() {

return fRepeatTimes;

}

}

唔,这看起来开始变得更坏了。为了支持两个新的特征,我们现在拥有了三个构造子,而且run(TestResult result)方法的大小迅速的膨胀起来。

即使不管所有这些新代码,我们这些程序员还没有满足这些需求:我们仍然不能在各自的线程中重复运行测试。为了这个目的,我们必须添加更多的代码。算了,我就放过你吧。

重构可以帮助这些代码减小尺寸。但是只需要稍做思考:如果再接到一个新的需求,我们要怎么办?现在JUnit 3.1支持四种不同的TestCase修饰器,它们可以轻松的随意组合以获取所需的功能。同时,JUnit的实现仍然简单——没有混乱的代码。这种设计保持TestCase类的简单、轻量级,用户只需要在需要的时候对TestCase对象进行装饰即可,而且可以选择任何组合顺序。

很清楚,这是一个模式帮助简化设计的例子。这个例子也说明了缺乏经验的开发者怎样改善他们的设计——如果他们知道模式指出的重构目标。

使用模式来开发软件是聪明之举,但如果你缺乏使用模式的经验,它也可能是危险的。出于这个原因,我极力提倡模式学习组。这些学习组让人们在同伴的帮助下稳步前进而精通模式。

当人们了解模式并以受过训练的方式使用它们时,模式是最有用的——这种受过训练的方式就是XP的方式。以XP的方式使用模式鼓励开发者保持设计的简单、并完全根据需要对模式进行重构。它鼓励在设计早期使用关键的模式。它鼓励将问题与能帮助解决问题的模式相匹配。最后,它鼓励开发者编写模式的简单实现,然后根据需要发展它们。

在XP的场景中,模式的确更有用;而在包含对模式的使用时,XP开发则更有可能成功。

参考书目
[Beck1 00] Beck, Kent. Email on mailto:%20extremeprogramming@egroups.com, January 2000.

[Beck2 94] Patterns Generate Architectures, Kent Beck and Ralph Johnson, ECOOP 94

[GHJV1 95] Design Patterns: Elements of Reusable Object-Oriented Software, by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides. 中译本:《设计模式:可复用面向对象软件的基础》,李英军等译。

[GHJV2 95] Design Patterns: Elements of Reusable Object-Oriented Software, by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides. Pages 353-354 中译本:《设计模式:可复用面向对象软件的基础》,李英军等译,第6章。

[Jeffries 99] Jeffries, Ron. Patterns And Extreme Programming. Portland Pattern Repository. December, 1999

[Kerth 99] Kerth, Norm. Conversation, circa March, 1999.

[Kerievsky 96] Kerievsky, Joshua. Don’t Distinguish Between Classes And Interfaces. Portland Pattern Repository. Circa 1996

TAG

Smile Big Smile Surprise Stick out tongue Wink Sad Tongue Tied Indifferent Crying Embarrassed Cool Angry Angel Devil [8-|] [:#] [:-*] [:^)] [<:o)] [|-)] Yes Beer Left Hug Music Star Time Snail Pizza Automobile Umbrella Computer Storm [mo] [8o|] [^o)] [+o(] [*-)] [8-)] Coffee No Drinks [Z] Right Hug Cake Broken Heart Gift Wilted Flower Movie Dog Idea Sleep Email Travel Paradise
呢称:

加粗 斜体 下划线 链接 图片 代码 邮件地址 引用 列表

最多只能输入100个字符

Tags

SQL 数据库 asp.net C# XML 控件 .NET教程 程序 事件 数据 安全 代码 Server 客户端 验证 数据库专栏 接口 文件 Oracle DataSet 函数 DataGrid 问题 .net return C#语言 JavaScript 服务 IIS 对象 语句 windows 继承 时间 web.config 设计 开发 参数 变量 解决 字符 ADO.net 环境 VB.Net语言 web 异常 工具 服务器 计算 实例 OLEDB Application VB Word WebService insert asp net 安装 记录

精华推荐

更多

精品下载

更多