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 總結
使用裝飾模式可以在不改變原對象邏輯的情況下,實現對象方法的增強。