当前位置:编程学习 > C#/ASP.NET >>

模式与XP(好文转)

答案:这是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

上一个:使.NET应用程序开发标准化2(转)
下一个:创建一个n层的体系架构,它可以通过运用ADO.NET的功能使开发简单化。-zt(1)

CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,