装饰模式用于动态地改变一个类的功能,而不改变类的结构和继承关系。
其UML图为:
举例:
假设你需要打印发票 sales ticket , 发票有抬头、正文和脚注,发票抬头可以是企事业单位,发票号等等,脚注也是一样,可能有很多不同种类的脚注需要打印。如果发票格式固定那也就没必要继续讨论了,现在的问题是,不同的客户需要的发票或者收据的抬头或脚注,他们需要的条目是不一样的,有的需要著明单位,有的只需要发票号,但是脚注需要开票人,等等,对你来说跟现在的 Web 系统一样,客户的要求是动态;不过发票的正文是不会变化的,是固定。要满足这个需求我们有很多种方案,比如你可以抽象一系统对象层次来分层完成这些对象责任。不过我们这里要推荐的是装饰模式,我们来具体看一下,装饰模式是如何工作的:
先看看该场景的 UML 图,
//接口
interface component
{
void prtTicket();
}
//需要动态扩展的具体类
class salesTicket implements component
{
public void prtTicket()
{
System.out.println("Sales Ticket body");
}
}
//装饰类
abstract class Decorator implements component
{
component comp=null;
public Decorator(component comp)
{
this.comp=comp;
}
public void prtTicket()
{
if(comp!=null)
comp.prtTicket();
}
}
//具体装饰类
class Header1 extends Decorator
{
public Header1(component comp)
{
super(comp);
}
public void prtTicket()
{
System.out.println("Sales Ticket Header1");
super.prtTicket();
}
}
//具体装饰类
class Header2 extends Decorator
{
public Header2(component comp)
{
super(comp);
}
public void prtTicket()
{
System.out.println("Sales Ticket Header2");
super.prtTicket();
}
}
//具体装饰类
class Footer1 extends Decorator
{
public Footer1(component comp)
{
super(comp);
}
public void prtTicket()
{
super.prtTicket();
System.out.println("Sales Ticket Footer1");
}
}
//具体装饰类
class Footer2 extends Decorator
{
public Footer2(component comp)
{
super(comp);
}
public void prtTicket()
{
super.prtTicket();
System.out.println("Sales Ticket Footer2");
}
}
public class Main
{
public static void main(String[] args)
{
/*@output:Sales Ticket Header1
Sales Ticket body
Sales Ticket Footer2*/
component test=new Header1(new Footer2(new salesTicket()));
test.prtTicket();
/*@output:Sales Ticket Header2
Sales Ticket body
Sales Ticket Footer1*/
component test2=new Header2(new Footer1(new salesTicket()));
test2.prtTicket();
}
}
这样,可以根据不同的需求,变换Header和Footer的组合,输出不同