1 概述
装饰模式(Decorator Pattern),意在不改变原有对象的情况下,改变/增强它的方法。
2 装饰模式
在不违反开闭原则的前提下,要改变某个对象的行为,可以使用继承。然而继承不适用于类/方法被final
修饰的情况,而且一般需要了解类内部的情况,违反了迪米特法则。
装饰模式体现了组合优先于继承的思想,通过组合的方式,“装饰”对象的功能,也能达到改变对象行为的目的。装饰模式的实现模式和代理模式很相似,都是实现目标对象的接口,然后持有目标类,调用目标类的方法。代理模式更偏向于对对象的控制,给对象添加与其无关的功能(打日志,权限校验等);而装饰模式更偏向于对对象的增强,即增强对象原有的方法,装饰后的对象还是原来的对象。
3 案例
举个例子。定义一个Car
接口,看如何用装饰模式在不修改原有对象的基础上,对其方法进行增强:
public class Test {
public static void main(String[] args) {
Car basicCar = new BasicCar();
// 装饰类
Car sportsCar = new SportsCar(basicCar);
basicCar.drive();
System.out.println("top speed of basic car: " + basicCar.topSpeed());
System.out.println("=============");
sportsCar.drive();
System.out.println("top speed of sports car: " + sportsCar.topSpeed());
}
}
public interface Car {
void drive();
int topSpeed();
}
public class BasicCar implements Car {
@Override
public void drive() {
System.out.println("Car is driving...");
}
@Override
public int topSpeed() {
return 120;
}
}
// 装饰类
public class SportsCar implements Car {
// 被装饰对象
Car car;
SportsCar(Car car) {
this.car = car;
}
// 对drive()方法进行增强
@Override
public void drive() {
System.out.println("Sports Car is build with high performance engine...");
car.drive();
}
// 对topSpeed()方法进行增强
@Override
public int topSpeed() {
return car.topSpeed() + 60;
}
}
输出:
Car is driving...
top speed of basic car: 120
=============
Sports Car is build with high performance engine...
Car is driving...
top speed of sports car: 180
装饰类SportsCar
实现了被装饰对象的接口,同时持有被装饰对象的实例,在调用被装饰对象的方法前后进行“装饰”。不影响原有类BasicCar
的逻辑,符合开闭原则。
Java
中Collections
工具类就使用了装饰模式,synchronizedCollection(Collection<T> c)
方法返回了一个装饰对象,对集合添加了同步处理,unmodifiableCollection(Collection<? extends T> c)
方法返回了一个装饰对象,使得集合不能被修改。
4 总结
使用装饰模式可以在不改变原对象逻辑的情况下,实现对象方法的增强。