一、装璜器模式介绍
1. 解决的问题
次要解决动静地给一个对象增加一些额定的职责。
2. 定义
装璜器模式是一种结构型设计模式,容许将对象通过放入蕴含行为的非凡封装对象来为原对象绑定新的行为。
3. 利用场景
- 心愿在无需批改代码的状况下即可应用对象,且心愿在运行时能为对象减少额定的行为,能够应用装璜器模式。
- 用继承来扩大对象行为的计划难以实现或者基本不可能时,能够应用装璜器模式。
二、装璜器模式优缺点
1. 长处
- 无需创立新的子类即可扩大对象的行为。
- 能够在运行时增加或删除对象的性能。
- 能够应用多个装璜封装对象来组合几种行为。
- 繁多职责准则:将实现了不同行为的一个大类拆分为多个较小的类。
2. 毛病
- 在封装器栈中删除特定封装器比拟艰难。
- 实现行为不受装璜栈程序影响的装璜比拟艰难。
- 各层初始化配置代码看起来可能会比拟蹩脚。
三、装璜器模式利用实例:日志零碎反对各类告诉组合
1. 实例场景
咱们通常会记录零碎运行的各类状况及状态,保留到日志中,罕用日志的级别别离为 DEBUG(调试)、INFO(运行信息)、WARN(正告)、ERROR(谬误)。
一旦产生谬误级别的日志,代表零碎呈现了重大问题,须要及时告诉到相干人员来尽快修复。
个别咱们会进行邮件告诉到运维及开发,但有时邮件会比拟多,容易被疏忽,探讨后心愿将谬误级别的日志能够反对邮件告诉、短信告诉、钉钉告诉,并反对邮件 + 短信、邮件 + 钉钉、邮件 + 短信 + 钉钉等各类组合。
此时,能够用装璜器模式来实现。
2. 装璜器模式实现
2.1 工程构造
decorator-pattern
└─ src
├─ main
│ └─ java
│ └─ org.design.pattern.decorator
│ └─ log
│ ├─ Log.java
│ ├─ Slf4jLog.java
│ └─ decorator
│ ├─ LogDecorator.java
│ ├─ MailLogDecorator.java
│ ├─ DingDingLogDecorator.java
│ └─ SMSLogDecorator.java
└─ test
└─ java
└─ org.design.pattern.decorator.test
└─ LogTest.java
2.2 代码实现
2.2.1 日志
日志接口
/**
* 日志接口
*/
public interface Log {
/**
* 记录调试日志
*
* @param message 信息
*/
void debug(String message);
/**
* 记录一般日志
*
* @param message 信息
*/
void info(String message);
/**
* 记录正告日志
*
* @param message 信息
*/
void warn(String message);
/**
* 记录谬误日志
*
* @param message 信息
*/
void error(String message);
}
Slf4j 日志类
/**
* Slf4j 日志
*/
public class Slf4jLog implements Log {
/**
* 日志记录对象
*/
private final Logger log = LoggerFactory.getLogger("system_log");
/**
* 记录调试日志
*
* @param message 信息
*/
@Override
public void debug(String message) {if (log.isDebugEnabled()) {log.debug(message);
}
}
/**
* 记录一般日志
*
* @param message 信息
*/
@Override
public void info(String message) {if (log.isInfoEnabled()) {log.info(message);
}
}
/**
* 记录正告日志
*
* @param message 信息
*/
@Override
public void warn(String message) {if (log.isWarnEnabled()) {log.warn(message);
}
}
/**
* 记录谬误日志
*
* @param message 信息
*/
@Override
public void error(String message) {if (log.isErrorEnabled()) {log.error(message);
}
}
}
2.2.2 日志装璜器
日志装璜器基类
/**
* 日志装璜器
*/
public class LogDecorator implements Log {
/**
* 日志类
*/
protected Log log;
/**
* 构造方法
*
* @param log 日志类
*/
public LogDecorator(Log log) {this.log = log;}
/**
* 记录调试日志
*
* @param message 信息
*/
@Override
public void debug(String message) {log.debug(message);
}
/**
* 记录一般日志
*
* @param message 信息
*/
@Override
public void info(String message) {log.info(message);
}
/**
* 记录正告日志
*
* @param message 信息
*/
@Override
public void warn(String message) {log.warn(message);
}
/**
* 记录谬误日志
*
* @param message 信息
*/
@Override
public void error(String message) {log.error(message);
}
}
邮件日志装璜器
/**
* 邮件日志装璜器
*/
public class MailLogDecorator extends LogDecorator {
/**
* 构造方法
*
* @param log 日志类
*/
public MailLogDecorator(Log log) {super(log);
}
/**
* 记录正告日志
*
* @param message 信息
*/
@Override
public void warn(String message) {log.warn(message);
mail(message);
}
/**
* 记录谬误日志
*
* @param message 信息
*/
@Override
public void error(String message) {log.error(message);
mail(message);
}
/**
* 发送邮件
*
* @param message 信息
*/
public void mail(String message) {
// 模仿邮件发送
log.info("邮件已发送,信息:" + message);
}
}
钉钉日志装璜器
/**
* 钉钉日志装璜器
*/
public class DingDingLogDecorator extends LogDecorator {
/**
* 构造方法
*
* @param log 日志类
*/
public DingDingLogDecorator(Log log) {super(log);
}
/**
* 记录正告日志
*
* @param message 信息
*/
@Override
public void warn(String message) {log.warn(message);
send(message);
}
/**
* 记录谬误日志
*
* @param message 信息
*/
@Override
public void error(String message) {log.error(message);
send(message);
}
/**
* 发送顶顶音讯
*
* @param message 信息
*/
public void send(String message) {
// 模仿邮件发送
log.info("钉钉音讯已发送,信息:" + message);
}
}
短信日志装璜器
/**
* 短信日志装璜器
*/
public class SMSLogDecorator extends LogDecorator {
/**
* 构造方法
*
* @param log 日志类
*/
public SMSLogDecorator(Log log) {super(log);
}
/**
* 记录谬误日志
*
* @param message 信息
*/
@Override
public void error(String message) {log.error(message);
send(message);
}
/**
* 发送短信
*
* @param message 信息
*/
public void send(String message) {
// 模仿短信发送
log.info("短信已发送,信息:" + message);
}
}
2.3 测试验证
2.3.1 测试验证类
/**
* 日志测试类
*/
public class LogTest {
/**
* 测试日志装璜器
*/
@Test
public void testLogDecorator() {Log log = new SMSLogDecorator(new DingDingLogDecorator(new MailLogDecorator(new Slf4jLog())));
log.debug("零碎调试开启");
log.info("零碎失常运行");
log.warn("数据为空正告");
log.error("mongo 连贯谬误");
}
}
2.3.2 测试后果
15:16:56.564 [main] DEBUG system_log - 零碎调试开启
15:16:56.566 [main] INFO system_log - 零碎失常运行
15:16:56.566 [main] WARN system_log - 数据为空正告
15:16:56.566 [main] INFO system_log - 邮件已发送,信息:数据为空正告
15:16:56.566 [main] INFO system_log - 钉钉音讯已发送,信息:数据为空正告
15:16:56.566 [main] ERROR system_log - mongo 连贯谬误
15:16:56.566 [main] INFO system_log - 邮件已发送,信息:mongo 连贯谬误
15:16:56.566 [main] INFO system_log - 钉钉音讯已发送,信息:mongo 连贯谬误
15:16:56.566 [main] INFO system_log - 短信已发送,信息:mongo 连贯谬误
Process finished with exit code 0
四、装璜器模式构造
- 部件 (Component)申明封装器和被封装对象的专用接口。
- 具体部件 (Concrete Component)类是被封装对象所属的类。它定义了根底行为,但装璜类能够扭转这些行为。
- 根底装璜 (Base Decorator)类领有一个指向被封装对象的援用成员变量。该变量的类型该当被申明为通用部件接口,这样他就能够援用具体的部件和装璜。装璜基类会将所有操作委派给被封装的对象。
- 具体装璜类 (Concrete Decorators)定义了可动静增加到部件的额定行为。具体装璜类会重写装璜基类的办法,并在调用父类办法之前或之后进行额定的行为。
- 客户端 (Client)能够应用多层装璜来封装部件,只有它能应用通用接口与所有对象互动即可。
设计模式并不难学,其自身就是多年教训提炼出的开发指导思想,关键在于多加练习,带着应用设计模式的思维去优化代码,就能构建出更正当的代码。
源码地址:https://github.com/yiyufxst/design-pattern-java
参考资料:
小博哥重学设计模式:https://github.com/fuzhengwei/itstack-demo-design
深刻设计模式:https://refactoringguru.cn/design-patterns/catalog