设计模式之装饰者模式

定义:

动态地给一个对象添加一些额外的职责,就增加功能来说,装饰者模式比生成子类更为灵活.其别名也可以称为包装器(Wrapper),与适配器模式的别名相同,但他们适用于不同的场合.根据翻译的不同,装饰者模式也有人称为"油漆工模式",它是一种对象结构型模式

装饰者模式和继承的共同点:

通过继承的方式可以是子类具有父类的属性和方法.子类继承父类后,因为一些业务需求可以通过重写的方式类加强父类的方法的一些功能,也可以重新定义某些属性,即覆盖父类的原有属性和方法,使其获得与父类不同的功能.而装饰者模式的最基本的功能就是对传入的一个对象进行功能的加强与优化.

其实就是避免继承子类过多导致类爆炸

下面用一张图分析继承和装饰者模式的区别

在这里插入图片描述

就拿大家日常生活中的例子来说吧,相信大家都有喝过豆浆。那么假设现在一杯纯豆浆(Soya)卖1元钱,你可以选择往里边加糖0.5元(Suger),加蜂蜜0.5元(Honey),加牛奶1元(Milk),加黑豆1元(BlackBean),加鸡蛋(1元)等等。如果要计算出任意组合的豆浆的价钱该怎么做呢?

  • 我们先有继承的方式解决一下
    假设有蜂蜜,糖,牛奶三种配料,我们看看有几种组合(就是要创建多少子类)
    1.豆浆+蜂蜜,2.豆浆加糖,3.豆浆+牛奶,4.豆浆+蜂蜜+糖,5.豆浆+蜂蜜+牛奶,6豆浆+糖+牛奶,7.豆浆+蜂蜜+糖+牛奶

上面三种配料就需要7种组合(也就是7个子类),如果再加上几种配料呢(例如:黑豆,香蕉,苹果…),可能这些组合要无数个子类,(而且你还要把这些子类都提前写出来,方便在客户端直接new 调用)瞬间子类爆炸

为了解决这个问题,我们的装饰者模式就登场了

模式构造

  • Component:抽象构建
  • ConcreteComponent:具体构件
  • Decorator:抽象装饰类
  • ConcreteDecorator:具体装饰类

例子

  • 商品(豆浆)信息接口,作为装饰者构造函数的参数(被装饰者父类)
public interface Drink {
     float money();//商品价格
     String message();//商品信息
}
  • 具体的被装饰者(豆浆,主要就是给豆浆添加配料,给豆浆包装一下(给豆浆装饰一下,他就是被装饰者))
public class Soya implements Drink {
    @Override
    public float money() {
        return 10f;
    }
    @Override
    public String message() {
        return "纯豆浆";
    }
}
  • 抽象装饰者类,继承此接口并通过构造方法获取被装饰对象公共接口
public abstract class Decorator  implements Drink{
    private Drink drink;
    public Decorator(Drink drink){
        this.drink = drink;
    }
    @Override
    public float money() {
        return drink.money();
    }

    @Override
    public String message() {
        return drink.message();
    }
}
  • 具体装饰者,加糖
public class Suger extends Decorator{
    public Suger(Drink drink) {
        super(drink);
    }

    @Override
    public float money() {
        return super.money()+1.5f;
    }

    @Override
    public String message() {
        return super.message()+"+糖";
    }
}
  • 具体的装饰者对象:加牛奶
public class Milk extends Decorator{
    public Milk(Drink drink) {
        super(drink);
    }

    @Override
    public float money() {
        return super.money()+1.5f;
    }

    @Override
    public String message() {
        return super.message()+"+牛奶";
    }
}
  • 具体的装饰你者:加蜂蜜
public class Honey extends Decorator {
    public Honey(Drink drink) {
        super(drink);
    }

    @Override
    public float money() {
        return super.money()+1.5f;
    }

    @Override
    public String message() {
        return super.message()+"+蜂蜜";
    }
}
  • 具体的装饰者:加黑豆
public class BlackBean extends Decorator {
    public BlackBean(Drink drink) {
        super(drink);
    }

    @Override
    public float money() {
        return super.money()+2.5f;
    }

    @Override
    public String message() {
        return super.message()+"+黑豆";
    }
}
  • 客户端调用
//定义一杯纯豆浆
        Soya soya = new Soya();
        System.out.println(soya.money()+soya.message());
        //豆浆+奶
        Milk milk = new Milk(new Soya());
        System.out.println(milk.money()+"******"+milk.message());
        //豆浆+奶+黑豆
        Milk milk1 = new Milk(new BlackBean(new Soya()));
        System.out.println(milk1.money()+"----"+milk1.message());
  • 打印输出结果
System.out: 10.0纯豆浆
System.out: 11.5******纯豆浆+牛奶
System.out: 14.0----纯豆浆+黑豆+牛奶

总结

有几种配料我们就创建几种装饰类,如上面只有糖,蜂蜜,牛奶,黑豆,我们就创建4个装饰类,而不用管他们有多少种组合,所有的组合都可以用这4个装饰类拼接组成,这就比继承里面要创建无数的子类方便多了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值