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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

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

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

一、基本介紹

動態地將責任附加到對象上。若要擴展功能,裝飾者提供了比繼承更有彈性的替代方案。

二、裝飾器模式的結構

1、Component,抽象構件

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

2、ConcreteComponent,具體構件,或者基礎構件

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

3、Decorator,裝飾角色

 一般是一個抽象類,繼承自或實現Component,在它的屬性里面有一個變量指向Component抽象構件,我覺得這是裝飾器最關鍵的地方。

4、ConcreteDecorator,具體裝飾角色

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

三、裝飾器模式優缺點

1、優點

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

(2)裝飾器模式是繼承關系的一個替代方案。我們看裝飾類Decorator,不管裝飾多少層,返回的對象還是Component(因為Decorator本身就是繼承自Component的),實現的還是is-a的關系。

2、缺點

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

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

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

四、裝飾器模式的使用場景

1、當你想要給一個類增加功能,然而,卻并不想修改原來類的代碼時,可以考慮裝飾器模式如果你想要動態的給一個類增加功能,并且這個功能你還希望可以動態的撤銷,就好像直接拿掉了一層裝飾物;

2、比如java里面的基本數據類型int、boolean、char....都有它們對應的裝飾類Integer、Boolean、Character....

3、在Java IO中,具體構建角色是節點流、裝飾角色是過濾流;

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

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

這就是 裝飾者模式,DataoutputStream是裝飾者子類,FileoutputStream是實現接口的子類。

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

五、裝飾器模式實現手抓餅

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

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

1、Component,抽象構件:街邊小吃

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;}//計算費用的抽象方法//子類來實現public abstract float cost(); }

2、ConcreteComponent,具體構件,或者基礎構件

(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、老板,來個手抓餅,加2個蛋、加1根烤腸

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

5、好嘞,您拿好

六、裝飾器模式在Java I/O系統中的實現

?前面總結了這么多,再從大神們的作品中找一個實際應用例子吧,畢竟那是經歷實戰檢驗的,肯定是有道理的。嗯,在平時的留意中我發現Java I/O系統的設計中用到了這一設計模式,因為Java I/O類庫需要多種不同功能的組合。這里我就以InputStream為例簡單說明一下,同樣我們還是來看一下其類圖:

InputStream作為抽象構件,其下面大約有如下幾種具體基礎構件,從不同的數據源產生輸入:

  • ByteArrayInputStream,從字節數組產生輸入;
  • FileInputStream,從文件產生輸入;
  • StringBufferInputStream,從String對象產生輸入;
  • PipedInputStream,從管道產生輸入;
  • SequenceInputStream,可將其他流收集合并到一個流內;

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

FilterInputStream內部封裝了基礎構件:

protected volatile InputStream in;

而BufferedInputStream在調用其read()讀取數據時會委托基礎構件來進行更底層的操作,而它自己所起的裝飾作用就是緩沖,在源碼中可以很清楚的看到這一切:

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;// 看這行就行了,委托基礎構件來進行更底層的操作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()獲取基礎構件從而委托其進行更底層的操作(在這里是讀取單個字節)就可以說明本文所要說的一切了。

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

?

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。