裝飾者模式動态的将責任附加到對象上。若要擴充功能,裝飾者提供了比繼承更有彈性的替代方案。
用一個咖啡的例子來展示,一杯咖啡裡面往往可以加入很多的調理(裝飾者)
1.設計兩個抽象類,一個是飲料類,還有一個是調料類
/*
* 飲料類
*/
public abstract class Beverage {
String description="unknow beverage";
public String getDescription(){
return description;
}
public abstract double cost();
}
/*
* 調料類
* 首先讓CondimentDecorator能夠取代Beverage,是以将CondimentDecorator擴充自Beverage類。
*/
public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}
2.現在有了基類,可以開始實作具體的類,先從濃縮咖啡(Espresso)開始
/*
* 濃縮咖啡類
*/
public class Espresso extends Beverage{
public Espresso(){
description="Espresso";
}
@Override
public double cost() {
// TODO Auto-generated method stub
return 1.99;
}
}
3.再來實作一些調料的類,以裝飾咖啡。 重寫2個父類方法getDescription(),cost()。 擷取到被他們裝飾的飲料的資訊。
* 摩卡是一個裝飾者,是以拓展自CondimentDecorator
*/
public class Mocha extends CondimentDecorator{
Beverage beverage; //用一個執行個體變量記錄飲料,也就是被裝飾者
public Mocha(Beverage beverage){ //通過構造器将飲料記錄下來
this.beverage=beverage;
}
@Override
public String getDescription() {
// TODO Auto-generated method stub
return beverage.getDescription()+",Mocha";
}
@Override
public double cost() {
// TODO Auto-generated method stub
return 0.2+beverage.cost(); //0.2是Mocha的價格
}
}
/*
* 另一個裝飾者:奶泡,擴充自CondimentDecorator
*/
public class Whip extends CondimentDecorator {
Beverage beverage; //用一個執行個體變量記錄飲料,也就是被裝飾者
public Whip(Beverage beverage){ //通過構造器将飲料記錄下來
this.beverage=beverage;
}
@Override
public String getDescription() {
// TODO Auto-generated method stub
return beverage.getDescription()+",Whip";
}
@Override
public double cost() {
// TODO Auto-generated method stub
return 0.3+beverage.cost(); //0.3是Whip的價格
}
}
4.接下來,來看看裝飾器是如何發揮作用的
public class Main {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Beverage beverage = new Espresso(); //先産生一杯沒有調料的Espresso
System.out.println(beverage.getDescription()+" money="+beverage.cost()); //
Beverage beverage2 = new Espresso();
beverage2=new Whip(new Mocha(beverage2)); //産生了一杯被Whip和Mocha裝飾的Espresso
System.out.println(beverage2.getDescription()+" money="+beverage2.cost());
}
}
裝飾器通過層層包裹發揮了作用: new Whip(new Mocha(beverage2)),裝飾器的構造函數強迫他必須傳入一個Beverage類型的參數。
裝飾者模式的應用:Java I/O
拿io流中的inpustream舉例,也是包裹的裝飾者設計模式,用DataInputStream、BufferedInputStream裝飾了FileInputStream。
再看InputStream的類圖,和之前設計的咖啡和調料的類圖基本類似。
FilterInputStream類似于“調料類”,而DataInputStream、BufferedInputStream都是具體實作的“調料”,可以用他們去裝飾“一個具體的飲料”------FileInputStream,而不論是FilterInputStream還是FileInputStream,他們都共同繼承于InputStream這個父類。