装饰者模式

目录

https://blog.csdn.net/dongganen/article/details/79688794


定义装饰者模式


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

案例分析


楼下新开了一家牛肉面店,有牛肉面15块,羊肉面20块,海鲜面25块,另外加荷包蛋3块,面结5块,豆腐4块,香菜1块。

硬编码,使用继承

我们对所有的面加佐料进行排列组合,类爆炸

//牛肉面
class BeefNoodles extends Noodles{

}

//牛肉面加鸡蛋
class BeefAndEggNoodles extends Noodles{

}

//牛肉面加鸡蛋加豆腐
class BeefAndEggAndTofuNoodles extends Noodles{

}

//羊肉面
class SheepNoodles extends Noodles{

}

//羊肉面加鸡蛋
class SheepAndEggNoodles extends Noodles{

}

//羊肉面加鸡蛋加豆腐
class SheepAndEggAndTofuNoodles extends Noodles{

}

//海鲜面
class SeaNoodles extends Noodles{

}

//海鲜面加鸡蛋
class SeaAndEggNoodles extends Noodles{

}

//海鲜面加鸡蛋加豆腐
class SeaAndEggAndTofuNoodles extends Noodles{

}

使用实例变量和组合

分析

我们让Noodles持有各种辅料的引用

代码
//装饰者模式
public class Decker {

    public static void main(String[] args) {
        Noodles noodles = new BeefNoodles();
        noodles.setEgg(true);
        noodles.setTofu(true);
        System.out.println( noodles.cost() + " " + noodles.getDesc());
    }
}

//面条
abstract class Noodles{
    String desc = "";
    Boolean egg = false;
    Boolean mianjie= false;
    Boolean tofu = false;
    Boolean coriander = false;

    abstract double cost();

    protected double otherCost(){
        double cost = 0.00;
        if(getEgg()){
            desc += " egg";
            cost += 3.00;
        }
        if(getMianjie()){
            desc += " mianjie";
            cost += 5.00;
        }
        if(getTofu()){
            desc += " tofu";
            cost += 4.00;
        }
        if(getCoriander()){
            desc += " coriander";
            cost += 1.00;
        }
        return cost;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public Boolean getEgg() {
        return egg;
    }

    public void setEgg(Boolean egg) {
        this.egg = egg;
    }

    public Boolean getMianjie() {
        return mianjie;
    }

    public void setMianjie(Boolean mianjie) {
        this.mianjie = mianjie;
    }

    public Boolean getTofu() {
        return tofu;
    }

    public void setTofu(Boolean tofu) {
        this.tofu = tofu;
    }

    public Boolean getCoriander() {
        return coriander;
    }

    public void setCoriander(Boolean coriander) {
        this.coriander = coriander;
    }
}

//牛肉面
class BeefNoodles extends Noodles{

    public BeefNoodles(){
        desc += "BeefNoodles ";
    }

    @Override
    double cost() {
        return 15.00 + super.otherCost();
    }
}

//羊肉面
class SheepNoodles extends Noodles{

    public SheepNoodles(){
        desc += "SheepNoodles ";
    }

    @Override
    double cost() {
        return 20.00 + super.otherCost();
    }
}

//海鲜面
class SeaNoodles extends Noodles{

    public SeaNoodles(){
        desc += "SeaNoodles ";
    }

    @Override
    double cost() {
        return 25.00 + super.otherCost();
    }
}
分析

这比使用继承解决已经上了一个台阶。
1. 调整价钱会修改otherCost里的逻辑,容易出错
2. 一旦出现新的辅料,会修改原来封装的逻辑,容易出错

认识装饰者模式


我们以面条为主体,然后在运行时以调料来”装饰”面条。

比如说我现在点了一碗牛肉面,用荷包蛋去装饰他,用面结去装饰他,调用方法,并依赖委托把价钱的描述加上去。

UML

image

  1. 装饰者和被装饰者有相同的类型。
  2. 你可以用一个或多个装饰者包装一个对象。
  3. 既然装饰者和被装饰者具有相同的超类型,所以在任何需要原始对象的地方都可以用装饰过的对象代替他。
  4. 装饰者可以在所委托被装饰者前后,加上自己的行为,以达到目的。
  5. 对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰对象。
代码
//装饰者模式
public class Decker {

    public static void main(String[] args) {
        //老板来一碗牛肉面
        Noodles noodles = new BeefNoodles();
        //价格鸡蛋
        noodles = new Egg(noodles);
        //加个面结
        noodles = new Mianjie(noodles);
        System.out.println(noodles.getDesc() + " " + noodles.cost());
    }
}

//面条
abstract class Noodles{
    String desc = "";

    abstract double cost();

    public String getDesc() {
        return desc;
    }
}

//面条装饰者
abstract class NoodlesDecorator extends Noodles{

    public abstract String getDesc();
}

//牛肉面
class BeefNoodles extends Noodles{

    public BeefNoodles(){
        desc += "BeefNoodles ";
    }

    @Override
    double cost() {
        return 15.00;
    }
}

//羊肉面
class SheepNoodles extends Noodles{

    public SheepNoodles(){
        desc += "SheepNoodles ";
    }

    @Override
    double cost() {
        return 20.00;
    }
}

//海鲜面
class SeaNoodles extends Noodles{

    public SeaNoodles(){
        desc += "SeaNoodles ";
    }

    @Override
    double cost() {
        return 25.00;
    }
}

//鸡蛋
class Egg extends NoodlesDecorator{

    Noodles noodles;

    public Egg(Noodles noodles){
        this.noodles = noodles;
    }

    @Override
    double cost() {
        return 3.00 + noodles.cost();
    }

    @Override
    public String getDesc() {
        return noodles.getDesc() + " 加鸡蛋";
    }
}

//面结
class Mianjie extends NoodlesDecorator{

    Noodles noodles;

    public Mianjie(Noodles noodles){
        this.noodles = noodles;
    }

    @Override
    double cost() {
        return 5.00 + noodles.cost();
    }

    @Override
    public String getDesc() {
        return noodles.getDesc() + " 加面结";
    }
}

//豆腐
class Tofu extends NoodlesDecorator{

    Noodles noodles;

    public Tofu(Noodles noodles){
        this.noodles = noodles;
    }

    @Override
    double cost() {
        return 4.00 + noodles.cost();
    }

    @Override
    public String getDesc() {
        return noodles.getDesc() + " 加豆腐";
    }
}

我们熟悉的Java IO使用的就是装饰者模式,在我一开始接触的时候我被众多的API搞混了,这也是装饰者模式的一个弊端,随着不同的装饰功能,类还是比较多的。但是我们在了解装饰者模式之后回过头可以回更加清晰。

参考《Head First设计模式》


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值