设计模式——装饰者模式

装饰者模式

1. 定义
装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案

2. 构成

  • 装饰者和被装饰者有相同的超类
  • 可以用一个或多个装饰者包装一个对象
  • 在任何需要原始对象(被包装)的场合,可以用装饰过的对象代替它
  • 装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,已达到特定的目的
  • 对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰对象
    装饰者模式的类图
    Component:抽象组件,每个组件都可以单独使用,或被装饰者包起来使用
    ConcreteComponent:具体组件,扩展自Component,使我们要动态地加上新行为的对象
    Decorator:抽象装饰者,每个装饰者都“有一个”(包装一个)组件,也就是说,装饰者有一个实例变量以保存某个Component的引用
    ConcreteDecorator wrappedObj:记录所装饰的事物(装饰者包着的Component)

3. 示例:饮料
以饮料为主题,在运行时以调料来“装饰”饮料
饮料示例的类图

  • Beverage相当于是抽象的Component类
  • HouseBlend、DarkRoast、Espresso、Decaf:4个具体组件,每个代表一种咖啡类型
  • Milk、Mocha、Soy、Whip:调料装饰者
public abstract class Beverage {
    String description = "Unkown Beverage";
    public String getDescription() {
        return description;
    }
    public abstract double cost();
}

public abstract class CondimentDecorator extends  Beverage{
    public abstract String getDescription();
}

public class DarkRoast extends Beverage {
    public DarkRoast() {
        description = "dark roast coffee";
    }
    @Override
    public double cost() {
        return .1;
    }
}

public class Decaf extends Beverage {
    public Decaf() {
        description = "decaf coffee";
    }
    @Override
    public double cost() {
        return 1.20;
    }
}

public class Espresso extends Beverage{
    public Espresso() {
        description = "Espresso";
    }
    @Override
    public double cost() {
        return 1.99;
    }
}

public class HouseBlend extends Beverage {
    public HouseBlend() {
        description = "house blend coffee";
    }
    @Override
    public double cost() {
        return .89;
    }
}

public class Milk extends CondimentDecorator {
    Beverage beverage;
    public Milk(Beverage beverage) {
        this.beverage = beverage;
    }
    @Override
    public String getDescription() {
        return beverage.getDescription() + ", Milk";
    }
    @Override
    public double cost() {
        return .10 + beverage.cost();
    }
}

public class Mocha extends CondimentDecorator {
    Beverage beverage;
    public Mocha(Beverage beverage) {
        this.beverage = beverage;
    }
    @Override
    public String getDescription() {
        return beverage.getDescription() + ", Mocha";
    }
    @Override
    public double cost() {
        return .20 + beverage.cost();
    }
}

public class Soy extends CondimentDecorator {
    Beverage beverage;
    public Soy(Beverage beverage) {
        this.beverage = beverage;
    }
    @Override
    public String getDescription() {
        return beverage.getDescription() + ", Soy";
    }
    @Override
    public double cost() {
        return .15 + beverage.cost();
    }
}

public class Whip extends CondimentDecorator {
    Beverage beverage;
    public Whip(Beverage beverage) {
        this.beverage = beverage;
    }
    @Override
    public String getDescription() {
        return beverage.getDescription() + ", Whip";
    }
    @Override
    public double cost() {
        return .10 + beverage.cost();
    }
}

4. 具体实例:Java I/O
装饰java.io类
编写自己的输入装饰者,把输入流内的所有大写字符转成小写

public class LowerCaseInputStream extends FilterInputStream {
    public LowerCaseInputStream(InputStream 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)Character.toLowerCase((char)b[i]);
        }
        return result;
    }
}

public class InputTest {
    public static void main(String[] args) {
        int c;
        try {
            InputStream in = new LowerCaseInputStream(
                    new BufferedInputStream(
                            new FileInputStream("test.txt")
                    )
            );
            while((c = in.read()) >= 0) {
                System.out.print((char)c);
            }
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

5. 装饰者模式的缺点

  • 利用装饰者模式常常造成设计中含有大量的小类
  • 在插入装饰者时,必须要小心谨慎
  • 采用装饰者实例化组件是,将增加代码的复杂度(贡茶模式、生成器模式)

6. 装饰者模式的优点

  • 适合用来建立富有弹性的设计
  • 符合开闭原则
  • 一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值