日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > windows >内容正文

windows

【源码分析设计模式 5】Java I/O系统中的装饰器模式

發(fā)布時(shí)間:2023/12/29 windows 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【源码分析设计模式 5】Java I/O系统中的装饰器模式 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、基本介紹

動(dòng)態(tài)地將責(zé)任附加到對(duì)象上。若要擴(kuò)展功能,裝飾者提供了比繼承更有彈性的替代方案。

二、裝飾器模式的結(jié)構(gòu)

1、Component,抽象構(gòu)件

Component是一個(gè)接口或者抽象類,是定義我們最核心的對(duì)象,也可以說是最原始的對(duì)象,比如街邊小吃;

2、ConcreteComponent,具體構(gòu)件,或者基礎(chǔ)構(gòu)件

ConcreteComponent是最核心、最原始、最基本的接口或抽象類Component的實(shí)現(xiàn),可以單獨(dú)用,也可將其進(jìn)行裝飾,比如街邊小吃最有名的手抓餅;

3、Decorator,裝飾角色

 一般是一個(gè)抽象類,繼承自或?qū)崿F(xiàn)Component,在它的屬性里面有一個(gè)變量指向Component抽象構(gòu)件,我覺得這是裝飾器最關(guān)鍵的地方。

4、ConcreteDecorator,具體裝飾角色

ConcreteDecoratorA和ConcreteDecoratorB是兩個(gè)具體的裝飾類,它們可以把基礎(chǔ)構(gòu)件裝飾成新的東西,比如把一個(gè)普通的手抓餅裝飾成加蛋、加腸兒、金針菇的手抓餅。

三、裝飾器模式優(yōu)缺點(diǎn)

1、優(yōu)點(diǎn)

(1)裝飾類和被裝飾類可以獨(dú)立發(fā)展,而不會(huì)相互耦合。換句話說,Component類無需知道Decorator類,Decorator類是從外部來擴(kuò)展Component類的功能,而Decorator也不用知道具體的構(gòu)件。

(2)裝飾器模式是繼承關(guān)系的一個(gè)替代方案。我們看裝飾類Decorator,不管裝飾多少層,返回的對(duì)象還是Component(因?yàn)镈ecorator本身就是繼承自Component的),實(shí)現(xiàn)的還是is-a的關(guān)系。

2、缺點(diǎn)

(1)裝飾器模式雖然減少了類的爆炸,但是在使用的時(shí)候,你就可能需要更多的對(duì)象來表示繼承關(guān)系中的一個(gè)對(duì)象

(2)裝飾器模式雖然從數(shù)量級(jí)上減少了類的數(shù)量,但是為了要裝飾,仍舊會(huì)增加很多的小類這些具體的裝飾類的邏輯將不會(huì)非常的清晰,不夠直觀,容易令人迷惑。

(3)多層的裝飾是比較復(fù)雜的。為什么會(huì)復(fù)雜?你想想看,就像剝洋蔥一樣,你剝到最后才發(fā)現(xiàn)是最里層的裝飾出現(xiàn)了問題,可以想象一下工作量。這點(diǎn)從我使用Java I/O的類庫(kù)就深有感受,我只需要單一結(jié)果的流,結(jié)果卻往往需要?jiǎng)?chuàng)建多個(gè)對(duì)象,一層套一層,對(duì)于初學(xué)者來說容易讓人迷惑。

四、裝飾器模式的使用場(chǎng)景

1、當(dāng)你想要給一個(gè)類增加功能,然而,卻并不想修改原來類的代碼時(shí),可以考慮裝飾器模式如果你想要?jiǎng)討B(tài)的給一個(gè)類增加功能,并且這個(gè)功能你還希望可以動(dòng)態(tài)的撤銷,就好像直接拿掉了一層裝飾物;

2、比如java里面的基本數(shù)據(jù)類型int、boolean、char....都有它們對(duì)應(yīng)的裝飾類Integer、Boolean、Character....

3、在Java IO中,具體構(gòu)建角色是節(jié)點(diǎn)流、裝飾角色是過濾流;

FilterInputStream和FilterOutputStream是裝飾角色,而其他派生自它們的類則是具體裝飾角色。

DataoutputStream out=new DataoutputStream(new FileoutputStream());

這就是 裝飾者模式,DataoutputStream是裝飾者子類,FileoutputStream是實(shí)現(xiàn)接口的子類。

這里不會(huì)調(diào)用到裝飾者類--FilteroutputStream,只是作為繼承的另一種方案,對(duì)客戶端來說是透明的,是為了功能的擴(kuò)張。

五、裝飾器模式實(shí)現(xiàn)手抓餅

老板,來個(gè)手抓餅,加個(gè)蛋、加根烤腸多少錢?

這個(gè)就是裝飾器模式,用蛋和烤腸去裝飾手抓餅,讓手抓餅更加美味。

1、Component,抽象構(gòu)件:街邊小吃

package designMode.advance.decorator;public abstract class Snack {public String des; // 描述private float price = 0.0f;public String getDes() {return des;}public void setDes(String des) {this.des = des;}public float getPrice() {return price;}public void setPrice(float price) {this.price = price;}//計(jì)算費(fèi)用的抽象方法//子類來實(shí)現(xiàn)public abstract float cost(); }

2、ConcreteComponent,具體構(gòu)件,或者基礎(chǔ)構(gòu)件

(1)手抓餅

package designMode.advance.decorator;public class HandGrabCake extends Snack {public HandGrabCake() {setPrice(5.0f);setDes(" 手抓餅 "+cost());}@Overridepublic float cost() {return super.getPrice();} }

(2)烤冷面

package designMode.advance.decorator;public class GrilledColdNoodles extends Snack {public GrilledColdNoodles() {setPrice(4.0f);setDes(" 烤冷面 "+cost());}@Overridepublic float cost() {return super.getPrice();} }

Decorator,裝飾角色

package designMode.advance.decorator;public class Decorator extends Snack {private Snack obj;public Decorator(Snack obj) { //組合this.obj = obj;}@Overridepublic float cost() {return super.getPrice() + obj.cost();}@Overridepublic String getDes() {// obj.getDes() 輸出被裝飾者的信息return des + " " + getPrice() + " && " + obj.getDes();} }

3、具體裝飾角色

(1)雞蛋

package designMode.advance.decorator;public class Egg extends Decorator {public Egg(Snack obj) {super(obj);setDes(" 雞蛋 ");setPrice(1.0f);} }

(2)烤腸

package designMode.advance.decorator;public class Sausage extends Decorator {public Sausage(Snack obj) {super(obj);setDes(" 烤腸 ");setPrice(2.0f);} }

(3)金針菇

package designMode.advance.decorator;public class NeedleMushroom extends Decorator{public NeedleMushroom(Snack obj) {super(obj);setDes(" 金針菇 ");setPrice(2.5f);} }

4、老板,來個(gè)手抓餅,加2個(gè)蛋、加1根烤腸

package designMode.advance.decorator;public class HandGrabCakeBar {public static void main(String[] args) {// 裝飾者模式下的訂單:2個(gè)蛋+一根烤腸的手抓餅// 1. 點(diǎn)一份手抓餅Snack order = new HandGrabCake();System.out.println("小白手抓餅費(fèi)用=" + order.cost());System.out.println("描述=" + order.getDes());// 2. order 加入一個(gè)雞蛋order = new Egg(order);System.out.println("手抓餅 加入1個(gè)雞蛋 費(fèi)用 =" + order.cost());System.out.println("手抓餅 加入1個(gè)雞蛋 描述 = " + order.getDes());// 3. order 加入一個(gè)雞蛋order = new Egg(order);System.out.println("手抓餅 加入1個(gè)雞蛋 加入2個(gè)雞蛋 費(fèi)用 =" + order.cost());System.out.println("手抓餅 加入1個(gè)雞蛋 加入2個(gè)雞蛋 描述 = " + order.getDes());// 3. order 加入一根烤腸order = new Sausage(order);System.out.println("手抓餅 加入1個(gè)雞蛋 加入2個(gè)雞蛋 加1根烤腸 費(fèi)用 =" + order.cost());System.out.println("手抓餅 加入1個(gè)雞蛋 加入2個(gè)雞蛋 加1根烤腸 描述 = " + order.getDes());System.out.println("===========================");Snack order2 = new GrilledColdNoodles();System.out.println("考冷面 費(fèi)用 =" + order2.cost());System.out.println("考冷面 描述 = " + order2.getDes());// 1. order2 加入一袋金針菇order2 = new NeedleMushroom(order2);System.out.println("考冷面 加入一袋金針菇 費(fèi)用 =" + order2.cost());System.out.println("考冷面 加入一袋金針菇 描述 = " + order2.getDes());} }

5、好嘞,您拿好

六、裝飾器模式在Java I/O系統(tǒng)中的實(shí)現(xiàn)

?前面總結(jié)了這么多,再?gòu)拇笊駛兊淖髌分姓乙粋€(gè)實(shí)際應(yīng)用例子吧,畢竟那是經(jīng)歷實(shí)戰(zhàn)檢驗(yàn)的,肯定是有道理的。嗯,在平時(shí)的留意中我發(fā)現(xiàn)Java I/O系統(tǒng)的設(shè)計(jì)中用到了這一設(shè)計(jì)模式,因?yàn)镴ava I/O類庫(kù)需要多種不同功能的組合。這里我就以InputStream為例簡(jiǎn)單說明一下,同樣我們還是來看一下其類圖:

InputStream作為抽象構(gòu)件,其下面大約有如下幾種具體基礎(chǔ)構(gòu)件,從不同的數(shù)據(jù)源產(chǎn)生輸入:

  • ByteArrayInputStream,從字節(jié)數(shù)組產(chǎn)生輸入;
  • FileInputStream,從文件產(chǎn)生輸入;
  • StringBufferInputStream,從String對(duì)象產(chǎn)生輸入;
  • PipedInputStream,從管道產(chǎn)生輸入;
  • SequenceInputStream,可將其他流收集合并到一個(gè)流內(nèi);

?FilterInputStream作為裝飾器在JDK中是一個(gè)普通類,其下面有多個(gè)具體裝飾器比如BufferedInputStream、DataInputStream等。我們以BufferedInputStream為例,使用它就是避免每次讀取時(shí)都進(jìn)行實(shí)際的寫操作,起著緩沖作用。我們可以在這里稍微深入一下,站在源碼的角度來管中窺豹。

FilterInputStream內(nèi)部封裝了基礎(chǔ)構(gòu)件:

protected volatile InputStream in;

而BufferedInputStream在調(diào)用其read()讀取數(shù)據(jù)時(shí)會(huì)委托基礎(chǔ)構(gòu)件來進(jìn)行更底層的操作,而它自己所起的裝飾作用就是緩沖,在源碼中可以很清楚的看到這一切:

public synchronized int read() throws IOException {if (pos >= count) {fill();if (pos >= count)return -1;}return getBufIfOpen()[pos++] & 0xff; }private void fill() throws IOException {byte[] buffer = getBufIfOpen();if (markpos < 0)pos = 0; /* no mark: throw away the buffer */else if (pos >= buffer.length) /* no room left in buffer */if (markpos > 0) { /* can throw away early part of the buffer */int sz = pos - markpos;System.arraycopy(buffer, markpos, buffer, 0, sz);pos = sz;markpos = 0;} else if (buffer.length >= marklimit) {markpos = -1; /* buffer got too big, invalidate mark */pos = 0; /* drop buffer contents */} else if (buffer.length >= MAX_BUFFER_SIZE) {throw new OutOfMemoryError("Required array size too large");} else { /* grow buffer */int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?pos * 2 : MAX_BUFFER_SIZE;if (nsz > marklimit)nsz = marklimit;byte nbuf[] = new byte[nsz];System.arraycopy(buffer, 0, nbuf, 0, pos);if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {throw new IOException("Stream closed");}buffer = nbuf;}count = pos;// 看這行就行了,委托基礎(chǔ)構(gòu)件來進(jìn)行更底層的操作int n = getInIfOpen().read(buffer, pos, buffer.length - pos);if (n > 0)count = n + pos; }private InputStream getInIfOpen() throws IOException {InputStream input = in;if (input == null)throw new IOException("Stream closed");return input; }

這部分的代碼很多,這里我們沒有必要考慮這段代碼的具體邏輯,只需要看到在BufferedInputStream的read方法中通過getInIfOpen()獲取基礎(chǔ)構(gòu)件從而委托其進(jìn)行更底層的操作(在這里是讀取單個(gè)字節(jié))就可以說明本文所要說的一切了。

至于I/O類庫(kù)中的其他設(shè)計(jì)諸如OutputStream、Writer、Reader,是一致的,這里就不再贅述了。

?

總結(jié)

以上是生活随笔為你收集整理的【源码分析设计模式 5】Java I/O系统中的装饰器模式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。