装饰器模式
# 装饰器模式
装饰器模式是一种非常有用的设计模式,可以在保持代码灵活性和可维护性的同时,动态地扩展对象的功能。
# 定义
装饰器模式,也叫作包装器模式,是一种结构型设计模式,指在不改变原有对象的基础上,动态地给一个对象添加一些额外的功能。
# 结构
抽象组件(Component): 抽象组件定义了被装饰对象和装饰器共同实现的接口或抽象类。它可以是抽象类或接口,提供了装饰器和被装饰对象的一致性接口。
具体组件(Concrete Component): 具体组件是被装饰的对象,实现了抽象组件定义的接口或抽象类。它是装饰器模式中的原始对象,也是装饰器所装饰的目标。
抽象装饰器(Decorator): 抽象装饰器是一个抽象类或接口,它继承或实现了抽象组件的接口或抽象类。持有抽象组件的引用,并定义了一个与抽象组件一致的接口,用于封装具体装饰器和被装饰对象的交互。
具体装饰器(Concrete Decorators): 具体装饰器是抽象装饰器的子类,它实现了抽象装饰器定义的接口,在运行时可以动态地给被装饰对象添加新的行为或功能。
- img: https://bitouyun.com/images/design-pattern/decorator.png
link: https://bitouyun.com/images/design-pattern/decorator.png
name: 装饰器模式
2
3
提示
比较简单的场景下可以省略抽象组件和抽象装饰器。
# 优点
灵活性:装饰器模式允许在不改变原始对象的情况下,通过包装器对象来动态添加功能。可以根据需要组合多个装饰器,以实现不同的组合效果,从而提供更大的灵活性和可定制性。
开闭原则:通过装饰器模式,可以在不修改现有代码的情况下添加新的功能。这符合开闭原则,即对扩展开放,对修改关闭。
单一职责原则:装饰器模式允许将功能划分为多个单一的装饰器类,每个装饰器类只关注一种功能的添加或修改,从而遵循了单一职责原则。
代码复用:装饰器模式可以通过组合不同的装饰器类来实现代码的复用。不同的装饰器可以按照需要进行组合,以创建不同的组合效果。
# 缺点
复杂性增加:使用装饰器模式会增加一些额外的类和对象,从而增加了系统的复杂性。如果使用不当,可能会导致过多的装饰器类,使得代码难以理解和维护。
运行时开销:由于装饰器模式涉及包装器对象的嵌套调用,可能会在运行时产生一些性能开销。每个装饰器都需要进行额外的处理,可能会对系统的性能产生一定的影响。
# 应用场景
在不改变现有对象结构的情况下,动态地给对象添加功能。
需要灵活地组合和配置对象的功能,以满足不同的需求。
需要对对象的功能进行扩展,但是使用继承会导致类爆炸的情况,或者不希望通过继承来实现功能扩展。
需要在运行时动态地添加、修改或移除对象的功能。
常见的使用场景包括:输入/输出流处理、身份验证和授权、缓存系统、日志记录等。
装饰器模式与代理模式的区别
代理模式是控制对对象的访问,为其他对象提供一个代理以控制对这个对象的访问。代理模式可以在访问对象时添加额外的逻辑。
装饰器模式注重对对象功能的增强和扩展,而代理模式注重对对象的控制访问。
装饰器模式通过包装器对象来包装原始对象,形成一条装饰链;代理模式通过代理对象来控制对原始对象的访问。
装饰器模式保持了原始对象的接口完整性,客户端可以透明地使用装饰后的对象;代理模式可以隐藏原始对象的细节,客户端可能无法直接访问原始对象。
实际上,装饰器模式可以看作是一种特殊的代理模式,其中代理对象的主要职责是增强原始对象的功能。因此,装饰器模式和代理模式可以相互补充,并在某些情况下可以互换使用。
# 示例代码1
场景1
添加用户业务,使用装饰器模式记录日志时间。
/**
* 日志记录接口
* 抽象组件,定义了被装饰对象和装饰器共同实现的接口或抽象类
*/
public interface Logger {
// 记录日志
void log(String message);
}
2
3
4
5
6
7
8
/**
* 日志实现类
* 具体组件,是被装饰的对象,实现或继承了抽象组件定义的接口或抽象类。
*/
@Slf4j
public class SimpleLogger implements Logger {
@Override
public void log(String message) {
log.info("日志:{}", message);
}
}
2
3
4
5
6
7
8
9
10
11
/**
* 日志装饰器抽象类
* 抽象装饰器,继承或实现了抽象组件的接口或抽象类,持有一个抽象组件的引用。
*/
public abstract class LoggerDecorator implements Logger {
// 持有抽象组件的引用
protected Logger logger;
public LoggerDecorator(Logger logger) {
this.logger = logger;
}
// 封装具体装饰器和被装饰对象的交互
@Override
public void log(String message) {
logger.log(message);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 记录日志时间类
* 具体装饰器类,是抽象装饰器的子类,实现抽象装饰器定义的接口方法,可以动态给被装饰对象添加新的行为或功能。
*/
@Slf4j
public class TimeLoggerDecorator extends LoggerDecorator {
public TimeLoggerDecorator(Logger logger) {
super(logger);
}
public void log(String message) {
log.info("时间:{}", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
logger.log(message);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 测试类
*/
public class Client {
public static void main(String[] args) {
// 日志实现类
Logger logger = new SimpleLogger();
// 日志装饰器
logger = new TimeLoggerDecorator(logger);
// 记录日志
logger.log("创建用户");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
// Make sure to add code blocks to your code group
# 示例代码2
场景2
使用装饰器模式实现用户权限控制,限制用户对系统的操作。
/**
* 用户接口
* 抽象组件,定义了被装饰对象和装饰器共同实现的接口或抽象类
*/
public interface User {
void operate(String action);
}
2
3
4
5
6
7
/**
* 普通用户
* 具体组件,是被装饰的对象,实现或继承了抽象组件定义的接口或抽象类。
*/
@Slf4j
public class NormalUser implements User {
private String username;
public NormalUser(String username) {
this.username = username;
}
@Override
public void operate(String action) {
log.info("{}执行{}操作", username, action);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 抽象装饰器类
* 继承或实现了抽象组件的接口或抽象类,持有一个抽象组件的引用。
*/
public abstract class UserDecorator implements User {
// 持有一个用户接口引用
protected User user;
public UserDecorator(User user) {
this.user = user;
}
@Override
public void operate(String action) {
user.operate(action);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 权限检查装饰器
* 具体装饰器类,是抽象装饰器的子类,实现抽象装饰器定义的接口方法,可以动态给被装饰对象添加新的行为或功能。
*/
@Slf4j
public class PermissionCheckUserDecorator extends UserDecorator {
// 允许的操作列表
private List<String> allowOperations;
public PermissionCheckUserDecorator(User user, List<String> allowOperations) {
super(user);
this.allowOperations = allowOperations;
}
public void operate(String action) {
if (allowOperations.contains(action)) {
super.operate(action);
} else {
log.error("没有{}权限", action);
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* 测试类
*/
public class Client {
public static void main(String[] args) {
User user = new NormalUser("Mike");
// 允许的操作
List<String> allowOperations = Arrays.asList("add", "update", "select");
user = new PermissionCheckUserDecorator(user, allowOperations);
user.operate("add");
user.operate("update");
user.operate("select");
user.operate("delete");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Make sure to add code blocks to your code group