1.装饰者模式的简介

什么是装饰者模式:

装饰者模式可以动态地给对象添加一些额外的属性或函数,简单点儿说就是当我们需要修改原有的功能,但我们又不愿直接去修改原有的代码时,那么设计一个装饰类套在原有代码外面

就增加功能来说,装饰者相比子类更加灵活。

为什么说是动态的将责任附加到对象身上,因为装饰者模式有了装饰角色,就可以根据需要动态的装饰不同的具体构件角色和具体装饰角色,这个具体构件和装饰角色是可以动态的切换的。

装饰者模式的特点:

装饰器角色和被装饰器角色都实现同一个接口, 主要目的是使得装饰器和被装饰器都实现同一个接口, 是为了扩展之后依旧保留 OOP 关系(同宗同源)。


应用场景:

IO 流包装、 数据源包装;

其实在 JDK 中就有很多地方用到了装饰者模式,比如说InputStream,InputStream 下边有 FileInputStream (读取文件)、BufferedInputStream等子类,都在不修改InputStream 代码的情况下扩展了各自的功能。

在spring中的体现:Spring 中用到的包装器模式在类名上有两种表现: 一种是类名中含有 Wrapper, 另一种是类名中含有Decorator。 基本上都是动态地给一个对象添加一些额外的职责。

2.装饰者模式的4个角色

装饰者模式以对客户透明的方式动态地给一个对象附加上更多的责任

换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。

装饰者模式可以在不创造更多实现子类的情况下,将对象的功能加以扩展

装饰者模式的类图如下:
image.png

在装饰模式中的角色有:

1)抽象构件角色:

这是一个抽象接口,主要是用来规范准备添加附加责任的对象。

2)具体构件角色:

定义一个准备附加责任的类。

3)抽象装饰角色:

这是一个抽象接口,该接口包含了要添加的附加责任的抽象方法
该接口继承了抽象构件角色,用来在具体装饰角色中保持原有的功能;

4)具体装饰角色:

负责添加具体的附加责任。

4.1,实现了抽象装饰角色;
4.2,以抽象构件角色为类型,注入具体构件角色
4.3,通过具体构建角色对象执行原有的功能函数;
4.4,重写附加责任的方法,添加具体的附加责任;

3.装饰者模式的代码示例:

1)抽象构件角色

定义登录功能的接口

  1. public interface IOldSignService {
  2. void sign(String username, String password); //登录功能
  3. }

2)具体构件角色

登录功能的具体实现

  1. @Service
  2. public class OldSignServiceImpl implements IOldSignService {
  3. /**
  4. * 登录功能
  5. */
  6. @Override
  7. public void sign(String username, String password) {
  8. System.out.println("用户输入用户名和密码:" + username + " " + password);
  9. }
  10. }

3)抽象装饰角色

拓展了发送短信的功能

  1. public interface IDecoratorSignService extends IOldSignService{
  2. void sendMsg(String content); //发送短信功能
  3. }

4)具体装饰角色

1、通过具体构件角色保持原有的登录功能; 2、同时增加了发送短信的功能;

  1. @Service
  2. public class DecoratorSignServiceImpl implements IDecoratorSignService{
  3. //以抽象构件角色为类型,注入具体构件角色,实现登录功能:
  4. @Autowired
  5. @Qualifier(value = "oldSignServiceImpl")
  6. private IOldSignService oldSignService;
  7. //通过具体构件角色保持原有的功能;
  8. @Override
  9. public void sign(String username, String password) {
  10. System.out.println("装饰构件,完成登录功能");
  11. oldSignService.sign(username, password);
  12. }
  13. //同时增加了发送短信的新功能;
  14. @Override
  15. public void sendMsg(String content) {
  16. System.out.println("新增发送短信功能,短信内容为 = " + content);
  17. }
  18. }

测试

  1. @SpringBootTest
  2. public class DecoratorSignServiceImplTest01 {
  3. @Autowired
  4. private IDecoratorSignService decoratorSignServiceImpl;
  5. @Test
  6. public void test01() {
  7. decoratorSignServiceImpl.sign("交控科技", "123456");
  8. decoratorSignServiceImpl.sendMsg("aaaaaaaaaaaa");
  9. }
  10. }

测试结果

image.png


作者:Mrsunup
链接:https://www.jianshu.com/p/8f6ebeee1ae6
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


4. Spring中的装饰者模式:

在spring中的体现:Spring 中用到的包装器模式在类名上有两种表现:一种是类名中含有 Wrapper, 另一种是类名中含有Decorator。
基本上都是动态地给一个对象添加一些额外的职责。

1)Spring配置 DataSource:

Spring 中配置 DataSource数据源的时候,这些dataSource可能是各种不同类型的,比如不同的数据库:Oracle、SQL Server、MySQL等,
也可能是不同的数据源:比如apache 提供的org.apache.commons.dbcp.BasicDataSource、spring提供的org.springframework.jndi.JndiObjectFactoryBean等。

这时,能否在尽可能少修改原有类代码下的情况下,做到动态切换不同的数据源?此时就可以用到装饰者模式。

Spring根据每次请求的不同,将dataSource属性设置成不同的数据源,以到达切换数据源的目的。

2)MyBatis执行器:

MyBatis中关于Cache和CachingExecutor接口的实现类也使用了装饰者设计模式。

Executor是MyBatis执行器,是MyBatis 调度的核心负责SQL语句的生成和查询缓存
CachingExecutor是一个Executor的装饰者,在Executor原有的功能基础上,增加了缓存的功能。此时可以看做是对Executor类的一个增强,即使用了装饰器模式。

3)Spring事务缓存

在 Spring 中,TransactionAwareCacheDecorator 类相当于装饰器模式中的抽象装饰角色,主要用来处理事务缓存,TransactionAwareCacheDecorator 就是对 Cache 的一个包装,即在Cache原有的功能基础上,增加了事务缓存的功能。