重學設計模式(五)—— 裝飾器、介面卡、門面和代理
Decorator裝飾器模式
裝飾模式指的是在不必改變原類檔案和使用繼承的情況下,動態地擴充套件一個物件的功能。它是通過建立一個包裝物件,也就是裝飾來包裹真實的物件。
java IO 流是裝飾模式一個典型的應用場景。
舉個生活中的例子,飲品店的飲料價格由原料(咖啡、茶……)價格和配料(糖、奶泡……)價格組成,我們是計算價格的呢?如果為每一種組合建立一個類,顯然不現實。但是如果我們把每一種飲品看作是配料對原料的修飾,那就簡單多了,參考上述類圖,我麼可以新建Beverage類,這是飲料的基類,提供一個抽象方法用於計算飲料價格:
Beverage.java
public abstract class Beverage {
String description = "Unknown Beverage";
public String getDescription(){
return description;
}
public abstract double cost();
}
在此基礎上我們建立兩個具體的原料型別Espresso和HouseBlend:
Espresso.java
public class Espresso extends Beverage {
public Espresso(){
this .description = "Espresso";
}
public double cost() {
return 1.99;
}
}
HouseBlend.java
public class HouseBlend extends Beverage{
public HouseBlend(){
this.description = "House Blend Coffee";
}
public double cost() {
return 0.89;
}
}
再來建立修飾類的基類Decorator和具體類Mocha:
Decorator.java
public abstract class Decorator extends Beverage {
public abstract String getDescription();
}
Mocha.java
public class Mocha extends Decorator{
private Beverage beverage;
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Mocha";
}
public double cost() {
return 0.2 + this.beverage.cost();
}
}
如果我們想要一杯HouseBlend配加一分Mocha,一杯Espresso配加兩份Mocha,就可以如下實現:
public class DecoratorTest {
public static void main(String[] args) {
//建立一個HouseBlend物件
Beverage beverage = new HouseBlend();
//用Mocha來修飾上述HouseBlend物件
Beverage beverage1 = new Mocha(beverage);
System.out.println(beverage1.getDescription() + " $" + beverage1.cost());
System.out.println("=====================================");
//建立一個Espresso物件
beverage = new Espresso();
//用2份Mocha來修飾上述HouseBlend物件
Beverage beverage2 = new Mocha(beverage);
beverage2 = new Mocha(beverage2);
System.out.println(beverage2.getDescription() + " $" + beverage2.cost());
}
}
執行結果:
Adaptor介面卡模式
將一個類的介面轉換成客戶希望的另外一個介面。Adapter模式使得原本由於介面不相容而不能一起工作的那些類可以一起工作。——Gang of Four
我們生活中電子產品的工作電壓一般都在36V以下,但是家裡都是220V的交流電,這個時候便有了電源介面卡這種東西。範圍再廣一點,大陸和香港地區的三相插座不一樣,一般商家向大陸顧客出售產品的時候會額外提供一個插座的轉換口。
生活中介面卡的例子比比皆是,放到程式設計中來,當一個類介面不是客戶想要的那種,我們便可以通過介面卡方式轉換該介面來滿足需求。
Adaptee.java
public interface Adaptee {
//需要被適配的類,目標介面
void adaptedOperation();
}
ConcreteAdaptee.java
public class ConcreteAdaptee implements Adaptee {
public void adaptedOperation() {
System.out.println("this is a concrete adaptee!");
}
}
Adaptor.java
public interface Adaptor {
//適配類,即客戶希望訪問的介面
void doSomething();
}
ConcreteAdaptor.java
public class ConcreteAdaptor implements Adaptor {
private Adaptee adaptee;
public ConcreteAdaptor(Adaptee adaptee) {
this.adaptee = adaptee;
}
public void doSomething() {
this.adaptee.adaptedOperation();
}
}
當我們希望通過訪問適配方法實現對目標方法的訪問,便可以如下實現:
public class AdaptorTest {
public static void main(String[] args) {
//目標介面
Adaptee adaptee = new ConcreteAdaptee();
//適配目標介面
Adaptor adaptor = new ConcreteAdaptor(adaptee);
//通過訪問適配方法實現訪問目標方法
adaptor.doSomething();
}
}
執行結果:
Facade門面模式
外觀模式通過封裝許多物件,以簡化它們的介面,此模式定義了一個高層的介面,這個介面使得這一子系統更加容易使用。
最少知識原則是門面模式遵循的一個設計原則。
最少知識原則:只和你的密友談話。
這個原則希望我們在設計中,不要讓太多的類耦合在一起,免得修改系統的一部分,會影響到其他部分。
Proxy代理模式
詳見博主之前的文章《動態代理》