设计模式系列篇

设计模式系列篇(七)——装饰器模式

2020-08-24  本文已影响0人  复旦猿

What

装饰器模式(Decorator Design Pattern),是面向对象编程领域中,一种动态地往一个类中添加新的行为的设计模式。就功能而言,装饰模式相比生成子类更为灵活,这样可以给某个对象而不是整个类添加一些功能。装饰器模式背后设计思想是“组合大于继承”。它主要的作用是给原始类添加增强功能。这也是判断是否该用装饰器模式的一个重要的依据。

Why

  1. 一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。因此,如果在不想增加很多子类的情况下扩展类,我们就可以使用装饰器模式来实现。
  2. 装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

How

现在的年轻人大多喜欢喝奶茶,奶茶有很多口味,而且每种口味又可以添加很多配料,比如布丁、红豆、珍珠等等,会有非常非常多的搭配方式,很难去枚举所有搭配组合。今天就以去买奶茶的例子来给大家讲解装饰器模式的典型实现。

// 首先,创建奶茶接口:
public interface MilkTea {
    void make();

    Integer price();
}

// 原味奶茶,价格10元
public class OriginMilkTea implements MilkTea{
    @Override
    public void make() {
        System.out.println("This is an origin milk tea.");
    }

    @Override
    public Integer price() {
        return 10;
    }
}

// 这个类主要目的是方便后面的子类在实现的时候可以只关注要增强的方法即可。
public class FilterMilkTea implements MilkTea {
    protected MilkTea milkTea;

    public FilterMilkTea(MilkTea milkTea) {
        this.milkTea = milkTea;
    }

    @Override
    public void make() {
        this.milkTea.make();
    }

    @Override
    public Integer price() {
        return this.milkTea.price();
    }
}

// 另加珍珠,2元
public class MilkTeaWithPearl extends FilterMilkTea {

    public MilkTeaWithPearl(MilkTea milkTea) {
        super(milkTea);
    }

    @Override
    public void make() {
        this.milkTea.make();
        System.out.println("Add pearl");
    }

    @Override
    public Integer price() {
        return this.milkTea.price() + 2;
    }
}

// 另加布丁,3元
public class MilkTeaWithPudding extends FilterMilkTea {

    public MilkTeaWithPudding(MilkTea milkTea) {
        super(milkTea);
    }

    @Override
    public void make() {
        this.milkTea.make();
        System.out.println("Add pudding");
    }

    @Override
    public Integer price() {
        return this.milkTea.price() + 3;
    }

}

// 另外加糖,免费,正是因为有了FilterMilkTea,price方法可以不用重写
public class MilkTeaWithSugar extends FilterMilkTea {

    public MilkTeaWithSugar(MilkTea milkTea) {
        super(milkTea);
    }

    @Override
    public void make() {
        this.milkTea.make();
        System.out.println("Add sugar");
    }
}

测试效果如下:

// 我:我要来一杯奶茶,加布丁、珍珠和糖。
// 店员:你好,总共15元。
public class TestMain {
    public static void main(String[] args) {
        MilkTea milkTea = new OriginMilkTea();
        MilkTeaWithPearl milkTeaWithPearl = new MilkTeaWithPearl(milkTea);
        MilkTeaWithPudding milkTeaWithPudding = new MilkTeaWithPudding(milkTeaWithPearl);
        MilkTeaWithSugar milkTeaWithSugar = new MilkTeaWithSugar(milkTeaWithPudding);
        milkTeaWithSugar.make();
        System.out.println(String.format("It costs you %d RMB", milkTeaWithSugar.price()));
    }
}

输出结果为:

This is an origin milk tea.
Add pearl
Add pudding
Add sugar
It costs you 15 RMB

装饰器的实现方法其实和代理模式很像,不过两者解决问题的侧重点是完全不同的。代理模式主要增加的是非功能性需求,而装饰器模式则是增加的功能性需求。

代码地址

i-learning

写在最后

如果你觉得我写的文章帮到了你,欢迎点赞、评论、分享、赞赏哦,你们的鼓励是我不断创作的动力~

上一篇 下一篇

猜你喜欢

热点阅读