zoukankan      html  css  js  c++  java
  • 装饰者模式

    1.定义

    动态的将责任附加到对象上,提供了比继承更有弹性的替代方案.

    关键点: 装饰者和被装饰者必须有共同的超类.

    2.代码实现

     比如有一杯咖啡,咖啡有各种价钱,我想给咖啡增添各种调料,比如摩卡,豆浆,奶泡等等,相应的咖啡的价钱也会增加.

    定义共同的超类Beverage类,Beverage类可以有子类,和一个抽象装饰类,抽象装饰类包含Beverage类,所以,抽象装饰类可以传入Beverage的子类来装饰咖啡等饮料

    定义Beverage类

    public abstract class Beverage {
        String description = "Unknow Beverage";
        
    
        public String getDescription() {
            return description;
        }
        
        public abstract double cost();
        
    }

    Beverage抽象类有两个实现类Espresso(浓缩咖啡) 和 HouseBlend(混合咖啡)

    public class Espresso extends Beverage {
        
        public Espresso() {
            description = "Espresso";
        }
    
        @Override
        public double cost() {
            return 1.99;
        }
        
    }
    public class HouseBlend extends Beverage {
    
        public HouseBlend() {
            description = "HouseBlend";
        }
    
        @Override
        public double cost() {
            return 0.89;
        }
    
    }

    以上两个类就是要被装饰的类

    定义装饰者抽象类,这个抽象类的子类就是装饰类,可以装饰之前的浓缩咖啡和混合咖啡

    public abstract class CondimentDecorator extends Beverage{
        /**
         * 这里重写getDescription方法只是为了获取咖啡以及添加的调料的名称
         */
        public abstract String getDescription();
    }

    实现装饰者类,定义三种调料Moca(摩卡), Soy(豆浆),Whip(奶泡)

    public class Moca extends CondimentDecorator{
        Beverage beverage;
        
        public Moca(Beverage beverage) {
            this.beverage = beverage;
        }
    
        @Override
        public String getDescription() {
            return beverage.getDescription()+", Mocha";
        }
    
        @Override
        public double cost() {
            return 0.20 + beverage.cost();
        }
        
        
    }
    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.10 + beverage.cost();
        }
    
    }
    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();
        }
    
    }

    在这里我们可以看到,因为这三个类中都定义了Beverage变量,所以可以用构造函数接受传递过来的Beverage类,并且在cost和getDescription方法中调用Beverage类的方法来添加额外的数据,传递CondimentBeverage类也没有问题,因为CondimentBeverage类也是继承自Beverage类.   这就是为什么装饰者需要装饰类和被装饰类需要共同超类的原因.

    接下来就可以测试了,定义测试类

    public class StarbuzzCoffee {
        public static void main(String[] args) {
            Beverage beverage = new Espresso();
            System.out.println(beverage.getDescription() + "/" + beverage.cost());//Espresso/1.99
            
            Beverage beverage2 = new HouseBlend();//价格为0.89
            beverage2 = new Soy(beverage2);//加上0.1 的豆浆
            beverage2 = new Whip(beverage2);//在加上0.1 的奶排
            beverage2 = new Moca(beverage2);//在加上0.2 的摩卡
            System.out.println(beverage2.getDescription() 
                    + "/" + beverage2.cost());//HouseBlend, Soy, Whip, Mocha/1.29
        }
    }

    3.总结

    装饰器模式的关键就是需要共同的超类,并且在装饰抽象类的子类中定义了超类变量,来装饰超类的.

    java中的I/O类就是使用的装饰器模式,大部分类都是用来装饰InputStrem和OutputStrem类的,FilterInputStreamm是抽象装饰类,虽然FilterInputStream没有定义成abstract类型的,但是我们看下源码就知道它其实和装饰器模式一模一样.

    源码如下:

    public
    class FilterInputStream extends InputStream {
        /**
         * The input stream to be filtered.
         */
        protected volatile InputStream in;
    
        /**
         * Creates a <code>FilterInputStream</code>
         * by assigning the  argument <code>in</code>
         * to the field <code>this.in</code> so as
         * to remember it for later use.
         *
         * @param   in   the underlying input stream, or <code>null</code> if
         *          this instance is to be created without an underlying stream.
         */
        protected FilterInputStream(InputStream in) {
            this.in = in;
        }
    }

    里面也包含了超类InputStream变量,并且构造函数给这个变量赋值,在以下方法中都是调用in.XXX方法来实现read,skip,close方法.

    虽然没有搞懂为什么不定义成abstract类,但是构造函数是protected类型的,只有在子类中可以生成FilterInputStream类,或许别的地方需要实例化FilterInputStream类也说不定,抽象类不能实例化,这样定义也许是为了更灵活考虑一点吧.

  • 相关阅读:
    关联模型(1:n)
    关联模型 (1对1)
    cheerio api
    二维数组去重
    Fiddler 模拟post 提交
    DataReader 转为实体
    在做一些复杂的类型转换之前(比如将一个数据转换成一个属性的类型,属性可能为可空类型)先判断该类型是否为可空类型,否则会报如下错误:
    WebClient 文件下载
    利用iTextSharp组件给PDF文档添加图片水印,文字水印
    TList、DataTable To Json
  • 原文地址:https://www.cnblogs.com/lishuaiqi/p/11108416.html
Copyright © 2011-2022 走看看