1、一個實例
在一家咖啡店有很多種咖啡,但都基于一種基本飲料開發(fā)出來的,每一種咖啡也可以加入很多不同的配料。
飲料有:HouseBlend(首選咖啡),Espresso(濃縮咖啡),DarkRoast(焦炒咖啡),Decaf(脫因咖啡)
調(diào)料有:Milk(牛奶)、摩卡(mocha)、豆?jié){(Soy)、奶泡(Whip)
這時候用戶下單要打印票據(jù)顯示配方和價格,該如何做呢?
//被裝飾者父類
public abstract class Beverage {
String description = "Unknown Beverage";
public String getDescription() {
return description;
}
public abstract double cost();
}
//創(chuàng)建幾個實現(xiàn)類
public class HouseBlend extends Beverage {
public HouseBlend() {
description = "House Blend Coffee";
}
@Override
public double cost() {
return 0.89;
}
}
public class DarkRoast extends Beverage {
public Espresso() {
description = "DarkRoast";
}
@Override
public double cost() {
return 1.99;
}
}
- 裝飾類(寫法1)
//創(chuàng)建裝飾者
public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}
// 創(chuàng)建具體的裝飾者
public class Mocha extends CondimentDecorator {
Beverage beverage;
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
@Override
public double cost() {
return 0.2 + beverage.cost();
}
@Override
public String getDescription() {
return beverage.getDescription() + ",Mocha";
}
}
public class Milk extends CondimentDecorator {
Beverage beverage;
public Milk(Beverage beverage) {
this.beverage = beverage;
}
@Override
public double cost() {
return 0.1 + beverage.cost();
}
@Override
public String getDescription() {
return beverage.getDescription() + ",Milk";
}
}
- 裝飾類(寫法2)
//創(chuàng)建裝飾者父類
public abstract class CondimentDecorator extends Beverage {
protected Beverage beverage;
public CondimentDecorator(Beverage beverage) {
this.beverage = beverage;
}
public abstract String getDescription();
}
// 創(chuàng)建具體的裝飾者
public class Mocha extends CondimentDecorator {
public Milk(Beverage beverage) {
super(beverage);
}
@Override
public double cost() {
return 0.2 + beverage.cost();
}
@Override
public String getDescription() {
return beverage.getDescription() + ",Mocha";
}
}
public class Milk extends CondimentDecorator {
public Milk(Beverage beverage) {
super(beverage);
}
@Override
public double cost() {
return 0.1 + beverage.cost();
}
@Override
public String getDescription() {
return beverage.getDescription() + ",Milk";
}
}
- main方法
public class StartbuzzCoffee {
public static void main(String[] args) {
Beverage beverage = new DarkRoast();
//一杯不加調(diào)料的咖啡
System.out.println(beverage.getDescription() + ",價格:" + beverage.cost());
//用摩卡和牛奶裝飾下
Beverage beverage2 = new DarkRoast();
beverage2=new Mocha(beverage2);
beverage2=new Milk(beverage2);
System.out.println(beverage2.getDescription() + ",價格:" + beverage2.cost());
Beverage beverage3=new Milk(new Mocha(new DarkRoast()));
System.out.println(beverage3.getDescription() + ",價格:" + beverage3.cost());
}
}
輸出
DarkRoast,價格:1.99
DarkRoast,Mocha,Milk,價格:2.29
DarkRoast,Mocha,Milk,價格:2.29

1652267688(1).png
2、什么是裝飾者模式
2.1、定義裝飾者模式
動態(tài)地將責任附加到對象上。若要擴展功能,裝飾者提供了比繼承更具有彈性的替代方案。
2.2 特征
- 裝飾者和被裝飾者有相同的超類型。
- 可以用一個或多個裝飾者包裝一個對象。
- 對象可以在任何時候被裝飾
怎么看出來是使用了裝飾模式呢?
當你看到 new BufferedInputStream(new FileInputStream("test.txt"));這種寫法就差不多了。
- 裝飾者和被裝飾者有相同的超類型
- 裝飾者持有超類型的引用,這樣裝飾者就可以不斷的修飾 被裝飾者
3、 java中的實例

1652342401(1).png
上圖是java中的inputStream。我們可以看出來FilterInputStream就是我們的裝飾者。
//被裝飾者父類
public abstract class InputStream{
public abstract int read() ;
}
//實現(xiàn)類(具體被裝飾者)
public class FileInputStream extends InputStream{
public FileInputStream(File file){}
public int read() throws IOException{}
}
public class StringBufferInputStream extends InputStream {
public synchronized int read(){}
public StringBufferInputStream(String s) { }
}
public class ByteArrayInputStream extends InputStream {
public ByteArrayInputStream(byte buf[]) {}
public synchronized int read(){}
}
- 裝飾類
//創(chuàng)建裝飾者
public class FilterInputStream extends InputStream {
protected volatile InputStream in;
protected FilterInputStream(InputStream in) {
this.in = in;
}
public int read() throws IOException {
return in.read();
}
}
// 創(chuàng)建具體的裝飾者
public class BufferedInputStream extends FilterInputStream {
public synchronized int read(){}
}
- 具體使用
public static void main(String[] args){
InputStream in = new BufferedInputStream(new FileInputStream("test.txt"));
}