裝飾者模式

裝飾者模式java

  裝飾者模式是23種設計模式之一,是指在不改變原來的類和使用繼承的方式,動態的擴展這個類的功能。裝飾者容許向一個現有的對象添加特定的功能卻不改變它的結構。經過一個類來包裝原有的類來提供額外的功能。設計模式

 

特色

 

(1) 裝飾對象和真實對象有相同的接口。這樣客戶端對象就能以和真實對象相同的方式和裝飾對象交互。

 

(2) 裝飾對象包含一個真實對象的引用(reference)

 

(3) 裝飾對象接受全部來自客戶端的請求。它把這些請求轉發給真實的對象。

 

(4) 裝飾對象能夠在轉發這些請求之前或之後增長一些附加功能。這樣就確保了在運行時,不用修改給定對象的結構就能夠在外部增長附加的功能。在面向對象的設計中,一般是經過繼承來實現對給定類的功能擴展。

 

裝飾者模式的結構:ide

 

 

Component:抽象組件,被裝飾的原始對象,能夠是抽象類或者接口學習

ConcreatCompoent:實現或者繼承了抽象組件,被裝飾的具體的實現this

Decorator:抽象的裝飾者,實現或者繼承了Component抽象組件,持有抽象組件的引用spa

ConcreatDecotarorA、ConcreatDecotarorB:具體的裝飾者,實現或者繼承了抽象裝飾者。設計

 實現3d

  舉個簡單的例子,假設有一個科沃斯機器人,它的基本功能是掃地,如今要求這個機器人能夠邊掃地邊唱歌,還能夠邊掃地邊跳舞。code

那麼,就能夠將機器定義爲一個抽象的類,裏面有一個抽象的方法,sweep();對象

/**
 * 抽象組件
 */
public abstract class Robot {
    /**
     * 打掃的方法
     */
    public abstract void sweep();
}

被裝飾的具體對象:

/**
 * 抽象組件的具體實現類,即被裝飾者對象
 */
public class ConcreatRobot extends Robot {
    @Override
    public void sweep() {
        System.out.println("打掃臥室");
    }
}

抽象裝飾者:

/**
 * 抽象的裝飾者類
 */
public class DecoratorRobot extends Robot {

    private Robot robot;

    public DecoratorRobot(Robot robot) {
        this.robot = robot;
    }

    @Override
    public void sweep() {
        robot.sweep();
    }
}

具體的裝飾者A:

/**
 * 裝飾者A
 */
public class ConcreatDecoratorA extends DecoratorRobot {

    public ConcreatDecoratorA(Robot robot) {
        super(robot);
    }

    /**
     * 一遍掃地一邊唱歌
     */
    @Override
    public void sweep() {
        super.sweep();
        this.sign();
    }

    /**
     * 唱歌
     */
    public void sign(){
        System.out.println("唱一首單身情歌");
    }
}

具體的裝飾者B:

/**
 * 裝飾者B
 */
public class ConcreatDecoratorB extends RobotDecorator {

    public ConcreatDecoratorB(Robot robot) {
        super(robot);

    }

    /**
     * 一遍掃地一邊跳舞
     */
    @Override
    public void sweep() {
        super.sweep();
        dance();
    }

    /**
     * 唱歌
     */
    public void dance(){
        System.out.println("跳一支探戈");
    }
}

客戶端調用:

public class DecoratorTest  {
    public static void main(String[] args) {

        Robot robot = new ConcreatRobot();
        RobotDecorator signRobot = new ConcreatDecoratorA(robot);
        signRobot.sweep();
        RobotDecorator danceRobot = new ConcreatDecoratorB(robot);
        danceRobot.sweep();

    }
}

控制檯輸出:

打掃臥室
唱一首單身情歌
打掃臥室
跳一支探戈

  從例子中能夠看出,裝飾的模式是一種組合的概念,所謂裝飾,就是要去擴展被裝飾者從而擴展功能,而咱們客戶端在調用的時候,能夠選擇合適的裝飾類來達到咱們想要的結果。好比我只想讓機器人掃地,那麼我只須要調用具體的抽象實現類,我想讓機器人又掃地又跳舞,那麼就使用包裝類。

 

  裝飾者模式是爲已有功能動態的添加更多功能的一種方式。那麼,在何時使用呢,當系統須要新的功能的時候,向舊代碼中添加新的代碼顯然增長了原有代碼的複雜度,而且違反了開閉原則。這個時候,裝飾者提供了一個很是好的機會,咱們能夠經過包裝這個主類,把每一個要包裝的功能單獨的寫成一個包裝類,從而擴展該類的功能。客戶端能夠根據須要,調用特定功能的包裝類。這樣作的好處是把類中的裝飾功能或者和核心功能分開,簡化原有的類。

裝飾者模式在java IO中的應用

  裝飾者模式在JDK中的典型應用莫過於IO體系了。Java中的IO分爲兩種,字節流和字符流,其中每一種分別能夠分爲輸入流和輸出流,咱們來看下IO體系的結構圖。

 

  咱們以InputStream爲例,InputStream是抽象的父類,FilterInputtream和ByteArrayInputStream繼承了InputStream,這些類繼承了InputStream的基本的字節讀取功能,FilterInputtream還持有了InputStream的引用,它的全部的方法,都是調用了這個引用的同名方法,也就是說,他把全部的調用都委託給了InputStream。而且FilterInputtream還有一些子類,好比BufferdInputStream,DataInputStream等。BufferedInputStream提供了緩衝輸入流,當咱們經過read()讀取輸入流的數據時,BufferedInputStream會將該輸入流的數據分批的填入到緩衝區中。每當緩衝區中的數據被讀完以後,輸入流會再次填充數據緩衝區;如此反覆,直到咱們讀完輸入流數據位置。因而可知,BufferedInputStream爲咱們提供了一個從緩衝區讀取數據的功能,就像是科沃斯機器人,通過包裝後爲咱們提供了唱歌的功能同樣。咱們來看下這幾個類的類圖。

                                                                                

  正如圖中所示,他們的結構徹底知足裝飾者模式的結構圖。同理,像DataInputStream也是一個包裝類,他提供了與機器無關方式從底層輸入流中讀取的功能。

咱們來看下以BufferdInputStream實現數據讀取的例子。

public class DecoratorTest {
    public static void main(String[] args) {

        InputStream in = null;
        BufferedInputStream bi = null;
        try {
            in = new FileInputStream("E:\\decorator.txt");
            //in 是一個文件輸入流,經過BufferedInputStream給它添加從緩衝區讀取數據的功能。
            //BufferedInputStream就是一個包裝類
            bi = new BufferedInputStream(in);
            int count = 0;
            byte[] buffer = new byte[1024];
            while ((count = bi.read(buffer)) != -1) {
                System.out.println(new String(buffer, 0, count));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (bi != null) {
                    bi.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

    }
}

   我本身以前學習IO流的時候,看到這麼多種類的流也是很難理解,當我以設計模式角度去解讀這些流時,會更加容易理解。裝飾者模式的實現對於使用者是透明的,咱們必須瞭解這個裝飾者是什麼功能,才能恰當的使用這個類。

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息