介绍
装饰模式是一种结构型设计模式,是对原有的东西增加一些包装,再原有的基础上增添东西。如果我们想扩展已有的功能,首先会想到继承,通过重写父类方法,super来调用父类的实现,再添加自己的额外逻辑。而装饰器模式是一种替代继承的方案,可以扩展已有的功能。装饰器模式实际就是给一个对象添加一些新的功能,是动态的增加,相比于继承增加子类更加灵活。
例子
假如原类是一个汽车类,汽车类作为原类有运输功能。但是现在要给不同的汽车上装额外的功能,一个汽车上可以听音乐功能,一个汽车上可以上网功能;
如果想要增加新功能,不可以直接修改原类的代码,那么增添一个包装类,对原有的汽车类进行扩展。
- 抽象构造角色
// 抽象构造角色
public interface ICarService {
public void ownFeature();
}
- 具体构造角色
// 具体构造角色
@Slf4j
@Service("carSerivce")
public class CarServiceImpl implements ICarService {
@Override
public void ownFeature() {
log.info("运输货物!");
}
}
- 抽象装饰角色
//抽象装饰角色
public abstract class DecoratorCarServiceImpl implements ICarService {
@Autowired
private ICarService carSerivce;
public void ownFeature() {
carSerivce.ownFeature();
}
}
- 具体装饰角色
// 具体装饰角色
@Slf4j
@Service("bwmCarService")
public class BMWCarServiceImpl extends DecoratorCarServiceImpl implements ICarService {
@Override
public void ownFeature() {
super.ownFeature();
log.info("提供音乐导航功能");
}
}
main测试:
@RequestMapping("/test")
@RestController
public class TestController {
@Autowired
private ICarService bwmCarService;
@GetMapping("/doService")
public void doService() {
bwmCarService.ownFeature();
}
}
扩展增强思考1:通过jdk代理模式增强方法
@Slf4j
@Component("jdkProxy")
public class JdkProxy implements InvocationHandler {
@Autowired
private ICarService carSerivce;
public Object getProxyInstance() {
return Proxy.newProxyInstance(carSerivce.getClass().getClassLoader(),
carSerivce.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = method.invoke(carSerivce, args);
log.info("提供音乐导航功能");
return result;
}
}
// -----------------------测试----------
@RequestMapping("/test")
@RestController
public class TestController {
@Autowired
private JdkProxy jdkProxy;
@GetMapping("/doService")
public void doService() {
ICarService benzService = (ICarService) jdkProxy.getProxyInstance();
benzService.ownFeature();
}
}
扩展增强思考2:通过cglib代理模式增强方法
@Slf4j
@Component("cglibProxy")
public class CglibProxy implements MethodInterceptor {
public <T> T getProxyInstance(Class<T> clazz) {
return (T) Enhancer.create(clazz, this);
}
@Override
public Object intercept(Object obj,
Method method,
Object[] args,
MethodProxy proxy) throws Throwable {
Object result = proxy.invokeSuper(obj, args);
log.info("提供音乐导航功能");
return result;
}
}
// -----------------------测试----------
@RequestMapping("/test")
@RestController
public class TestController {
@Autowired
private CglibProxy cglibProxy;
@GetMapping("/doService")
public void doService() {
ICarService iCarService = cglibProxy.getProxyInstance(CarServiceImpl.class);
iCarService.ownFeature();
}
}
扩展增强思考3:通过spring aop增强方法
@Slf4j
@Component("carAopProxy")
@Aspect
public class CarAopProxy {
@Pointcut("execution(* com.sunpy.simpleweb.pattern.CarServiceImpl.ownFeature(..))")
public void cutMethod() {
}
@After("cutMethod()")
public void afterAddFeature() {
log.info("提供音乐导航功能");
}
}
// -----------------------测试----------
@RequestMapping("/test")
@RestController
public class TestController {
@Autowired
private ICarService carSerivce;
@GetMapping("/doService")
public void doService() {
carSerivce.ownFeature();
}
}
实际应用中的设计
使用缓冲流读取文件的例子,分析第一句中装饰器模式的设计应用。
public static void main(String[] args) throws Exception {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:/BugReport.txt"));
int length = 0;
byte[] arr = new byte[2048];
while ((length = bis.read(arr)) != -1) {
System.out.println(new String(arr, 0, length));
}
bis.close();
}
① 抽象构造角色:
public abstract class InputStream implements Closeable {
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
}
② 具体构造角色:
public class FileInputStream extends InputStream {
public FileInputStream(String name) throws FileNotFoundException {
this(name != null ? new File(name) : null);
}
public int read(byte b[]) throws IOException {
return readBytes(b, 0, b.length);
}
}
③ 抽象装饰角色:
public class FilterInputStream extends InputStream {
protected volatile InputStream in;
protected FilterInputStream(InputStream in) {
this.in = in;
}
}
④ 具体装饰角色:
public class BufferedInputStream extends FilterInputStream {
public BufferedInputStream(InputStream in) {
this(in, defaultBufferSize);
}
public BufferedInputStream(InputStream in, int size) {
super(in);
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
buf = new byte[size];
}
public int read(byte b[]) throws IOException {
return readBytes(b, 0, b.length);
}
}
说明:
此功能就是在FileInputStream文件流装饰上缓存的功能。目标也是增强文件流的功能。关键点在于抽象装饰角色是否持有抽象构造角色的引用,引用抽象构造角色就间接引用了具体构造角色,这样就可以通过构造器传入来实现装饰进而达到功能的增强。
总结
- 装饰类实际就是一个为原有类增添新功能的模式(也可以为原功能删除,但是得是原类方法级层次上的,方法体内是不可以的)。
- 装饰类其实也把核心的功能和装饰的功能分开了。