设计模式——装饰者模式

装饰者模式是什么?

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

装饰者模式解决什么问题?

现有奶茶类,description 用于描述奶茶中加的配料,cost用于返回价格:

public class MilkTea {

    String description = "MilkTea";

    public String getDescription() {
        return description;
    }

    public int cost() {
        return 7;
    }
}

如果要给奶茶加配料(如布丁、珍珠等):

实现方式1

创建布丁奶茶继承奶茶,加上布丁的价格(珍珠同理):

class MilkTeaWithPudding extends MilkTea {

    public MilkTeaWithPudding() {
        description += "+Pudding";
    }

    @Override
    public int cost() {
        return super.cost() + 1;
    }
}
  • problem1:当配料越来越多时,其继承类也会越来越多(MilkTeaWithXXX)
  • problem2:不可同时加配料(MilkTeaWithPuddingAndPearl)
  • problem3:不可双倍加配料(MilkTeaWithDoublePudding)
  • problem4:当推出新奶茶时(bananaMilkTea)又得维护其庞大的继承类

实现方式2

修改MilkTea,内部维护各种配料,有则在描述和价格中加上:

public class MilkTea {

    String description = "MilkTea";

    private boolean pudding = false;
    private boolean pearl = false;


    public void setPudding(boolean pudding) {
        this.pudding = pudding;
    }

    public void setPearl(boolean pearl) {
        this.pearl = pearl;
    }

    public String getDescription() {
        if (pudding) {
            description += "+pudding";
        }
        if (pearl) {
            description += "+pearl";
        }
        return description;
    }

    public int cost() {
        int cost = 7;
        if (pudding) {
            cost += 1;
        }
        if (pearl) {
            cost += 1;
        }
        return cost;
    }
}
  • problem1:内部通过大量循环判断
  • problem2:如果要加上新配料或配料价格改变时需要修改源代码
  • problem3:当推出新奶茶时(bananaMilkTea),上述重复代码又得写一遍

装饰者模式实现

被装饰者

保持原有类不变:

public class MilkTea {

    String description = "MilkTea";

    public String getDescription() {
        return description;
    }

    public int cost() {
        return 7;
    }
}

装饰者

装饰者继承被装饰者,内部维护被装饰者,抽出装饰者的公用方法:

abstract class CondimentDecorator extends MilkTea {
    MilkTea milkTea;

    public abstract String getDescription();
}

装饰者实例

新建Pudding和Pearl装饰者,重写方法加上自己的装饰(价格和描述),当推出新配料时,只要让其继承CondimentDecorator即可:

class Pudding extends CondimentDecorator {

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

    @Override
    public String getDescription() {
        return milkTea.description + "+Pudding";
    }

    @Override
    public int cost() {
        return milkTea.cost() + 1;
    }
}

class Pearl extends CondimentDecorator {

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

    @Override
    public String getDescription() {
        return milkTea.description + "+Pearl";
    }

    @Override
    public int cost() {
        return milkTea.cost() + 1;
    }
}

装饰过程

因为Pudding和Pearl继承CondimentDecorator,而CondimentDecorator继承MilkTea,故都可转为MilkTea类型进行操作:

 MilkTea milkTea=new MilkTea();
 milkTea=new Pudding(milkTea);
 milkTea=new Pudding(milkTea);
 milkTea=new Pearl(milkTea);
 System.out.println(milkTea.getDescription()+" "+milkTea.cost());

新增被装饰者

当推出新奶茶时(BananaMilkTea ),只要让其继承MilkTea即可:

class BananaMilkTea extends MilkTea {

    public BananaMilkTea() {
        description = "BananaMilkTea";
    }

    public int cost() {
        return 10;
    }
}

新装饰过程

利用多态,装饰过程同理:

 MilkTea milkTea=new BananaMilkTea ();
 milkTea=new Pudding(milkTea);
 milkTea=new Pudding(milkTea);
 milkTea=new Pearl(milkTea);
 System.out.println(milkTea.getDescription()+" "+milkTea.cost());

Tips:

  • Java中的io流采用的就是装饰者模式,通过层层装饰完成对文件的读写操作,如new BufferedInputStream(new FileInputStream(path))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值