设计模式学习笔记(三)——装饰者模式

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

分析: 装饰者模式本质上是用对象包装对象,所以装饰者和被装饰者必须有相同的超类,可以用一个或多个装饰者包装一个对象,在需要被装饰者的场景可以直接使用装饰过的对象,重点是拓展功能,可以在被装饰者的行为前后加入自己的行为,达到特定的目的。

使用场景:

  1. 需要扩展一个类的功能,或给一个类添加附加职责。
  2. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
  3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。
  4. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

UML类图

在这里插入图片描述

Component:组件接口,每个组件可以单独使用或被装饰者包起来使用。
ConcreteComponent:抽象被装饰的对象接口
ConcreteDecorator:装饰者抽象接口,持有一个Component类型的引用
ConcreteDecoretor:具体装饰者对象,有一个变量记录被装饰者,可以扩展Component的状体,可以加上新行为达到功能扩展的目的

示例

有一家咖啡连锁店准备更新订单系统,购买不同种类咖啡时,要求可以在其中加入各种调料,根据不同调料要收取不同的费用
分析: 如果我们使用继承的方法来做的话,会碰到例如调料价钱改变使得需要修改源代码,或对应新加入的饮料,对应的调料不适用,使用装饰者模式的话,我们先创建一个咖啡对象,运行时以调料对象来装饰它,并调用各自的收费方法将价钱加上去。

设计原则: 这边涉及到一个新的实际原则,开放-关闭原则:类应该对扩展开放,对修改关闭。我们的目标是允许类容易扩展,在不改变现有代码的情况下,即可搭配新的行为。

代码:

Component组件

public abstract class Baverage {

    public String description = "饮品";

    public String getDescription(){
        return description;
    }

    public abstract double cost();
}

抽象装饰者接口

public abstract class CondimentDecorator extends Baverage {

    public abstract String getDescription();

}

具体被装饰者

public class Espresso extends Baverage {

    public Espresso(){
        description = "Espresso";
    }

    @Override
    public double cost() {
        return 1.99;
    }
}

public class HouseBlend extends Baverage {

    public HouseBlend(){
        description = "HouseBlend";
    }

    @Override
    public double cost() {
        return .89;
    }
}

具体装饰者

public class Mocha extends CondimentDecorator {

    Baverage baverage;

    public Mocha(Baverage baverage) {
        this.baverage = baverage;
    }

    @Override
    public String getDescription() {
        return baverage.getDescription()+",Mocha";
    }

    @Override
    public double cost() {
        return .20+baverage.cost();
    }
}

public class Soy extends CondimentDecorator {

    Baverage baverage;

    public Soy(Baverage baverage) {
        this.baverage = baverage;
    }

    @Override
    public String getDescription() {
        return baverage.getDescription()+",soy";
    }

    @Override
    public double cost() {
        return .20+baverage.cost();
    }
}

public class Whip extends CondimentDecorator {

    Baverage baverage;

    public Whip(Baverage baverage) {
        this.baverage = baverage;
    }

    @Override
    public String getDescription() {
        return baverage.getDescription()+",whip";
    }

    @Override
    public double cost() {
        return .30+baverage.cost();
    }
}

测试

public class Order {

    public static void main(String[] args) {

        Baverage baverage = new Espresso();
        System.out.println(baverage.getDescription()+'$'+baverage.cost());

        Baverage baverage1 = new HouseBlend();
        baverage1 = new Mocha(baverage1);
        baverage1 = new Mocha(baverage1);
        baverage1 = new Whip(baverage1);
        System.out.println(baverage1.getDescription()+'$'+baverage1.cost());

    }
}

结果
在这里插入图片描述

JAVA中的装饰者模式——Java I/O

抽象组件(以inputStream为例): InputStream
被装饰者: InputStream的除FilterInputStream的子类,像FileInputStream
抽象装饰者: FilterInputStream
具体装饰者: FilterInputStream的子类,像BufferdInputStream,DataInputStream

类图
在这里插入图片描述

和我们的示例相比,java.io其实没有太多区别。outputStream和Writer/Reader也是同样的。

缺陷: 装饰者模式的一个缺点是在设计中,经常有大量的小类,可能造成开发过程中的困扰。

编写一个自己的Java I/O装饰者
分析: 从上文可知,只要扩展FilterInputStream类,重写read()方法即可

public class LowCaseInputStream extends FilterInputStream {

    public LowCaseInputStream(InputStream inputStream) {
        super(inputStream);
    }

    @Override
    public int read() throws IOException {
        int read = super.read();
        return (read == -1?read:Character.toLowerCase(read));
    }

    public int read(byte[] b,int offSet,int len)throws IOException{
        int read = super.read(b, offSet, len);
        for (int i = offSet;i<offSet+read;i++){
            b[i] = (byte)Character.toLowerCase((char) b[i]);
        }
        return read;
    }
}

public class IoTest {
    public static void main(String[] args) {
        int c;
        try {
            InputStream in = new LowCaseInputStream(
                    new BufferedInputStream(
                            new FileInputStream("D://text.txt")));
            while ((c = in.read())>=0){
                System.out.print((char) c);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

结果:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值