淺談設計模式(二):裝飾器模式|中介模式|原型模式

  • 2020 年 2 月 11 日
  • 筆記

裝飾器模式(Decorator Pattern)

裝飾器模式可用來給一個類動態添加功能,將其裝飾成一個新的類。這就是裝飾器的概念。看到這裡我們可能會想,要達到這種效果,我們用子類繼承父類不就可以了嗎? 沒錯裝飾器模式,本身是一種繼承的替代方案。那既然是替代方案,那麼自然就有它不一樣的地方。

具體區別在哪裡呢? 請看

  • 裝飾器模式更靈活:繼承時父子類的關係是靜態的,而裝飾器模式是動態的,裝飾類和被裝飾類的關係是運行時候確認的
  • 裝飾類和被裝飾類的耦合關係是鬆散的,各自可以獨立變化

下面看看具體的代碼。具體過程可看注釋

// 1.首先我們有一個Pen接口  public interface Pen {    public void write();  }  // 2.Pencil類實現了Pen這個接口  public class Pencil implements Pen {      public void write () {          System.out.print("寫");      }  }  // 3.裝飾類PencilDecorator也實現了Pen這個接口,且代理調用Pencil的方法  public class PencilDecorator implements Pen{      Pen pen;      public PencilDecorator(Pen pen) {        this.pen = pen;      }      public void write () {        pen.write();      }  }  // 4.用具體裝飾類繼承PencilDecorator,這樣就可以做擴展變化  public class BluePencilDecorator extends PencilDecorator{      public BluePencilDecorator (Pen pen) {          super(pen);      }      public void writeBlue () {          this.write();          System.out.println("寫出來是藍色的");      }  }  // 同4.用具體裝飾類繼承PencilDecorator,這樣就可以做擴展變化  public class RedPencilDecorator extends PencilDecorator{      public RedPencilDecorator (Pen pen) {          super(pen);      }      public void writeRed () {          this.write();          System.out.println("寫出來是紅色的");      }  }  // 測試  public class Test {      public static void main(String args []) {         Pen pencil = new Pencil();         RedPencilDecorator redPencil = new RedPencilDecorator(pencil);         BluePencilDecorator bluePencil = new BluePencilDecorator(pencil);         redPencil.writeRed();         bluePencil.writeBlue();      }  }

輸出結果

代碼的結構如下圖所示

從這裡我們看到了,經過PencilDecorator類這一層的隔離,Pencil類和BluePencilDecorator類/RedPencilDecorator類在一定程度上解耦,從而各自獨立發展了。這就是代理模式能夠替代繼承的原因和它的獨特優勢

唉!! 等一下,好像看到了什麼熟悉的東西,請看

沒錯,這還真就是代理模式的代碼。

在這裡,我們可以從兩個角度去理解裝飾器模式。

  • 第一,從構成上看,裝飾器模式 = 代理模式 + 類繼承。 也就是在代理模式的基礎上,加了一堆繼承[代理類]的子類,從而進行擴展變化,並且還盡量減少了和原有類的聯繫。
  • 第二,從功能上看,代理模式側重的是「控制」,而裝飾器模式側重的是「擴展」。比如說,類A代理了類B,那麼這兩個類由於同一個接口的約束,它們的方法和實現的功能其實是一樣的。而類C裝飾了類D,那麼這個時候類C不僅僅具備了類D的方法,同時還能加入自己的特殊邏輯。

中介者模式(Mediator Pattern)

簡單的說,中介者模式是一個分散到集中的一個過程

還是看下具體的代碼

// Colleague接口  public interface Colleague {      public void handleExternal(Mediator mediator);      public void handleInternal();  }  // 中介者接口  public abstract class Mediator {     public Colleague A;     public Colleague B;     public Colleague C;     public Mediator (Colleague A, Colleague B, Colleague C) {         super();      this.A = A;      this.B = B;      this.C = C;    }    public abstract void handleA ();    public abstract void handleB ();    public abstract void handleC ();  }  // 實現了中介者接口的中介者類,封裝了不同Colleague類的對象間的複雜操作  public class ConcreteMediator extends Mediator{      public ConcreteMediator(Colleague A, Colleague B, Colleague C) {          super(A,B,C);      }      public void handleA() {          B.handleInternal();          C.handleInternal();      }      public void handleB() {        A.handleInternal();        C.handleInternal();      }      public void handleC() {        A.handleInternal();        B.handleInternal();      }  }  // Colleague類在涉及其他Colleague類的複雜操作的時候,通過中介者調用  public class A implements Colleague {      public void handleExternal(Mediator mediator) {        mediator.handleA();        System.out.println("---------------");      }      public void handleInternal() {          System.out.println("A");      }  }  // Colleague類在涉及其他Colleague類的複雜操作的時候,通過中介者調用  public class B implements Colleague {      public void handleExternal(Mediator mediator) {          mediator.handleB();          System.out.println("---------------");      }      public void handleInternal() {          System.out.println("B");      }  }  // Colleague類在涉及其他Colleague類的複雜操作的時候,通過中介者調用  public class C implements Colleague {      public void handleExternal(Mediator mediator) {          mediator.handleC();          System.out.println("---------------");      }        public void handleInternal() {          System.out.println("C");      }  }  // 測試  public class main {      public static void main(String args []) {          Colleague a = new A();          Colleague b = new B();          Colleague c = new C();          Mediator mediator = new ConcreteMediator(a,b,c);          a.handleExternal(mediator);          b.handleExternal(mediator);          c.handleExternal(mediator);      }  }

結果輸出

中介者模式理解起來,就好像

  1. 你有很多雜亂的物品擺放在房間的不同地方,找起來很不好找,現在把這些物品統一放到一個柜子里,方便集中管理。
  2. 一群人去食堂打飯的時候,如果各自去取菜那麼食堂可能亂做一團,所以這時候食堂大媽就成為了「中介者」

原型模式(Prototype Pattern)

原型模式是什麼?

一句話,原型模式就是克隆對象,完了。

這麼簡單? 這也能叫設計模式?

沒錯,就是這樣

讓我們看下代碼

// 通過實現Cloneable接口並重寫clone方法的方式,讓Bar對象變得可克隆。  public class Bar implements Cloneable {      String value;      public String getValue () {        return value;      }      public void setValue (String value) {          this.value = value;      }      public Bar clone() {          Bar clone = null;          try {              clone = (Bar)super.clone();          } catch (CloneNotSupportedException e) {              e.printStackTrace();          }          return clone;      }  }  // 調用clone方法可以克隆對象  public class mian {      public static void main(String args []) {        Bar bar = new Bar();        Bar bar2 = bar.clone();        bar.setValue("1");        bar2.setValue("2");        System.out.println(bar.getValue());        System.out.println(bar2.getValue());      }  }

運行結果

告訴我,原型模式的本質是什麼

原型模式的本質就是—— 套娃

原型模式的優缺點

  • 原型模式的優點: 底層的二進制實現拷貝,相比起new操作可以節約性能
  • 原型模式的缺點: 構造函數沒有調用,犧牲了靈活性