装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
怎么做?
- 新建一个类,该类耦合了需要装饰的类,将实现传递进来,保证原有功能的完整性。为了表明该类是某接口的包装类,所以一般声明为
abstract
类,即使该类并无抽象方法。 - 新建一个需要扩充功能的类,继承上面新建的抽象类,增加新扩展的功能即可。
代码示例:
接口的抽象包装类
/**
* {@link org.springframework.core.env.Environment} 接口的抽象包装类。
* @author pleuvoir
*/
public abstract class AbstractEnvironmentWrap implements Environment {
protected Environment environment;
public AbstractEnvironmentWrap(Environment environment) {
this.environment = environment;
}
@Override
public boolean containsProperty(String key) {
return environment.containsProperty(key);
}
@Override
public String getProperty(String key) {
return environment.getProperty(key);
}
@Override
public String getProperty(String key, String defaultValue) {
return environment.getProperty(key, defaultValue);
}
@Override
public <T> T getProperty(String key, Class<T> targetType) {
return environment.getProperty(key, targetType);
}
@Override
public <T> T getProperty(String key, Class<T> targetType, T defaultValue) {
return environment.getProperty(key, targetType, defaultValue);
}
@Override
public <T> Class<T> getPropertyAsClass(String key, Class<T> targetType) {
return environment.getPropertyAsClass(key, targetType);
}
@Override
public String getRequiredProperty(String key) throws IllegalStateException {
return environment.getRequiredProperty(key);
}
@Override
public <T> T getRequiredProperty(String key, Class<T> targetType)
throws IllegalStateException {
return environment.getRequiredProperty(key, targetType);
}
@Override
public String resolvePlaceholders(String text) {
return environment.resolvePlaceholders(text);
}
@Override
public String resolveRequiredPlaceholders(String text)
throws IllegalArgumentException {
return environment.resolveRequiredPlaceholders(text);
}
@Override
public String[] getActiveProfiles() {
return environment.getActiveProfiles();
}
@Override
public String[] getDefaultProfiles() {
return environment.getDefaultProfiles();
}
@Override
public boolean acceptsProfiles(String... profiles) {
return environment.acceptsProfiles(profiles);
}
}
需要扩充功能的实现类
/**
* {@link org.springframework.core.env.Environment} 包装类,提供了更为简便的数据获取方法
* @author pleuvoir
*
*/
public class EnvironmentWrap extends AbstractEnvironmentWrap {
public EnvironmentWrap(Environment environment) {
super(environment);
}
/**
* 获取Integer类型的数据,若数据格式不可转换为Integer类型,将抛出异常{@link NumberFormatException}
* @param key
* @return
*/
public Integer getInteger(String key) {
String val = super.getProperty(key);
return Integer.valueOf(val);
}
/**
* 获取Integer类型的数据,并提供默认的值,若数据格式不可转换为Integer类型或者为null时,将会返回默认值
* @param key
* @param defaultVal
* @return
*/
public Integer getInteger(String key, Integer defaultVal) {
Integer i = null;
try {
i = getInteger(key);
} catch (NumberFormatException e) {
}
if (i == null) {
i = defaultVal;
}
return i;
}
/**
* 获取Long类型的数据,若数据格式不可转换为Long类型,将抛出异常{@link NumberFormatException}
* @param key
* @return
*/
public Long getLong(String key) {
String val = super.getProperty(key);
return Long.valueOf(val);
}
/**
* 获取Long类型的数据,并提供默认的值,若数据格式不可转换为Long类型或者为null时,将会返回默认值
* @param key
* @param defaultVal
* @return
*/
public Long getLong(String key, Long defaultVal) {
Long i = null;
try {
i = getLong(key);
} catch (NumberFormatException e) {
}
if (i == null) {
i = defaultVal;
}
return i;
}
/**
* 获取Double类型的数据,若数据格式不可转换为Double类型,将抛出异常{@link NumberFormatException}
* @param key
* @return
*/
public Double getDouble(String key) {
String val = super.getProperty(key);
return Double.valueOf(val);
}
/**
* 获取Double类型的数据,并提供默认的值,若数据格式不可转换为Double类型或者为null时,将会返回默认值
* @param key
* @param defaultVal
* @return
*/
public Double getDouble(String key, Double defaultVal) {
Double i = null;
try {
i = getDouble(key);
} catch (NumberFormatException e) {
}
if (i == null) {
i = defaultVal;
}
return i;
}
/**
* 获取BigDecimal类型的数据,若数据格式不可转换为BigDecimal类型,将抛出异常
* {@link NumberFormatException}
* @param key
* @return
*/
public BigDecimal getBigDecimal(String key) {
String val = super.getProperty(key);
return new BigDecimal(val);
}
/**
* 获取BigDecimal类型的数据,并提供默认的值,若数据格式不可转换为BigDecimal类型或者为null时,将会返回默认值
* @param key
* @param defaultVal
* @return
*/
public BigDecimal getBigDecimal(String key, BigDecimal defaultVal) {
BigDecimal i = null;
try {
i = getBigDecimal(key);
} catch (NumberFormatException e) {
}
if (i == null) {
i = defaultVal;
}
return i;
}
/**
* 获取Boolean类型的数据,若数据格式不可转换为Boolean类型,将返回false
* @param key
* @return
*/
public Boolean getBoolean(String key) {
String val = super.getProperty(key);
return Boolean.valueOf(val);
}
/**
* 获取String类型的数据
* @param key
* @return
*/
public String getString(String key) {
return super.getProperty(key);
}
}
实际上除了扩展原有功能外,还可以修改原有方法的实现,在原有方法前后增加新的执行方法,这种使用方法有点代理模式的感觉。
建议:如果只是扩展新功能(提供新方法),类的后缀使用 Wrap
,如果对原有方法进行了修改则使用 Decorator
。
结论
在不修改原有类的基础上进行扩展功能,可代替继承。特别适合对一些 jar 包或者不能修改源代码功能的扩展。如果多装饰几次,就会变得无比的麻烦,可参考 java IO 的实现方式。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于