主目錄見:Android高級進(jìn)階知識(這是總目錄索引)
?今天要講裝飾模式其實跟之前的代理模式實現(xiàn)上有點(diǎn)相似,但是在使用上會有些不同滚朵,在我理解上呢冤灾,代理側(cè)重對被代理對象的功能修改,同時限制了其他類對被代理對象的訪問辕近。然而裝飾模式更側(cè)重被裝飾對象功能的嵌套增強(qiáng)且不限制其他類對被裝飾對象的訪問韵吨,為什么這么說呢?在等會要講的IO流你就知道移宅,為了增強(qiáng)功能归粉,IO流可以嵌套多層來增強(qiáng)功能而且可以單獨(dú)使用。這里我們首先看下裝飾模式的UML類圖,今天不畫漏峰,直接copy一張:
角色介紹:
- Component:抽象組件糠悼,可以是一個接口或抽象類,是被裝飾的原始對象;
- ConcreteComponent:組件的具體實現(xiàn)類浅乔。是被裝飾的具體對象倔喂,就像上面英文說的這是我們要動態(tài)添加行為的類。
- Decorator:抽象裝飾者靖苇,職責(zé)是裝飾被裝飾的對象席噩。內(nèi)部一定有一個對被裝飾者的引用。一般情況下也是一個抽象類顾复,根據(jù)具體邏輯實現(xiàn)不同的子類班挖。如果邏輯簡單可以直接是實現(xiàn)類鲁捏。
- ConcreteDecorator:具體裝飾者類芯砸,裝飾者可以添加新的方法萧芙,而且能在原有的方法前面或者后面添加新的行為。
一.目標(biāo)
今天有一個目標(biāo)也是以前自己學(xué)IO流時候留下的問題假丧,因為以前學(xué)IO流的時候總感覺怎么這么多類嵌套來嵌套去双揪,感覺都用不起來。那么今天目標(biāo)就是:
1.從裝飾模式看IO流的使用包帚;
2.明白裝飾模式在什么場景下使用渔期。
二.模式講解
我們這里也來想象一個場景,比如你今天要去參加一個party渴邦,你挑了一件T恤疯趟,一條牛仔,一雙奧康皮鞋準(zhǔn)備出席谋梭。然后出門發(fā)現(xiàn)天氣挺冷信峻,所以進(jìn)門加了件毛衣,然后走到路上瓮床,發(fā)現(xiàn)大家穿著時髦盹舞,所以想了想,趕緊去店里買了個帽子隘庄,然后出席了party踢步。所以我們首先來看抽象組件角色:
public interface Component {
void decorate();
}
然后我們看下我們具體的組件角色:
public class PersonComponent implements Component {
@Override
public void decorate() {
System.out.println("我穿了一件T恤,一條牛仔丑掺,一雙奧康皮鞋");
}
}
可以看到這個組件是可以獨(dú)立運(yùn)行的获印,已經(jīng)是完整的實現(xiàn)了。但是如果我們這是要增加他的功能呢吼鱼?我們接下來看抽象裝飾者角色:
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();
}
}
}
可以看到這個抽象裝飾者實現(xiàn)了Component蓬豁,并且持有了Component的一個引用。同時調(diào)用了組件的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é)流的族譜:
然后我們再來看InputStream的繼承結(jié)構(gòu):
從圖中我們可以很清楚地看到幾個裝飾者模式的角色。我們以InputStream為例來分析斗忌,首先我們看到這里的InputStream就是裝飾者模式里面的Component角色质礼,看看他的實現(xiàn):
public abstract class InputStream implements Closeable {
......
}
這個InputStream里面有一些方法:
然后接著看具體組件角色ConcreteComponent這里分別有:
ByteArrayInputStream
FileInputStream
ObjectInputStream
PipedInputStream
SequenceInputStream
StringBufferInputStream
這里的具體組件角色都有他特定的功能,比如說织阳,F(xiàn)ileInputStream代表一個文件輸入流并提供讀取文件內(nèi)容的功能眶蕉,ObjectInputStream提供了對象反序列化的功能。他們都是可以獨(dú)立使用的具體組件角色唧躲。接著我們看到抽象裝飾者角色Decorator,這里就是FilterInputStream造挽,我們來看下他的實現(xiàn):
public class FilterInputStream extends InputStream {
protected volatile InputStream in;
protected FilterInputStream(InputStream in) {
this.in = in;
}
public int read() throws IOException {
return in.read();
}
.....
}
可以看到這個抽象裝飾者角色持有了具體組件角色的引用碱璃,然后調(diào)用了具體組件角色的方法。然后我們看到繼承結(jié)構(gòu)中具體裝飾者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()方法里面會調(diào)用InputStream來讀數(shù)據(jù)到緩存里面,否則直接從緩存里面讀取谐丢。這里我們不詳細(xì)展開爽航,我們知道BufferedInputStream就是一個具體裝飾者角色,它能為一個原本沒有緩沖功能的InputStream添加上緩沖的功能乾忱。
?有了上面的的基礎(chǔ)我們就知道怎么使用I/O流了讥珍,F(xiàn)ileInputStream這個具體組件角色本來是沒有緩存功能的,但是我們在讀取文件的時候我們希望他有緩存功能窄瘟,所以我們就可以用裝飾模式來使用他:
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
}
// 關(guān)閉流
bis.close();
所以以后我們以此類推串述,我們就可以使用好我們的I/O流了。
2.Android中的裝飾者模式
這邊選擇了一張看著比較清楚的圖寞肖,我們這里不展開講纲酗,只是說說這里面的裝飾者模式的角色。
1.抽象組件角色:Context
2.具體組件角色:ContextImpl
3.抽象裝飾角色:ContextWrapper
4.具體裝飾角色:Service新蟆,Application觅赊,ContextThemeWrapper
這里的角色非常清晰明顯,具體的代碼大家可以自己去看看琼稻。
總結(jié):裝飾模式在使用中還是非常廣泛和容易的吮螺,如果你有需求正好是對一個已有的類進(jìn)行功能增強(qiáng)的話,那么你可以考慮考慮這個設(shè)計模式是不是適用帕翻,設(shè)計模式就是用的多了才有感覺鸠补,希望大家一起努力哈。