动态地给一个对象添加一些额为的职责。对此,装饰者模式比直接继承父类增加功能更加灵活。
秋天到了,女朋友非要喝秋天的第一杯奶茶,到了“蜜雪冰城”奶茶店后,给女朋友点了一杯珍珠芒果奶茶,加了珍珠、芒果等配料,给自己点了一杯加冰柠檬水,加了冰块、柠檬片等配料,这时候就可以使用装饰器模式。
抽象构件(Component)角色:
奶茶
public interface IMilktea {
void addDosing();
}
具体构件(ConcreteComponent)角色:
public class PearlMilktea implements IMilktea{
@Override
public void addDosing() {
System.out.println("开始制作:珍珠奶茶");
}
}
public class LemonMilktea implements IMilktea{
@Override
public void addDosing() {
System.out.println("开始制作:柠檬水");
}
}
装饰者(Decorator)角色:
配料
public abstract class Dosing implements IMilktea{
IMilktea iMilktea;
public Dosing(IMilktea iMilktea){
this.iMilktea = iMilktea;
}
@Override
public void addDosing() {
this.iMilktea.addDosing();
}
}
具体装饰(ConcreteDecorator)角色:
加珍珠
public class Pearl extends Dosing {
public Pearl(IMilktea iMilktea) {
super(iMilktea);
}
@Override
public void addDosing() {
super.addDosing();
System.out.println("制作中:加珍珠");
}
}
加芒果
public class Mango extends Dosing {
public Mango(IMilktea iMilktea) {
super(iMilktea);
}
@Override
public void addDosing() {
super.addDosing();
System.out.println("制作中:加芒果");
}
}
加宁檬
public class Lemon extends Dosing {
public Lemon(IMilktea iMilktea) {
super(iMilktea);
}
@Override
public void addDosing() {
super.addDosing();
System.out.println("制作中:加柠檬");
}
}
加冰
public class Ice extends Dosing {
public Ice(IMilktea iMilktea) {
super(iMilktea);
}
@Override
public void addDosing() {
super.addDosing();
System.out.println("制作中:加冰");
}
}
客户端
public class Client {
public static void main(String[] args) {
System.out.println("服务员:你好,需要点什么呀?");
System.out.println("我: 一杯加芒果、加珍珠的珍珠奶茶,一杯加柠檬、加冰的柠檬水");
System.out.println("服务员:好的。");
System.out.println("---------------------------");
PearlMilktea pearlMilktea = new PearlMilktea();
Pearl pearl = new Pearl(pearlMilktea);
Mango mango = new Mango(pearl);
Ice ice = new Ice(mango);
ice.addDosing();
System.out.println("-------第一杯制作完成----------");
LemonMilktea lemonMilktea = new LemonMilktea();
Lemon lemon = new Lemon(lemonMilktea);
Ice ice1 = new Ice(lemon);
ice1.addDosing();
System.out.println("-------第二杯制作完成----------");
System.out.println("我:珍珠奶茶怎么加冰了?");
System.out.println("服务员:对不起,珍珠奶茶做错了,重新给您做。");
System.out.println("---------------------------");
mango.addDosing();
System.out.println("-------不加冰的珍珠奶茶制作完成----------");
System.out.println("我:好的,谢谢!");
}
}
输出结果
服务员:你好,需要点什么呀?
我: 一杯加芒果、加珍珠的珍珠奶茶,一杯加柠檬、加冰的柠檬水
服务员:好的。
---------------------------
开始制作:珍珠奶茶
制作中:加珍珠
制作中:加芒果
制作中:加冰
-------第一杯制作完成----------
开始制作:柠檬水
制作中:加柠檬
制作中:加冰
-------第二杯制作完成----------
我:珍珠奶茶怎么加冰了?
服务员:对不起,珍珠奶茶做错了,重新给您做。
---------------------------
开始制作:珍珠奶茶
制作中:加珍珠
制作中:加芒果
-------不加冰的珍珠奶茶制作完成----------
我:好的,谢谢!
大家在用java.io的类的时候是不是经常混淆,其中的类实在是太多了。反正我没了解装饰者模式之前,用起这些类来是真的痛苦。直到我知道这些类其中很多都是装饰者,用起来才得心应手。
从Java I/O中能看出装饰者模式的缺点:装饰者模式的使用常常造成设计中有大量的小类,在一定程度上造成使用此API程序员的困扰。但是,现在你已经了解了装饰者模式的工作原理,以后使用别人大量装饰的API时,就可以很容易的辨别出他们的装饰者时如何组织的。
编写一个装饰者,把输入流内的所有大写字符转成小写。例如:“Talk Is Cheap! Show Me Your Code!” 转成 “talk is cheap! show me your code!”:
public class LowerCaseInputStream extends FilterInputStream{
public LowerCaseInputStream(InputSteam in){
super(in);
}
public int read() throws IOException{
int c = super.read();
return (c == -1) ? c : Character.toLowerCase((char)c));
}
public int read(byte[] b, int offset, int len) throws IOException{
int result = super.read(b, offset, len);
for(int i == offset; i < offset + result; i++){
b[i] = (byte)Charator.toLowerCase((char)b[i]);
}
return result;
}
}