我们要实现三个功能:在
jsp
页面上生成报表(包括一个表和一个图)、生成
pdf
报表和
excel
报表。
原来的代码虽然已经实现了这些功能,但每个类的功能不明确,而且存在大量重复代码。于是想到用设计模式来解决这个问题。起初想用装饰模式(
Decorator Pattern
),但经过分析,发现装饰模式适合于那种需要把多个功能动态组合在一起的情况。但对于一个
report
,我们并不需要它同时能生成
pdf
和
excel
(即不是多个功能的组合)。
桥梁模式(
Bridge Pattern
)才是最适合的。桥梁模式的用意是
"
将抽象化(
Abstraction
)与实现化(
Implementation
)脱耦,使得二者可以独立地变化
"
。(
According to GoF, the Bridge Pattern is intended to "Decouple an abstraction from its implementation so that the two can vary independently"
)
类图如下:
类名 | 功能 | 角色 |
AbstractionReport | 所有功能报表的父类 | 抽象化(Abstraction) |
PdfReport | 生成pdf报表文件 | 修正抽象化 (Refined Abstraction) |
ExcelReport | 生成excel报表文件 | 修正抽象化 |
JspReport | 在jsp中调用,生成报表 | 修正抽象化 |
| | |
ImplementorReport | 所有数据报表的父类 | 实现化(Implementor) |
NetworkPerformanceReport | 网络设备性能报表 | 具体实现化 (Concrete Implementor) |
ServerPerformanceReport | 服务器性能报表 | 具体实现化 |
PortTrafficReport | 接口流量报表 | 具体实现化 |
AbstractionReport的功能是生成pdf或excel文件,而ImplementorReport的功能是收集数据,为生成报表作准备。
AbstractionReport的子类相对固定,因为我们现在只要实现三个功能,当然,如果以后还想再实现其他功能,比如生成txt报表或html报表,我们还能再扩展,增加两个类TxtReport和HtmlReport即可实现。
ImplementorReport的子类就比较多了,列出的只是其中三个。
任意一个AbstractionReport与ImplementorReport的组合都能有不同的功能。有了以上的各个类,我们就能生成各种各样的报表,比如我们要生成一个“网络设备性能”的pdf报表文件,就这么写:
AbstractionReport report = new PdfReport(new NetworkPerformanceReport());
report.createReport();
生成excel报表文件:
AbstractionReport report = new ExcelReport(new NetworkPerformanceReport());
report.createReport();
生成“服务器性能报表”pdf报表文件:
AbstractionReport report = new PdfReport(new ServerPerformanceReport());
report.createReport();
生成“服务器性能报表”excel报表文件:
AbstractionReport report = new ExcelReport(new ServerPerformanceReport());
report.createReport();