- 作者:老汪软件技巧
- 发表时间:2024-09-30 17:02
- 浏览量:
装饰模式(Decorator Pattern)是一种结构型设计模式,它允许你在不改变原有对象结构的情况下,动态地给对象添加新的功能。装饰模式通过创建一个装饰类,包裹原有的对象,并在装饰类中实现新的功能,同时调用被装饰对象的方法来保持原有行为。
以下是装饰模式的主要特点和定义:
一、主要角色
Component(抽象构件) :
ConcreteComponent(具体构件) :
Decorator(抽象装饰者) :
ConcreteDecorator(具体装饰者) :
业务类图
classDiagram
class Beverage {
<>
+description : String
+cost() : double
+getDescription() : String
}
class Espresso {
+Espresso()
+cost() : double
+getDescription() : String
}
class CondimentDecorator {
<>
+beverage : Beverage
+cost() : double
+getDescription() : String
}
class Milk {
+Milk(Beverage)
+cost() : double
+getDescription() : String
}
class Sugar {
+Sugar(Beverage)
+cost() : double
+getDescription() : String
}
Espresso --|> Beverage
Milk --|> CondimentDecorator
Sugar --|> CondimentDecorator
Beverage <|-- CondimentDecorator
代码
以下是用 Java 实现装饰器模式的示例代码。假设我们有一个饮料的场景,有基本的咖啡和可以添加各种调料(如牛奶、糖等)的装饰器。
首先定义抽象构件Beverage (饮料):
public abstract class Beverage {
public String description = "Unknown Beverage";
public abstract double cost();
public String getDescription() {
return description;
}
}
然后实现具体构件Espresso(浓缩咖啡):
public class Espresso extends Beverage {
public Espresso() {
description = "Espresso";
}
@Override
public double cost() {
return 1.99;
}
}
接着定义抽象装饰者CondimentDecorator:
public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}
再实现具体装饰者Milk(牛奶):
public class Milk extends CondimentDecorator {
private Beverage beverage;
public Milk(Beverage beverage) {
this.beverage = beverage;
}
@Override
public double cost() {
return beverage.cost() + 0.5;
}
@Override
public String getDescription() {
return beverage.getDescription() + ", Milk";
}
}
以及另一个具体装饰者Sugar(糖):
public class Sugar extends CondimentDecorator {
private Beverage beverage;
public Sugar(Beverage beverage) {
this.beverage = beverage;
}
@Override
public double cost() {
return beverage.cost() + 0.2;
}
@Override
public String getDescription() {
return beverage.getDescription() + ", Sugar";
}
}
最后使用这些类:
public class Main {
public static void main(String[] args) {
Beverage espresso = new Espresso();
System.out.println(espresso.getDescription() + " $" + espresso.cost());
Beverage espressoWithMilk = new Milk(espresso);
System.out.println(espressoWithMilk.getDescription() + " $" + espressoWithMilk.cost());
Beverage espressoWithMilkAndSugar = new Sugar(espressoWithMilk);
System.out.println(espressoWithMilkAndSugar.getDescription() + " $" + espressoWithMilkAndSugar.cost());
}
}
在这个示例中,Beverage是抽象构件,定义了饮料的基本接口。Espresso是具体构件,代表基本的浓缩咖啡。CondimentDecorator是抽象装饰者,Milk和Sugar是具体装饰者,它们在不改变原有对象结构的情况下,给饮料添加了新的功能(如添加牛奶或糖后的描述和价格变化)。
框架中的使用spring
在 Spring 框架中,装饰器模式有一些体现,比如在 Spring AOP(面向切面编程)中:
一、Spring AOP 的实现
Spring AOP 通过创建代理对象来实现面向切面编程。在这个过程中,可以看作是对目标对象进行了装饰。
例如,当我们定义一个切面来对某个业务方法进行增强时,Spring 会在运行时创建一个代理对象,这个代理对象包裹着目标对象,并在调用目标方法前后执行切面中定义的逻辑(如日志记录、性能监控等)。
以下是一个简单的示例:
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.demo.service.*.*(..))")
public void logBeforeMethodExecution(JoinPoint joinPoint) {
System.out.println("Before method execution: " + joinPoint.getSignature().getName());
}
@AfterReturning(pointcut = "execution(* com.example.demo.service.*.*(..))", returning = "result")
public void logAfterMethodExecution(JoinPoint joinPoint, Object result) {
System.out.println("After method execution. Result: " + result);
}
}
这里,LoggingAspect类就像是一个装饰器,它在不改变目标对象(被切面增强的业务类中的方法)结构的情况下,为目标方法添加了日志记录的功能。
二、自定义 BeanPostProcessor
Spring 允许我们实现自定义的BeanPostProcessor来对 Bean 进行额外的处理,这也可以看作是一种装饰器模式的应用。
例如,我们可以创建一个BeanPostProcessor来在 Bean 创建后对其进行一些特定的初始化或增强操作:
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
// 在 Bean 初始化之前进行一些处理
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof SomeService) {
SomeService service = (SomeService) bean;
// 对 SomeService 类型的 Bean 进行特定的增强
return new DecoratedService(service);
}
return bean;
}
}
在这个例子中,CustomBeanPostProcessor可以看作是一个装饰器,它在 Bean 创建后根据特定的条件对 Bean 进行装饰(增强)。
综上所述,Spring 在多个方面体现了装饰器模式的思想,使得我们可以在不改变原有代码结构的情况下,动态地为对象添加新的功能。
mybatis
在 MyBatis 中,装饰器模式也有一定的体现。
例如,MyBatis 的缓存机制可以看作是一种装饰器模式的应用。MyBatis 提供了基础的缓存实现,同时也允许通过自定义缓存装饰器来增强缓存功能。
假设我们有一个自定义的二级缓存装饰器,它在原有的二级缓存基础上增加了一些额外的功能,如缓存统计、缓存过期时间控制等。
以下是一个简单的示例:
import org.apache.ibatis.cache.Cache;
import java.util.concurrent.locks.ReadWriteLock;
public class CustomCacheDecorator implements Cache {
private final Cache delegate;
public CustomCacheDecorator(Cache delegate) {
this.delegate = delegate;
}
@Override
public String getId() {
return delegate.getId();
}
@Override
public void putObject(Object key, Object value) {
delegate.putObject(key, value);
}
@Override
public Object getObject(Object key) {
// 可以在这里添加额外的逻辑,如缓存统计
return delegate.getObject(key);
}
@Override
public Object removeObject(Object key) {
return delegate.removeObject(key);
}
@Override
public void clear() {
delegate.clear();
}
@Override
public int getSize() {
return delegate.getSize();
}
@Override
public ReadWriteLock getReadWriteLock() {
return delegate.getReadWriteLock();
}
}
在 MyBatis 的配置中,可以使用这个自定义的缓存装饰器来增强缓存功能:
<configuration>
<settings>
<setting name="cacheEnabled" value="true"/>
settings>
<plugins>
<plugin interceptor="com.example.CustomCacheInterceptor">
<property name="delegateCache" value="org.mybatis.caches.ehcache.EhcacheCache"/>
plugin>
plugins>
configuration>
这里的CustomCacheInterceptor可以在创建缓存对象时,使用自定义的装饰器来包裹原有的缓存实现,从而实现对缓存功能的增强。
通过这种方式,MyBatis 利用装饰器模式在不改变原有缓存结构的情况下,灵活地扩展了缓存的功能。
总结
使用场景
需要在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。当不能采用继承的方式来扩展对象的功能时,可以使用装饰模式。例如,当存在大量独立的扩展功能,而采用继承会导致大量的子类时。
优点
比继承更加灵活:可以在运行时动态地给对象添加功能,而继承是在编译时确定的。可以对一个对象进行多次装饰,添加不同的功能组合。符合开闭原则:可以在不修改原有代码的情况下,添加新的功能。
缺点
装饰模式会增加许多小类,使程序变得复杂。装饰模式的装饰顺序可能会影响最终的结果,需要仔细考虑装饰的顺序。