流行框架源碼分析(16)-Decorator裝飾模式

主目錄見:Android高級進階知識(這是總目錄索引)
?今天要講裝飾模式其實跟之前的代理模式實現上有點相似,但是在使用上會有些不同,在我理解上呢,代理側重對被代理對象的功能修改,同時限制了其他類對被代理對象的訪問。然而裝飾模式更側重被裝飾對象功能的嵌套增強且不限制其他類對被裝飾對象的訪問,為什么這么說呢?在等會要講的IO流你就知道,為了增強功能,IO流可以嵌套多層來增強功能而且可以單獨使用。這里我們首先看下裝飾模式的UML類圖,今天不畫,直接copy一張:

裝飾模式

角色介紹:

  • Component:抽象組件,可以是一個接口或抽象類,是被裝飾的原始對象;
  • ConcreteComponent:組件的具體實現類。是被裝飾的具體對象,就像上面英文說的這是我們要動態(tài)添加行為的類。
  • Decorator:抽象裝飾者,職責是裝飾被裝飾的對象。內部一定有一個對被裝飾者的引用。一般情況下也是一個抽象類,根據具體邏輯實現不同的子類。如果邏輯簡單可以直接是實現類。
  • ConcreteDecorator:具體裝飾者類,裝飾者可以添加新的方法,而且能在原有的方法前面或者后面添加新的行為。

一.目標

今天有一個目標也是以前自己學IO流時候留下的問題,因為以前學IO流的時候總感覺怎么這么多類嵌套來嵌套去,感覺都用不起來。那么今天目標就是:
1.從裝飾模式看IO流的使用;
2.明白裝飾模式在什么場景下使用。

二.模式講解

我們這里也來想象一個場景,比如你今天要去參加一個party,你挑了一件T恤,一條牛仔,一雙奧康皮鞋準備出席。然后出門發(fā)現天氣挺冷,所以進門加了件毛衣,然后走到路上,發(fā)現大家穿著時髦,所以想了想,趕緊去店里買了個帽子,然后出席了party。所以我們首先來看抽象組件角色:

public interface Component {
    void decorate();
}

然后我們看下我們具體的組件角色:

public class PersonComponent implements Component {

    @Override
    public void decorate() {
        System.out.println("我穿了一件T恤,一條牛仔,一雙奧康皮鞋");
    }
}

可以看到這個組件是可以獨立運行的,已經是完整的實現了。但是如果我們這是要增加他的功能呢?我們接下來看抽象裝飾者角色:

public abstract class Decorator implements Component {
    private Component component;
    
     public Decorator(Component component) {
         this.component = component;
    }

    @Override
    public void decorate() {
        if (null != component) {
            component.decorate();
        }
    }
}

可以看到這個抽象裝飾者實現了Component,并且持有了Component的一個引用。同時調用了組件的decorate()方法。然后我們分別看下兩個具體的裝飾類:

public class SweaterDecorator extends Decorator {

    public SweaterDecorator(Component component) {
        super(component);
    }

    @Override
    public void decorate() {
        super.decorate();
        System.out.println("加了件毛衣");
    }
}

還有一個是帽子的裝飾類:

public class HatDecorator extends Decorator {

    public HatDecorator(Component component) {
        super(component);
    }

    @Override
    public void decorate() {
        super.decorate();
        System.out.println("加個帽子");
    }
}

可以看到各個角色非常明顯,然后我們看下使用:

Decorator hatDecorator = new HatDecorator(new SweaterDecorator(new PersonComponent()));
hatDecorator.decorate();

看到這里你是不是很自然地想起來I/O流的使用方法。那么我們就引出我們的I/O流的使用。

1.I/O流的使用方法

我們這里先來看幾張I/O流的族譜,首先我們來看字節(jié)流的族譜:

OutputStream

然后我們再來看InputStream的繼承結構:
InputStream

從圖中我們可以很清楚地看到幾個裝飾者模式的角色。我們以InputStream為例來分析,首先我們看到這里的InputStream就是裝飾者模式里面的Component角色,看看他的實現:
public abstract class InputStream implements Closeable {
......
}
這個InputStream里面有一些方法:
方法

然后接著看具體組件角色ConcreteComponent這里分別有:

ByteArrayInputStream
FileInputStream
ObjectInputStream
PipedInputStream
SequenceInputStream
StringBufferInputStream

這里的具體組件角色都有他特定的功能,比如說,FileInputStream代表一個文件輸入流并提供讀取文件內容的功能,ObjectInputStream提供了對象反序列化的功能。他們都是可以獨立使用的具體組件角色。接著我們看到抽象裝飾者角色Decorator,這里就是FilterInputStream,我們來看下他的實現:

public class FilterInputStream extends InputStream {
  protected volatile InputStream in;
  protected FilterInputStream(InputStream in) {
        this.in = in;
    }

  public int read() throws IOException {
        return in.read();
    }
.....
}

可以看到這個抽象裝飾者角色持有了具體組件角色的引用,然后調用了具體組件角色的方法。然后我們看到繼承結構中具體裝飾者ConcreteDecorator有四個:

BufferedInputStream
DataInputStream
LineNumberInputStream
PushbackInputStream

我們這里以BufferedInputStream為例,我們看下他的read()方法:

   public synchronized int read() throws IOException {
        if (pos >= count) {
            fill();
            if (pos >= count)
                return -1;
        }
        return getBufIfOpen()[pos++] & 0xff;
    }

?這里的方法邏輯就是如果pos>=count,那么我們就開始填充緩存,在fill()方法里面會調用InputStream來讀數據到緩存里面,否則直接從緩存里面讀取。這里我們不詳細展開,我們知道BufferedInputStream就是一個具體裝飾者角色,它能為一個原本沒有緩沖功能的InputStream添加上緩沖的功能。

?有了上面的的基礎我們就知道怎么使用I/O流了,FileInputStream這個具體組件角色本來是沒有緩存功能的,但是我們在讀取文件的時候我們希望他有緩存功能,所以我們就可以用裝飾模式來使用他:

       InputStream in = new FileInputStream("test.txt");
        // 字節(jié)緩存流
        BufferedInputStream bis = new BufferedInputStream(in);
        byte[] bs = new byte[20];
        int len = 0;
        while ((len = bis.read(bs)) != -1) {

            System.out.print(new String(bs, 0, len));
            // ABCD
            // hello
        }
        // 關閉流
        bis.close();

所以以后我們以此類推,我們就可以使用好我們的I/O流了。

2.Android中的裝飾者模式

Context繼承結構圖

這邊選擇了一張看著比較清楚的圖,我們這里不展開講,只是說說這里面的裝飾者模式的角色。
1.抽象組件角色:Context
2.具體組件角色:ContextImpl
3.抽象裝飾角色:ContextWrapper
4.具體裝飾角色:Service,Application,ContextThemeWrapper
這里的角色非常清晰明顯,具體的代碼大家可以自己去看看。

總結:裝飾模式在使用中還是非常廣泛和容易的,如果你有需求正好是對一個已有的類進行功能增強的話,那么你可以考慮考慮這個設計模式是不是適用,設計模式就是用的多了才有感覺,希望大家一起努力哈。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1 場景問題# 1.1 復雜的獎金計算## 考慮這樣一個實際應用:就是如何實現靈活的獎金計算。 獎金計算是相對復雜...
    七寸知架構閱讀 4,051評論 4 67
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,237評論 25 708
  • 設計模式匯總 一、基礎知識 1. 設計模式概述 定義:設計模式(Design Pattern)是一套被反復使用、多...
    MinoyJet閱讀 3,970評論 1 15
  • 中秋之夜,托著下巴,看著窗外,好久沒有靜靜的觀望月亮了,它可真美,美的我不知改用什么詞匯來形容,我怕任何一個詞語...
    lemontree_aeca閱讀 310評論 0 2
  • 一、本期目標: 建立和諧的家庭關系,改善緩和父子關系。 愿景:擁有一個幸福和諧的家庭,一家人友好相處相互信...
    夏寧點點閱讀 189評論 0 0