HeadFirst設計模式3-裝飾者模式

1. 為何需要裝飾者模式(why)

??在我們的工作中,往往會這樣的需求,就是動態地將責任附加到對象上,來達到拓展對象功能的目的。例如,對于做餅這件事來說,往往在做好一個餅之后,會有加糖,加鹽,加雞蛋這樣類似的客戶需求,不同的需求價格當然不同。我們通常的做法創建基類(Cake),然后讓其他的子類繼承它,試想下,如果如果有很多的類,豈不是會造成類爆炸,新出一款新的餅,就會構造一個類,計算不同的價格。而裝飾者模式應用在這上面就非常的好。你想加糖,那我在外面包裝一層,把額外的價格加上去。以后如果有幾種配料的疊加,不用創造新的類,由原來的子類通過裝飾者模式包裝起來就行。

2. 如何實現裝飾者模式how)
  1. 定義一個餅的基類,其他的餅的種類繼承它。
public abstract class Cake {
    public String message="CAKE";
    public float cost;
    public String getMessage(){
        return message;
    }
    //每個實現類自己實現
    public abstract float getCost();

}

油餅,和糖餅分別實現餅

public class BatterCake extends Cake {
    public BatterCake() {
        message="batterCake";
    }

    @Override
    public float getCost() {
        this.cost=1.2f;
        return cost;
    }
}

public class OilCake extends Cake{ //餅的實現類,油餅

    public OilCake() {
        message="oilCake";
    }
    @Override
    public float getCost() {
        this.cost=1.5f;
        return cost;
    }
}
  1. 可以分別加糖或者加鹽,因此先來個裝飾器接口
public abstract class CakeDecorator extends Cake {
  
}
  1. ??分別實現通過裝飾器加糖和加鹽

/**
 * Created by maskwang on 2017/10/15 0015.
 * 餅加鹽
 */
public class SaltDecorator extends CakeDecorator{
    Cake cake;

    public SaltDecorator(Cake cake) {
        this.cake = cake;
    }

    @Override
    public String getMessage() {
        return cake.getMessage()+"  with salt   ";
    }

    @Override
    public float getCost() {
        return cake.getCost()+0.3f;
    }
}

public class SugerDecorator extends CakeDecorator {
    Cake cake;

    public SugerDecorator(Cake cake) {
        this.cake = cake;
    }

    @Override
    public String getMessage() {
        return cake.getMessage()+"  with suger  ";
    }

    @Override
    public float getCost() {
        return cake.getCost()+0.2f;   //餅的錢+糖的錢
    }
}
  1. 測試一下通過裝飾器既加糖又加鹽
public class Test {
    public static void main(String[] args) {
        Cake cake = new OilCake();
        cake = new SaltDecorator(cake);
        cake=new SugerDecorator(cake);
        System.out.println(cake.getMessage());
        System.out.println(cake.getCost());
    }
}

結果如下:

image.png

??這里解釋一下,最后的2.0如何出來,構造出OilCake,cost就是1.5,
cake = new SaltDecorator(cake),那么cost就是1.8。cake=new SugerDecorator(cake),那么就是2.0。

  1. 我們常見到的IO包下,就運用到裝飾者模式,例如BufferedInputStream,DataInputStream等。也可以實現一個裝飾器,把字母轉化成小寫。如下:
package com.designpattern.decoratorpattern;

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * Created by maskwang on 2017/10/15 0015.
 */
public class UperCaseInputStream extends FilterInputStream {

    public UperCaseInputStream(InputStream in) {
        super(in);
    }

    @Override
    public int read() throws IOException {
        int c=super.read();
        return (c==-1?c:Character.toUpperCase((char)c));
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        int result=super.read(b,off,len);
        for(int i=off;i<off+result;i++){
            b[i]=(byte)Character.toUpperCase((char)b[i]);
        }
        return result;
    }

}

測試IO裝飾類

 public static void main(String[] args) throws IOException {
//        Cake cake = new OilCake();
//        cake = new SaltDecorator(cake);
//        cake=new SugerDecorator(cake);
//        System.out.println(cake.getMessage());
//        System.out.println(cake.getCost());
        int c;
        try {
            InputStream in=new UperCaseInputStream(new BufferedInputStream(new FileInputStream("E:\\test.txt")));
            while ((c=in.read())>0)
                System.out.println((char)(c));
        }catch (IOException e){
            e.printStackTrace();
        }
    }

![Uploading image_647020.png . . .]

image.png
3. 總結(conclution)
  • ??從上述我們可以看出來 ,裝飾者模式用于已經存在的類添加額外的功能,但是它也有缺點,就是它要在設計中加入大量的小類,會造成額外的空間占用。其核心思想還是如下:

??多用組合,少用繼承。針對接口編程,不針對實現編程。對拓展開放,對修改關閉。
github地址:github.com/maskwang520

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

推薦閱讀更多精彩內容