设计模式-装饰器

装饰器

概念

动态的将职责附加到对象上。对于某类对象的功能扩展来讲,装饰模式比继承更有弹性。

运行时期的扩展远比编译期的继承威力大。

 

UML类图

 

 UML类图说明

1)每个组件都可以单独使用,或者被装饰者包裹起来使用

2)每个装饰者(ConcreteDecoratorA, ConcreteDecoratorB)都有一个实例变量用以保存某个Component的引用

3)Decorator可以是装饰者共同实现的接口或抽象类

4)ConcreteComponent扩展自Component,是我们将要动态添加新行为的对象

5)装饰者可以扩展Component的状态

6)Component记录所装饰的事物即装饰者包裹着的Component

7)装饰者可以添加新的方法,新行为是通过在旧行为前面或后面做一些计算来添加的

 

案例

星巴兹是一家连锁咖啡店,它们的订单系统如下

 

实现说明

1)Beverage是一个抽象类,店内的所有饮料都必须继承此类

2)description这个实例变量由子类来设置,利用getDescription返回此变量内容

3)每个子类实现cost()来返回饮料的价格

 

需求变更:购买咖啡时,也可以添加各种调料,如蒸奶、豆浆等,星巴兹会根据加入的调料收取不同的费用

实现1:

增加类来满足需求的变更,比如,HouseBlendWithStemedMilk, HouseBlendWithStemedMilkandMocha等待

 

分析:

   这简直是个类爆炸,制造了一个维护噩梦,每新增一种调料,就要新增一个或多个类来满足需求,

   如果牛奶的价格上涨怎么办?

   并且者也违反了两个原则:多用组合,少用继承;封装变化

 

实现2:

利用实例变量和继承来追踪这些调料

 

 

 

实现说明

1)超类cost()用于计算所有调料的价格,子类覆盖超类的cost()方法,把指定的饮料类型的价格加进来

2)子类中的每个cost()方法需要计算饮料的价格,然后通过调用父类的cost()实现加入调料的价格

 

分析:

  

  这种方法有潜在的问题

  调料价格的改变会使我们改变现有的代码

      V

  一旦新的调料出现,我们不仅要在超类中添加新的方法,

  还要在子类中覆盖超类中的cost()方法

      V

  如果以后再开发出新的饮料(比如,冰茶),某些调料可能并不适合,

  但是冰茶仍将继承那些不适合的方法,比如hasWhip()等

      V

  万一顾客需要双倍mocha怎么办?

 

使用装饰者模式实现

 

装饰者小结

1)装饰者和被装饰者对象有相同的超类,即你可以在任何需要的被装饰对象的时候,用装饰者代替它

2)可以用一个或多个装饰者去包装一个对象

3)装饰者可以在被装饰者行为的之前或之后,加上自己的行为已达到特定的目的

4)对象可以在任何时候被装饰,即你可以在运行时动态的、不限量的用你喜欢的装饰者来装饰对象

 

Java代码实现装饰者模式

Beverage.java

package design.pattern.decorator;

public abstract class Beverage {
    String description = "Unknown beverage";
    
    public String getDescription(){
        return description;
    }
    
    public abstract double cost();
}
View Code

 

CondimentDecorator.java

package design.pattern.decorator;

public abstract class CondimentDecorator extends Beverage{
    public abstract String getDescription();
}
View Code

 

HouseBlend.java

package design.pattern.decorator;

public class HouseBlend extends Beverage {
    
    public HouseBlend() {
        description = "HouseBlend";
    }

    @Override
    public double cost() {
        return 0.89;
    }

}
View Code

 

DarkRoast.java

package design.pattern.decorator;

public class DarkRoast extends Beverage {

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

    @Override
    public double cost() {
        return 0.99;
    }

}
View Code

 

Decaf.java

package design.pattern.decorator;

public class Decaf extends Beverage {

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

    @Override
    public double cost() {
        return 1.05;
    }

}
View Code

 

Milk.java

package design.pattern.decorator;

public class Milk extends CondimentDecorator {
    Beverage beverage;
    
    public Milk(Beverage beverage) {
        this.beverage = beverage;
    }
    
    @Override
    public String getDescription() {
        return beverage.getDescription() + ", Milk";
    }

    @Override
    public double cost() {
        return 0.1 + beverage.cost();
    }

}
View Code

 

Mocha.java

package design.pattern.decorator;

public class Mocha extends CondimentDecorator {
    Beverage beverage;
    
    public Mocha(Beverage beverage) {
        this.beverage = beverage;
    }
    
    @Override
    public String getDescription() {
        return beverage.getDescription() + ", Mocha";
    }

    @Override
    public double cost() {
        return 0.2 + beverage.cost();
    }

}
View Code

 

Soy.java

package design.pattern.decorator;

public class Soy extends CondimentDecorator {
    Beverage beverage;
    
    public Soy(Beverage beverage) {
        this.beverage = beverage;
    }
    
    @Override
    public String getDescription() {
        return beverage.getDescription() + ", Soy";
    }

    @Override
    public double cost() {
        return 0.15 + beverage.cost();
    }

}
View Code

 

Whip.java

package design.pattern.decorator;

public class Whip extends CondimentDecorator {
    Beverage beverage;
    
    public Whip(Beverage beverage) {
        this.beverage = beverage;
    }
    
    @Override
    public String getDescription() {
        return beverage.getDescription() + ", Whip";
    }

    @Override
    public double cost() {
        return 0.10 + beverage.cost();
    }

}
View Code

 

DecoratorTest.java

package design.pattern.decorator;

public class DecoratorTest {
    public static void main(String[] args) {
        Beverage hb = new HouseBlend();
        hb = new Milk(hb);
        hb = new Mocha(hb);
        System.out.println(hb.getDescription()); //HouseBlend, Milk, Mocha
        System.out.println(hb.cost()); //1.19
    }
}
View Code

 

参考资料:《HeadFirst 设计模式》

转载于:https://www.cnblogs.com/marton/p/11494733.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值