在电视剧《相爱十年》中,主角肖然把出现了品控问题的安尔雅肥皂换了个包装、改了套说辞变成了全新的品牌浴雪清,并成功的推销出去了,得到了第一桶金。这就说所谓的包装,本质上并没有改变,但是外在表现形式上有了改动,给人感觉这好像是一个全新的物种一样。
日光之下并无新事,这话出自《圣经》,讲的就是这道理。
在编程领域同样会存在这种包装的需求,比如我们需要更改某个类的行为,但它是 final 类型的,不能继承。或者是干脆就不想继承,想通过组合的方式去包装它,以达到这种修改对象行为的目的。
比如 JavaWeb 中的 HttpServletRequestWrapper 类就是一个典型的包装器类,它就是应用了包装器设计模式的思想。这个类持有了原有的 request 对象,实现了 ServletRequest 接口,重写了它的所有方法,并提供了针对 HTTP 协议的个性化功能。
该设计模式中有几个角色
学习启示:学习设计模式的过程中,搞清楚这个模式里面有几个角色,也就是有几个对象,理顺他们的关系,也就理解了这个设计模式。
在包装器模式中从根本上来说,就只有被包装对象和包装对象。他们之间是一种组合关系,包装对象内部持有了被包装对象,并提供了一些被包装对象所没有的扩展行为。多出来或者改动的行为就是包装!
如何实现包装器模式/装饰器模式
「英文时间」:decorator n. 装饰器
「英文时间」:wrapper n. 包装材料
包装器设计模式的核心就是,通过组合和继承同一个接口的方式,不需要更改的行为就用默认实现,需要更改的就自定义修改。
下面还是以一个上面安尔雅和浴雪清肥皂的例子来讲解具体的代码如何写,UML 类图和具体操作步骤如下:
装饰器模式.png
第一步:定义包装类和被包装类共同的接口
第二步:定义被包装类,并实现接口的方法
第三步:定义包装类,并通过构造函数接收被包装类对象,将其作为内部属性持有。然后按照实际选择修改或者新增行为!
共同的接口:肥皂
//肥皂的接口
public interface Soap {
void wash();
void name();
}
被包装类:安尔雅肥皂
//
class AnErYa implements Soap{
@Override
public void wash() {
System.out.println("肥皂洗澡更干净");
}
@Override
public void name() {
System.out.println("安尔雅");
}
}
包装类:浴雪清肥皂
class YuXueQing implements Soap{
private Soap sopa;//持有被包装类的引用
public YuXueQing(Soap s) {
this.sopa = s;//获取被包装类的引用
}
//修改被包装对象的行为
@Override
public void name() {
System.out.println("浴雪清");
}
//定义默认实现
@Override
public void wash() {
this.sopa.wash();
}
//浴雪清新增行为
public void medicine(){
System.out.println("中药成分");
}
}
测试代码:
public static void main(String[] args) {
Soap s1 = new AnErYa();
Soap s2 = new YuXueQing(s1);
s2.wash();
s2.name();
YuXueQing y = (YuXueQing) s2;
y.medicine();
}