1.前言
面向對象三大基本特征中就有繼承,表現了對代碼的重用和對新功能的擴展。代理模式很好地完成了代碼重用,功能都是由被代理者提供,它只負責判斷是否調用。就像你住在一個房子里,外人都知道去那找你,但見你前得先進門。
而裝飾模式則可以引入新功能,替代繼承關系,所以,能不能增加功能或者改進功能就是裝飾模式與代理模式的區別。
2.概念
裝飾模式指動態地給一個對象添加一些額外的職責。所謂動態,就是在定義類的時候,不明確聲明與別的類或者接口的關系。由于裝飾模式基礎是代理模式,而代理模式在結構上組合了原始對象,所以與原始對象沒有硬性的聯系,可以比子類更加靈活地添加功能。
3.場景
李四準備買房,但是工作太忙,只好委托中介。他向中介說明買房的條件,并要求中介在簽約前一定要到現場看房,簽約后將協議帶給他。
4.寫法
由于增加的功能很單一,可以直接在代理模式的基礎上完成。
// 1.聲明需要代理的操作
public interface Buyer {
void buy();
}
// 2.被代理者實現操作
public class LiSi implements Buyer {
@Override
public void buy() {
System.out.println("我要買這套房");
}
}
// 3.代理者調用被代理者的方法
public class Middleman implements Buyer {
private Buyer customer;
public Middleman(Buyer customer) {
super();
this.customer = customer;
}
@Override
public void buy() {
// 可以在調用被代理者方法前后附加動作
System.out.println("中介已到現場看房");
customer.buy();
System.out.println("中介已簽協議并帶回");
}
}
public class Main {
public static void main(String[] args) {
// 由中介完成所有事
Buyer liSi = new LiSi();
Buyer middleman = new Middleman(liSi);
middleman.buy();
}
}
這里強調一下,上面的代碼是在代理模式下改的,有些稱謂不對。第一點中聲明需要代理的操作,其實是聲明抽象組件,可以是抽象類或接口;第二點中被代理者實現操作,其實是實現具體組件;第三點中代理者調用被代理者的方法,其實是實現具體裝飾。
既然強調添加功能的靈活性,那就考慮不同條件下有不同的額外功能。李四要求若是新房,條件不變;若是二手房,則必須自己親自去看。
// 1.抽象裝飾者
public abstract class Agency implements Buyer {
private Buyer customer;
public Agency(Buyer customer) {
super();
this.customer = customer;
}
@Override
public void buy() {
// 子類重寫實現不同裝飾邏輯
customer.buy();
}
}
// 2.具體裝飾者
public class FirstAgency extends Agency {
public FirstAgency(Buyer customer) {
super(customer);
}
@Override
public void buy() {
// 新房的裝飾邏輯
System.out.println("中介已到現場看房");
super.buy();
System.out.println("中介已簽協議并帶回");
}
}
public class SecondAgency extends Agency {
public SecondAgency(Buyer customer) {
super(customer);
}
@Override
public void buy() {
// 二手房的裝飾邏輯
System.out.println("李四親自到場看房");
super.buy();
}
}
public class Main {
public static void main(String[] args) {
Buyer liSi = new LiSi();
// 附加新房的要求
Buyer first = new FirstAgency(liSi);
first.buy();
// 附加二手房的要求
Buyer second = new SecondAgency(liSi);
second.buy();
}
}
實現了子類的作用,但是卻沒有破壞類的層次結構,僅僅是將原類和新方法封裝在了一起。舉個例子,曹操挾天子以令諸侯,他沒有皇族血脈,但是可以自由地行使皇命。
5.總結
裝飾模式能夠具有這樣的特性,主要還是在于它的結構。使用組合關系,獲取原有對象的訪問權,并添加自己的方法。可以發現,自講解結構型模式開始,組合這個概念就不斷出現,它是使用對象模式的基礎。