定义
动态地将责任附加到对象上,若要扩展功能,装饰者比继承更有弹性
角色
装饰者将被装饰聚合到自己内部,双方都继承共同的抽象方法,往往是被装饰者只需要完成自己的本质工作,装饰者在集成的被装饰者功能基础之上添加自己的逻辑。下面以饮品店咖啡和咖啡配料组合例子作为案例说明
饮品店案例
- UML
public abstract class Drink {
private String des;
private float price = 0f;
// setter getter 省略
public abstract float cost();
}
public class Coffee extends Drink {
// 被装饰者只需要完成自己本身的价格
@Override
public float cost() {
return super.getPrice();
}
// 被装饰者只需要完成自己本身的价格
@Override
public String getDes() {
return super.getDes() + ":" + super.getPrice();
}
}
public class Decorator extends Drink {
//装饰者将被装饰者聚合进来作为自己行为的基础
private Drink obj;
public Decorator(Drink obj) {
this.obj = obj;
}
//obj.getDes()在被装饰者基础之上进行装饰自己行为super.getDes() + ":" + super.getPrice()
@Override
public String getDes() {
return super.getDes() + ":" + super.getPrice() + " && " + obj.getDes();
}
@Override
public float cost() {
return super.getPrice() + obj.cost();
}
}
// 被装饰者
// 以拿铁咖啡为例 作为被装饰者定义自己行为即可
public class Latte extends Coffee {
public Latte() {
super.setDes(" Latte ");
super.setPrice(6.0f);
}
}
// ------------作为装饰者的具体实现-----------------
public class Milk extends Decorator {
public Milk(Drink obj) {
super(obj);
super.setDes("牛奶");
super.setPrice(2.0f);
}
}
public class Chocolate extends Decorator {
public Chocolate(Drink obj) {
super(obj);
super.setDes(" 巧克力 ");
super.setPrice(2.0f);
}
}
// ----------------客户端----------------
public static void main(String[] args) {
Drink order = new Latte();
System.out.println("order明细:" + order.getDes() + "\n" + "order总价:" + order.cost());
// 此时被装饰者是Latte
order = new Chocolate(order);
// 被装饰者是加了chocolate的latte
order = new Milk(order);
System.out.println("order明细:" + order.getDes() + "\n" + "order总价:" + order.cost());
}
java中的装饰者模式InputStream
- 比如我们想扩展一个把字符转换成小写的inputStream,我们只需要扩展一个继承FilterInputStream的具体装饰者(这里命令为LowerCaseInputStream)代码如下:
public class LowerCaseInputStream extends FilterInputStream {
protected LowerCaseInputStream(InputStream in) {
super(in);
}
@Override
public int read() throws IOException {
// super.read()方法执行了in.read();即完成了被装饰者的功能
int c = super.read();
// 在被装饰者功能的基础之上增加其他行为
return (c == -1 ? c : Character.toLowerCase((char) c));
}
}
//----客户端调用---
public class InputStreamMain {
public static void main(String[] args) {
int c;
try {
InputStream in = new LowerCaseInputStream(new BufferedInputStream(new FileInputStream("./test")));
while ((c = in.read()) >= 0) {
System.out.print((char) c);
}
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 输入:I know the Decorator Pattern therefore I RULE!
// 输出:i know the decorator pattern therefore i rule!
对比适配器、外观、装饰者
- 适配器:将一个对象包装起来以改变其接口
- 外观:将一群对象“包装”起来以简化其接口
- 装饰者:将一个对象包装起来以增加新的行为和责任
参考
《Head First设计模式》