背景
一个iPhone,可以套上保护壳(ConcDecorator A),也可以再套上无线充(ConcDecorator B),得到最后的效果(execute)。
苹果无需发布新的型号(继承),我们简单地通过装饰(组合)就可以得到想要的最终产品。
模式定义
Attach additional responsibilities to an object dynamically keeping the same interface. Decorators provide a flexible alternative to subclassing for extending functionality.
为动态保持相同接口的对象附加额外的职责。装饰器为扩展功能提供了一种灵活的选择,而不是子类化。
可以看到,是十分符合我们的需求的,每一个装饰品如保护壳、无线充,就是一个个可以嵌套的装饰器。
模式实现
1.定义iPhone接口
主要定义了iPhone模板的说明接口方法getDesc,后续以这个方法为核心,展开嵌套。
package com.example.designpattern.decorator;
/**
* 手机
*
* @author hongcunlin
*/
public interface Phone {
/**
* 介绍
*
* @return 介绍内容
*/
String getDesc();
}
2.实现iPhone接口
简单试下getDesc的方法,目前是一个裸机的iPhone。
package com.example.designpattern.decorator.impl;
import com.example.designpattern.decorator.Phone;
/**
* 苹果手机iPhone 14 Pro Max
*
* @author hongcunlin
*/
public class Iphone implements Phone {
@Override
public String getDesc() {
return "iPhone";
}
}
3.定义iPhone装饰器抽象类
装饰器的超类,里边存放iPhone属性,围绕它进行嵌套。
package com.example.designpattern.decorator.impl.decorator;
import com.example.designpattern.decorator.Phone;
/**
* 手机装饰器
*
* @author hongcunlin
*/
public abstract class IphoneDecorator implements Phone {
/**
* 手机(抽象类存在的意义,否则就使用接口了)
*/
protected Phone phone;
/**
* 构造方法
*
* @param phone 手机
*/
IphoneDecorator(Phone phone) {
this.phone = phone;
}
}
4.1.实现iPhone装饰器之保护壳
嵌套一
package com.example.designpattern.decorator.impl.decorator;
import com.example.designpattern.decorator.Phone;
/**
* iPhone保护壳
*
* @author hongcunlin
*/
public class IphoneCaseDecorator extends IphoneDecorator {
/**
* 构造方法
*
* @param phone 手机
*/
public IphoneCaseDecorator(Phone phone) {
super(phone);
}
@Override
public String getDesc() {
return "带保护壳的" + phone.getDesc();
}
}
4.2.实现iPhone装饰器之无线充
嵌套二
package com.example.designpattern.decorator.impl.decorator;
import com.example.designpattern.decorator.Phone;
/**
* iPhone无线充
*
* @author hongcunlin
*/
public class IphoneChargerDecorator extends IphoneDecorator {
/**
* 构造方法
*
* @param phone 手机
*/
public IphoneChargerDecorator(Phone phone) {
super(phone);
}
@Override
public String getDesc() {
return "带无线充的" + phone.getDesc();
}
}
5.测试
这里我们先初始化一个iPhone,接着带上保护壳看看效果,最后再带上无线充看看效果。
package com.example.designpattern.decorator;
import com.example.designpattern.decorator.impl.Iphone;
import com.example.designpattern.decorator.impl.decorator.IphoneCaseDecorator;
import com.example.designpattern.decorator.impl.decorator.IphoneChargerDecorator;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class DesignPatternTest {
@Test
public void test() {
// 常规iPhone
Phone iphone = new Iphone();
System.out.println(iphone.getDesc());
// 带保护壳的iPhone
iphone = new IphoneCaseDecorator(iphone);
System.out.println(iphone.getDesc());
// 带无线充的带保护壳的iPhone
iphone = new IphoneChargerDecorator(iphone);
System.out.println(iphone.getDesc());
}
}
可以看到,随着装饰器的层层嵌套,iPhone的模样越来越复杂,是符合我们的预期的。
最后
装饰器主要是通过组合的模式,对类内容进行扩展,而不是通过继承的方式,特别是在Java只能单继承的情况,行之有效。
后面有空接着闲聊23种设计模式中的其他种。