其实我这系列小文,名为源码分析,其实是自己读《设计模式》的读书笔记。Decorator模式在java的IO库中得到应用,java的IO库看起来复杂,其实理解了Decorator模式再回头看可以很好理解并使用。
Decorator模式,也就是装饰器模式,是对象结构型模式之一。
1.意图:动态地给一个对象添加一些额外的职责。给对象添加功能,我们首先想到的是继承,但是如果每增一个功能都需要继承,类的继承体系将无可避免地变的庞大和难以理解。面向对象设计的原则:优先使用组合,而非继承,继承的层次深度最好不过三。
2.适用场景:
1)在不影响其他对象的情况下,以动态、透明的方式给单个对象添加额外的责任
2)处理可以撤销的职责
3)为了避免类的数目爆炸,或者不能采用生成子类的方法进行扩展时
3.UML图和协作:
Component——定义一个对象接口,可以给这些对象动态地添加职责
ConcreteComponent——定义一个对象,可以给这个对象添加职责
Decorator——维持一个指向Component的引用,并定义一个与Component一致的接口,作为装饰类的父类
ConcreteDecorator——具体装饰类
4.效果:
1)与静态继承相比,Decorator可以动态添加职责,更为灵活
2)避免产生复杂的类,通过动态添加职责,而不是一次性提供一个万能的接口
3)缺点是将产生比较多的小对象,对学习上有难度,显然,java.io就是这个问题
我们以一个例子来实现Decorator模式,假设这样一个场景:在某个应用中需要打印票据,我们写了一个PrintTicket接口,然后提供一个实现类(DefaultPrintTicket)实现打印的功能:
<!---->package com.rubyeye.design_pattern.decorator;
//抽象component接口
public interface PrintTicket {
public void print();
}
//默认实现类,打印票据
package com.rubyeye.design_pattern.decorator;
public class DefaultPrintTicket implements PrintTicket {
public void print() {
System.out.println("ticket body");
}
}
OK,我们的功能已经实现,我们还体现了针对接口编程的原则,替换一个新的打印方式很灵活,但是客户开始提需求了——人生无法避免的三件事:交税、死亡和需求变更。客户要求打印页眉,你首先想到的是继承:
<!---->package com.rubyeye.design_pattern.decorator;
public class AnotherPrintTicket implements PrintTicket {
public void print() {
System.out.println("ticket header");
System.out.println("ticket body");
}
}
请注意,我们这里只是简单的示例,在实际项目中也许意味着添加一大段代码,并且需要修改打印票据本体的功能。需求接踵而至,客户要求添加打印页码,要求增加打印花纹,要求可以联打......你的类越来越庞大,直到你看见这个类都想吐的地步!-_-。让我们看看另一个方案,使用Decorator模式来动态地给打印增加一些功能,首先是实现一个Decorator,它需要保持一个到PrintTicket接口的引用:
<!---->package com.rubyeye.design_pattern.decorator;
public class PrintTicketDecorator implements PrintTicket {
protected PrintTicket printTicket;
public PrintTicketDecorator(PrintTicket printTicket) {
this.printTicket = printTicket;
}
//默认调用PrintTicket的print
public void print() {
printTicket.print();
}
}
然后,我们实现两个具体的装饰类——打印页眉和页脚:
<!---->package com.rubyeye.design_pattern.decorator;
public class HeaderPrintTicket extends PrintTicketDecorator {
public HeaderPrintTicket(PrintTicket printTicket){
super(printTicket);
}
public void print() {
System.out.println("ticket header");
super.print();
}
}
<!---->package com.rubyeye.design_pattern.decorator;
public class FooterPrintTicket extends PrintTicketDecorator {
public FooterPrintTicket(PrintTicket printTicket) {
super(printTicket);
}
public void print() {
super.print();
System.out.println("ticket footer");
}
}
使用起来也很容易:
<!---->package com.rubyeye.design_pattern.decorator;
public class DecoratorTest {
/**
* @param args
*/
public static void main(String[] args) {
PrintTicket print=new HeaderPrintTicket(new FooterPrintTicket(new DefaultPrintTicket()));
print.print();
}
}
输出:
ticket header
ticket body
ticket footer
了解了Decorator模式,我们联系了下JUnit里面的应用。作为一个测试框架,应该方便地支持二次开发,也许用户开发自己的TestCase,添加自定义的功能,比如执行重复测试、多线程测试等等。动态添加职责,而又不想使用静态继承,这正是Decorator使用的地方。在junit.extensions包中有一个TestDecorator,正是所有装饰类的父类,也是作为二次开发的基础,它实现了Test接口,而Test接口就是我们定义的抽象接口:
<!---->
public class TestDecorator implements Test {
//保有一个指向Test的引用
protected Test fTest;
public TestDecorator(Test test) {
fTest= test;
}
public void basicRun(TestResult result) {
fTest.run(result);
}
public void run(TestResult result) {
basicRun(result);
}
}
Junit已经提供了两个装饰类:junit.extensions.ActiveTest用于处理多线程,junit.extensions.RepeatedTest用于执行重复测试,看看RepeatedTest是怎么实现的:
<!---->
public class RepeatedTest extends TestDecorator {
//重复次数
private int fTimesRepeat;
public RepeatedTest(Test test, int repeat) {
super(test);
fTimesRepeat= repeat;
}
public void run(TestResult result) {
//重复执行
for (int i= 0; i < fTimesRepeat; i++) {
if (result.shouldStop())
break;
super.run(result);
}
}
}
RepeatedTest继承TestDecorator ,覆写run(TestReult result)方法,重复执行,super.run(result)将调用传入的TestCase的run(TestResult result)方法,这已经在TestDecorator默认实现。看看使用方式,使用装饰模式的好处不言而喻。
<!---->TestSuite suite = new TestSuite();
suite.addTest(new TestSetup(new RepeatedTest(new Testmath("testAdd"),12)));
分享到:
相关推荐
### Junit设计模式分析——设计模式经典案例 #### 1. JUnit概述 **1.1 JUnit简介** JUnit是一个非常流行的Java单元测试框架,它最初由Erich Gamma和Kent Beck开发完成。作为XUnit测试体系架构的一种实现,JUnit...
### JUnit源码及其涉及的设计模式 #### 一、引言 JUnit作为一款广泛应用于Java项目的单元测试框架,其设计理念和实现方式对于软件开发者来说具有很高的学习价值。本文将深入探讨JUnit源码,并重点关注其中使用的...
**Junit源码分析(圣思园)** Junit是Java编程语言中最广泛使用的单元测试框架,它使得开发者能够方便地编写和运行可重复的、可靠的测试用例。本篇文章将深入探讨Junit的源码,揭示其内部工作原理,帮助我们更好地...
《Junit设计模式分析》这本书深入探讨了如何在单元测试框架Junit中巧妙地应用设计模式,以提高代码的可测试性和可维护性。在软件开发过程中,设计模式是解决常见问题的最佳实践,它们能够帮助开发者创建灵活、可扩展...
本实验“自动饮料机Junit测试”旨在帮助学生深入理解和应用单元测试,特别是在Java编程环境下。单元测试是一种针对程序代码最小可测试单元进行验证的方法,通常这个单元是函数或方法。Junit是Java领域广泛使用的单元...
本篇将深入分析JUnit源码中的设计模式,帮助你理解其内在的架构原理,提升你的编程技能。 首先,JUnit的核心设计原则之一是“开闭原则”(Open-Closed Principle),它主张软件实体(类、模块、函数等)应对于扩展...
本资源"Junit设计模式分析(带源码)"旨在深入探讨JUnit在设计上的模式和最佳实践,通过源码分析帮助开发者更好地理解和应用这个工具。 1. 单元测试基础: 单元测试是对软件中的最小可测试单元进行检查,如函数、...
这个框架的设计基于一系列高效的设计模式,这些模式不仅提升了JUnit的灵活性,还使得开发者能够方便地扩展和定制测试功能。 首先,JUnit的核心设计理念是“简单易用”。它遵循了“最小化API”原则,提供了一套简洁...
自定义JUnit源码是一个对Java开发人员非常有帮助的主题,特别是对于那些想要深入理解测试框架工作原理或希望根据自身需求定制测试工具的开发者。JUnit是一个广泛使用的单元测试框架,它简化了编写和运行针对Java代码...
junit 的源码jar包 junit 的源码jar包 junit 的源码jar包
Junit jar包以及 Junit 源码包
JUnit是Java编程语言中最常用的单元测试框架之一,它允许开发者编写可重复运行的测试用例,以确保代码的正确性和稳定性。以下是对JUnit单元测试框架的一些详细解释: 1. **JUnit简介**: JUnit是一个开源的、基于...
"安卓Android源码——飞行历飞行模式AirPlus.zip"这个压缩包文件很可能是关于安卓系统中实现飞行模式的具体源代码,尤其是与AirPlus相关的部分。AirPlus可能是一个特定的模块或者功能,用于优化或扩展飞行模式的特性...
JUnit 设计模式分析 本文将对 JUnit 设计模式进行深入分析,探讨 JUnit 中的设计模式应用,了解 JUnit 是如何使用设计模式来实现测试框架的。 一、JUnit 概述 JUnit 是一个优秀的 Java 单元测试框架,由 Erich ...
JUnit4源码的完整版本包含了整个框架的实现细节,对于理解其工作原理、学习测试驱动开发(TDD)以及进行自定义扩展非常有帮助。 1. **JUnit核心概念**: - **Test Case**:在JUnit4中,测试用例是通过继承`org....
《JUnit设计模式分析》 JUnit,作为Java编程领域中最广泛使用的单元测试框架,它的重要性不言而喻。在软件开发过程中,单元测试是确保代码质量、可维护性和可扩展性的重要手段。本分析将深入探讨JUnit的设计模式,...
"软件单元测试——JUnit使用" 软件单元测试是软件开发过程中的一种测试方法,它是指对软件中的最小单元进行测试,以确保软件的可靠性和正确性。JUnit是一个流行的Java测试框架,广泛应用于软件单元测试中。 在本...