设计模式——装饰者模式

1. 情景

面馆开张了,主营2种面:酸菜面、牛肉面;外加2种配料:鸡蛋、豆皮

装饰者模式来设计这一订单系统:

满足要求:可以返回点的名称、计算总价格

2. 设计

大体思路:

这里要说的是鸡蛋、豆皮是装饰者,为了让他可以任意的加配料,返回仍是面条类。

类设计图:

3. 实现

面条抽象类

public abstract class Noodle {
    String description = "Unknown Name";

    public String getDescription() {
        return description;
    }

    public abstract double cost();
}

装饰者抽象类

public abstract class CondimentDecorator extends Noodle {
    @Override
    public abstract String getDescription();
}

面条具体类–酸菜面

public class SuancaiNoodle extends Noodle{
    SuancaiNoodle() {
        description = "Suancai Noodle";
    }
    @Override
    public double cost() {
        return 10;
    }
}

面条具体类–牛肉面

public abstract class Noodle {
    String description = "Unknown Name";

    public String getDescription() {
        return description;
    }

    public abstract double cost();
}

配料具体类–鸡蛋

public class Egg extends CondimentDecorator{
    private Noodle noodle;
    Egg(Noodle noodle) {
        this.noodle = noodle;
    }
    @Override
    public String getDescription() {
        return noodle.getDescription() + " + Egg";
    }

    @Override
    public double cost() {
        return noodle.cost() + 2;
    }
}

配料具体类–豆皮

public class SkinOfTofu extends CondimentDecorator{
    private Noodle noodle;

    SkinOfTofu(Noodle noodle) {
        this.noodle = noodle;
    }

    @Override
    public String getDescription() {
        return noodle.getDescription() + " + SkinOfTofu";
    }

    @Override
    public double cost() {
        return noodle.cost() + 1;
    }
}

4. 测试

public class NoodleTest {
    public static void main(String[] args) {
        Noodle suancai = new SuancaiNoodle();
        Noodle addEgg = new Egg(suancai);
        Noodle addEggSkin = new SkinOfTofu(addEgg);
        System.out.println(addEggSkin.getDescription());
        System.out.println(addEggSkin.cost());

        System.out.println("-----");

        Noodle beef = new BeefNoodle();
        Noodle addEgg2 = new Egg(beef);
        System.out.println(addEgg2.getDescription());
        System.out.println(addEgg2.cost());
    }
}

结果

Suancai Noodle + Egg + SkinOfTofu
13.0
-----
Beef Noodle + Egg
14.0

5.java  I/O

其中InputStream是抽象组件

其下一列如FileInputStream是抽象装饰者,BufferedInputStream是具体装饰者

用法举例

public class ReadFileTest {
    public static void main(String[] args) {
        try {
            FileInputStream fis = new FileInputStream("jihite/test.json");
            BufferedInputStream bis = new BufferedInputStream(fis);
            BufferedInputStream bis2 = new BufferedInputStream(bis);
            byte[] b = new byte[bis2.available()];
            bis2.read(b);

            System.out.println(new String(b));
            bis2.close();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
}

6. 归纳

定义:

在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

设计原则:

  • 多组合、少继承
  • 对扩展开放、对修改关闭

优点:

  • Decorator模式与继承关系的都是要扩展对象,但是Decorator可以提供比继承更多的灵活性
  • 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合
缺点:
  • 比继承更加灵活也同时意味着更加多的复杂性
  • 导致设计中出现许多小类,如果过度使用,会使程序变得很复杂