編輯:關於Android編程
這篇將會介紹裝飾者模式(Decorator Pattern),裝飾者模式也稱為包裝模式(Wrapper Pattern),結構型模式之一,其使用一種對客戶端透明的方式來動態的擴展對象的功能,同時它也是繼承關系的一種替代方案之一,但比繼承更加靈活。在現實生活中也可以看到很多裝飾者模式的例子,或者可以大膽的說裝飾者模式無處不在,就拿一件東西來說,可以給它披上無數層不一樣的外殼,但是這件東西還是這件東西,外殼不過是用來擴展這個東西的功能而已,這就是裝飾者模式,裝飾者的這個角色也許各不相同但是被裝飾的對象本質是不變的。
我們的目標是允許類統一擴展,在不修改現有代碼的情況下,就可搭配新的行為。如能實現這樣的目標,有什麼好處呢?這樣的設計具有彈性,可以應對改變,可以接受新的功能來應對改變的需求,也就是 OO 原則中的對擴展開放和對修改關閉的開閉原則。
動態地給一個對象添加一些額外的職責,就增加功能來說,裝飾者模式相比生成子類更加靈活,提供了有別於繼承的另一種選擇。
裝飾者模式可以靜態的,或者根據需要可以動態的在運行時為一個對象擴展功能。被裝飾者和眾多的裝飾者都是繼承自一個接口,他們有著一樣的行為特性。裝飾者模式是繼承的另一種選擇方式,繼承是在編譯的時候為類添加新的行為,並且這個改變會影響所有原來該類的實體,裝飾者模式就不一樣,它提供一種能夠在運行時根據需要選擇不同運行對象的功能。裝飾者模式和繼承這兩種方式的不同之處在某些擴展功能的情況下顯得尤為重要,在一些面向對象編程的語言中,類無法在運行時被創建,而且當需要擴張功能時,這些行為往往無法預測,這就意味著在每個可能的情況下,這個類都需要被創建,所以對比之下,裝飾者模式優點在於每個裝飾者都是對象,在運行時被創建,並且能夠在每次使用時根據需要自己組合。
我們現在來看看裝飾者模式的 uml 類圖:
裝飾者模式共有四大角色:<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCkNvbXBvbmVudKO6s+nP89fpvP6/ydLUysfSu7j2vdO/2rvy1d/Kx7Ppz/PA4KOsxuSz5LWxtcS+zcrHsbvXsMrOtcTUrcq8ttTP86Os08PAtLao0uXXsMrO1d+6zbG717DKztXftcS7+bG+0NDOqqGjQ29uY3JldGVDb21wb25lbnSjutfpvP6+38zlyrXP1sDguMPA4MrHIENvbXBvbmVudCDA4LXEu/mxvsq1z9ajrNKyysfO0sPH17DKzrXEvt/M5bbUz/Oho0RlY29yYXRvcqO6s+nP89ewys7V39ewys7X6bz+ttTP86OsxuTE2rK/0ru2qNKq09DSu7j21rjP8tfpvP621M/ztcTS/dPDoaPU2rTztuDK/cfpv/bPwqOsuMPA4M6qs+nP88Dgo6zQ6NKquPm+3bK7zay1xNewys7C37ytyrXP1rK7zay1xL7fzOXX08DgoaO1sci7o6zI57n7ysfXsMrOwt+8rbWl0rujrNa709DSu7j2tcTH6b/2z8LO0sPHv8nS1Lr2wtS4w8Dg1rG909f3zqq+38zltcTXsMrO1d+ho0NvbmNyZXRlRGVjb3JhdG9yQSC6zSBDb25jcmV0ZURlY29yYXRvckKjutewys7V377fzOXKtc/WwOC21LPpz/PXsMrO1d+1xL7fzOXKtc/WoaOhoaGh1NrS0dPQtcQgQ29tcG9uZW50ILrNIENvbmNyZXRlQ29tcG9uZW50IMzlz7XPwqOsyrXP1tewys7V38Sjyr3AtMCp1bnUrdPQz7XNs7XEuabE3KOsv8nS1LfWzqogNSC49rK91ui8zLPQu/LV38q1z9YgQ29tcG9uZW50INfpvP6jrMn6s8nSu7j2IERlY29yYXRvciDXsMrO1d+z6c/zwOCju9TayfqzybXE1eK49iBEZWNvcmF0b3Ig17DKztXfwODW0KOs1Pa809K7uPYgQ29tcG9uZW50ILXEy73T0LPJ1LG21M/zo7u9qyBDb25jcmV0ZUNvbXBvbmVudCC78tXfxuTL+9Do0qqxu9ewys61xLbUz/O0q8jrIERlY29yYXRvciDA4NbQsqK4s9a1uPjJz9K7sr21xCBDb21wb25lbnQgttTP86O71NrXsMrO1d8gRGVjb3JhdG9yIMDg1tCjrL2ry/nT0LXEstnX97a8zOa7u7PJuMMgQ29tcG9uZW50ILbUz/O1xLbU06ay2df3o7vU2iBDb25jcmV0ZURlY29yYXRvciDA4NbQo6y4+b7d0OjSqrbU06a4srjH0OjSqtbY0LS1xLe9t6iho6GhoaHXsMrO1d/Eo8q91NrUtMLr1tDTw7XE0rLKx7fHs6O24LXEo6zU2iBKYXZhILrNIEFuZHJvaWQg1tC2vMTcubu8+7W917DKztXfxKPKvbXE07DX06O6DQo8cD4mbmJzcDs8L3A+DQo8aDIgaWQ9"java-中的裝飾者模式">Java 中的裝飾者模式
最典型的就是 Java 中的 java.io 包下面的 InputStream 和 OutputStream 相關類了,初學 Java 的時候,看到這些類,頭都大了,其實學了裝飾者模式之後,再理解這些類就很簡單了,畫一個簡單的類圖來表示:
InputStream 類是一個抽象組件, FileInputStream,StringBufferInputStream 和 ByteArrayInputStream 類都是可以被裝飾者包起來的具體組件;FilterInputStream 是一個抽象裝飾者,所以它的四個子類都是一個個裝飾者了。
其次,對於 android 開發工程師來說,最最重要的就應該是“上帝類” Context 和其子類了,這些類我就不用解釋了,上一張類圖基本就明確了:
所以對於 Application,Activity 和 Service 等類來說,他們只是一個個裝飾者,都是用來裝飾 ContextImpl 這個被裝飾者類,Application 是在 createBaseContextForActivity 方法中,通過 ContextImpl 的靜態方法 createActivityContext 獲得一個 ContextImpl 的實例對象,並通過 setOuterContext 方法將兩者建立關聯;Activity 是通過 handleLaunchActivity 方法設置的 ContextImpl 實例,這個方法會獲取到一個Activity對象,在performLaunchActivity函數中會調用該activity的attach方法,這個方法把一個ContextImpl對象attach到了Activity中,具體可以看看我的這篇博客,裡面詳細介紹到了 Activity 的啟動過程:android 不能在子線程中更新ui的討論和分析。別的類在這裡就不介紹了,具體的大家可以去網上查閱相關資料。
我們這裡以一個圖形系統中的 Window 為例,一般情況窗口都是能夠垂直或者是左右歡動的,所以為了能夠更好的支持 Window 的滑動,給滑動的 Window 加上一個 ScrollBar 是一個不錯的方法,為了重用代碼,水平滑動的 Window 和垂直滑動的 Window 我們就能夠使用裝飾者模式去處理,基本類圖如下所示:
根據類圖,我們首先實現 Window 這個接口:
IWindow.class
public interface IWindow {
void draw();
String getDescription();
}
然後是被裝飾者 SimpleWindow 類,它實現了窗口的基本行為:
SimpleWindow.class
public class SimpleWindow implements IWindow {
@Override
public void draw() {
Log.e("shawn", "drawing a window");
}
@Override
public String getDescription() {
return "a window";
}
}
然後是裝飾者類角色的抽象父類:
WindowDecorator.class
public abstract class WindowDecorator implements IWindow{
private IWindow window;
public WindowDecorator(IWindow window) {
this.window = window;
}
@Override
public void draw() {
window.draw();
}
@Override
public String getDescription() {
return window.getDescription();
}
}
最後是實現該裝飾者父類的裝飾者子類:
HorizontalScrollBarDecorator.class
public class HorizontalScrollBarDecorator extends WindowDecorator {
public HorizontalScrollBarDecorator(IWindow window) {
super(window);
}
@Override
public void draw() {
super.draw();
Log.e("shawn", "then drawing the horizontal scroll bar");
}
@Override
public String getDescription() {
return super.getDescription() + " with horizontal scroll bar";
}
}
VerticalScrollBarDecorator.class
public class VerticalScrollBarDecorator extends WindowDecorator {
public VerticalScrollBarDecorator(IWindow window) {
super(window);
}
@Override
public void draw() {
super.draw();
Log.e("shawn", "then drawing the vertical scroll bar");
}
@Override
public String getDescription() {
return super.getDescription() + " with vertical scroll bar";
}
}
最後測試代碼:
switch (v.getId()) {
case R.id.btn_horizontal_window:
IWindow horizontalWindow = new HorizontalScrollBarDecorator(new SimpleWindow());
horizontalWindow.draw();
Log.e("shawn", "window description : " + horizontalWindow.getDescription());
break;
case R.id.btn_vertical_window:
IWindow verticalWindow = new VerticalScrollBarDecorator(new SimpleWindow());
verticalWindow.draw();
Log.e("shawn", "window description : " + verticalWindow.getDescription());
break;
}
結果:
com.android.decoratorpattern E/shawn: drawing a window
com.android.decoratorpattern E/shawn: then drawing the horizontal scroll bar
com.android.decoratorpattern E/shawn: window description : a window with horizontal scroll bar
com.android.decoratorpattern E/shawn: drawing a window
com.android.decoratorpattern E/shawn: then drawing the vertical scroll bar
com.android.decoratorpattern E/shawn: window description : a window with vertical scroll bar
代碼一目了然,結構清晰。
其實說到底,每一個寫過 Android 程序的人都應該用過裝飾者模式,因為每寫一個 Activity,就相當於是寫了一個裝飾者類,不經意間就用了裝飾者模式,大家想一想是不是,哈哈~~
裝飾者模式和代理模式有點類似,很多時候需要仔細辨別,容易混淆,倒不是說會把代理模式看成裝飾者模式,而是會把裝飾者模式看作代理模式。區分一下,裝飾者模式的目的是透明地為客戶端對象擴展功能,是繼承關系的一種替代方案,而代理模式則是給一個對象提供一個代理對象,並由代理對象來控制對原有對象的引用。裝飾者模式應該為所裝飾的對象增強功能;代理模式對代理的對象施加控制,但不對對象本身的功能進行增強。
同時有幾個要點需要提一下:
https://github.com/zhaozepeng/Design-Patterns/tree/master/DecoratorPattern
在html中大家都知道布局是什麼意思了,簡單來說就是將頁面劃分模塊,比如html中的div、table等。那麼Android中也是這樣的。Android五大布局讓界面更加
認識Http協議 Android中發送http網絡請求是很常見的,要有GET請求和POST請求。一個完整的http請求需要經歷兩個過程:客戶端發送請求到服務器,然後服務
最近由於項目需要,寶寶好久沒搞Android啦,又是因為項目需要,現在繼續弄Android,哎,說多了都是淚呀,別的不用多說,先搞一個登錄界面練練手,登錄界面可以說是An
GridView(網格視圖)是按照行列的方式來顯示內容的,一般用於顯示圖片,圖片等內容,比如實現九宮格圖,用GridView是首選,也是最簡單的。主要用於設置Adapte