zoukankan      html  css  js  c++  java
  • 设计模式-装饰器

    装饰器

    概念

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

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

    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 设计模式》

  • 相关阅读:
    RAID技术
    敏捷开发
    如何写出高质量的代码?现在知道还不晚
    Java大型互联网架构技术经验
    Chrome精品插件
    2018 java BAT最新面试宝典
    Java成神之路(2018版)
    三分钟读懂摘要算法
    我的Mac应用清单
    事务隔离级别
  • 原文地址:https://www.cnblogs.com/marton/p/11494733.html
Copyright © 2011-2022 走看看