设计模式2.装饰者模式

Posted jiazhongxin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式2.装饰者模式相关的知识,希望对你有一定的参考价值。

装饰者模式

装饰者模式(Decorator),不改变原本对象,动态地给一个对象添加一些额外的职责,比继承更加灵活(继承在扩展功能上是静态的),符合开闭原则(对于扩展是开放的,对于更改是封闭的)

Component:抽象的装饰主体

ConcreteComponent:具体的装饰主体

Decorator:抽象的装饰者

ConcreteDecorator:具体的装饰者

 

结构图:

技术图片

 

 

场景:

  假如现在有饮料需要加配料出售,饮料分为纯牛奶和纯净水,配料有糖、茶,如果使用子类继承的方式(饮料都加配料)实现价格计算,将需要六种方案,也就是需要写六个子类来实现。如果业务扩展,饮料种类增加,配料种类也增加,将会产生大量的子类,即“类爆炸”。

 

解决:

  采用装饰者模式将可以解决这个问题。被装饰的是饮料本身(纯牛奶、纯净水),配料的不同选择即为不同的装饰。

 

结构图:

技术图片

例:

public interface Drink {              // Component
    float cost();
    String desc();
}
public class Milk implements Drink {  // ConcreteComponent1

    @Override
    public float cost() {
        return 10.0f;
    }

    @Override
    public String desc() {
        return "纯牛奶";
    }
}
public class Water implements Drink {  // ConcreteComponent2
    @Override
    public float cost() {
        return 1.0f;
    }

    @Override
    public String desc() {
        return "纯净水";
    }
}
public abstract class DrinkDecorator implements Drink {  // Decorator

    private Drink drink;  // 要装饰的对象

    public Decorator(Drink drink) {
        this.drink = drink;
    }

    @Override
    public float cost() {
        return drink.cost();
    }

    @Override
    public String desc() {
        return drink.desc();
    }
}
public class SugarDecorator extends DrinkDecorator{
    public SugarDecorator(Drink drink) {
        super(drink);
    }

    @Override
    public float cost() {
        return super.cost() + 1.0f;
    }

    @Override
    public String desc() {
        return super.desc() + "+糖";
    }
}
public class TeaDecorator extends DrinkDecorator{
    public TeaDecorator(Drink drink) {
        super(drink);
    }

    @Override
    public float cost() {
        return super.cost() + 2.0f;
    }

    @Override
    public String desc() {
        return super.desc() + "+茶";
    }
}
public class Test {
    public static void main(String[] args) {
        System.out.println("装饰方式一:");             // 主料:纯牛奶,先加糖后加茶
        Drink milk = new Milk();
        SugarDecorator sugar = new SugarDecorator(milk); // 纯牛奶 + 糖(第一步装饰)
        TeaDecorator tea = new TeaDecorator(sugar);       // 纯牛奶 + 糖 + 茶(第二步装饰)
        System.out.println(tea.desc());
        System.out.println(tea.cost());

        System.out.println("装饰方式二:");             // 主料:纯净水,先加茶后加水
        Drink water = new Water();
        TeaDecorator tea1 = new TeaDecorator(water);   // 纯净水 + 茶(第一步装饰)
       SugarDecorator sugar1 = new SugarDecorator(tea1); // 纯净水 + 茶 + 糖(第二步装饰)
        System.out.println(sugar1.desc());
        System.out.println(sugar1.cost());
    }
}

输出:

装饰方式一:
纯牛奶+糖+13.0
装饰方式二:
纯净水+茶+4.0

说明:

根据面向接口编程的思想,Drink(角色:Component)需是接口,MilkWater(角色:ConcreteComponent)是其具体实现类,DrinkDecorator(角色:Decorator)也需是其实现类,SugarDecoratorTeaDecorator(角色:ConcreteDecorator)是DrinkDecorator的子类。

 

分析:

Drink milk = new Milk();

SugarDecorator sugar = new SugarDecorator(milk);   // 1.纯牛奶 + 糖(第一步装饰)

TeaDecorator tea = new TeaDecorator(sugar);       // 2.纯牛奶 + + 茶(第二步装饰)

 

  首先创建装饰主体:Milk类对象milk,然后利用SugarDecorator的构造器对其进行装饰,随后再将SugarDecorator装饰过的对象传入TeaDecorator的构造器对其进行再次装饰。

  看第2处代码,再次装饰时,构造器需传入Drink的实现类对象,所以已被装饰过的对象必须是Drink接口的实现类,而已被装饰过的对象是DrinkDecorator的子类,所以DrinkDecoratorDecorator)需实现Drink接口(Component)。

 

 

  如果,饮料只有一种(纯牛奶),则不需要Drink接口(Component),直接将DrinkDecoratorDecorator)继承MilkConcreteComponent)即可。结构图如下:

技术图片

 

 

 

  而且Decorator也可以有多个,完成不同场景下的装饰工作。

 

以上是关于设计模式2.装饰者模式的主要内容,如果未能解决你的问题,请参考以下文章

装饰者模式

java-装饰者模式

设计模式05----装饰者模式

装饰者设计模式

设计模式---装饰者模式

设计模式 - 装饰者模式