1. 為何需要裝飾者模式(why)
??在我們的工作中,往往會這樣的需求,就是動態地將責任附加到對象上,來達到拓展對象功能的目的。例如,對于做餅這件事來說,往往在做好一個餅之后,會有加糖,加鹽,加雞蛋這樣類似的客戶需求,不同的需求價格當然不同。我們通常的做法創建基類(Cake),然后讓其他的子類繼承它,試想下,如果如果有很多的類,豈不是會造成類爆炸,新出一款新的餅,就會構造一個類,計算不同的價格。而裝飾者模式應用在這上面就非常的好。你想加糖,那我在外面包裝一層,把額外的價格加上去。以后如果有幾種配料的疊加,不用創造新的類,由原來的子類通過裝飾者模式包裝起來就行。
2. 如何實現裝飾者模式how)
- 定義一個餅的基類,其他的餅的種類繼承它。
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;
}
}
- 可以分別加糖或者加鹽,因此先來個裝飾器接口
public abstract class CakeDecorator extends Cake {
}
- ??分別實現通過裝飾器加糖和加鹽
/**
* 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; //餅的錢+糖的錢
}
}
- 測試一下通過裝飾器既加糖又加鹽
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。
- 我們常見到的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