设计模式之装饰者模式

装饰器模式:允许向现有的一个类增加(增强)其新功能,但是却不改变其结构,比继承会更灵活!
解决的问题:有时候为了扩展一个类,用继承会产生子类膨胀的问题。
关键代码:Component类充当抽象类(可以是接口);装饰类引用和继承Component类;集体扩展类重写父类方法;
可以增强或扩展原有的方法,如果在装饰类中添加方法,则后面只能强转成具体实现类,才能调用,因为装饰器定义字段类型为Component类型,所以调用方法必须在Component定义或声明过;
顺便说一句:接口中的字段默认是static final类型的
使用装饰器类典型的特征就是java中I/O类,放在后面说
下面举一个例子:
一家咖啡店有基础咖啡:Espreeso(浓缩咖啡)、HouseBlend(混合咖啡),为了适合不同人的口味,自由添加Macho(摩卡)、Soy(豆浆)、奶泡(whip)如果使用继承,就拿Espresso来说,就有至少2的3次方种(不算加双份的),即8个子类(包含都不添加的类),所以这种继承很容易出现子类膨胀的问题;
但是使用装饰器模式:
设计模式之装饰者模式_第1张图片
共同继承的超类(抽象类和接口)Component类

package com.pattern.decorator;

//在java中也可以直接使用接口 作为超类
public abstract class Beverage {
     String description="unknow beverage";
     public String getDescription(){
         return description;
     }
     public abstract double cost();
}

需要被扩展的基础咖啡类
//所有的基础咖啡都已经且必须实现抽象类Beverage并实现方法。

package com.pattern.decorator;

public class Espresso extends Beverage {

    public Espresso() {
        description="Espression";
        // TODO Auto-generated constructor stub
    }

    @Override
    public double cost() {
        // TODO Auto-generated method stub
        return 1.99;
    }

}
package com.pattern.decorator;

public class HouseBlend extends Beverage {

    public HouseBlend() {
        description="HouseBlend";
        // TODO Auto-generated constructor stub
    }

    @Override
    public double cost() {
        // TODO Auto-generated method stub
        return 0.89;
    }
}

装饰者类 包含被扩展类的抽象类型引用和继承抽象类型component

package com.pattern.decorator;
//添加调料的抽象类,具体扩展类都要继承该类并实现方法
public abstract class CondimentDecorator extends Beverage {

    @Override
    public double cost() {
        // TODO Auto-generated method stub
        return 0;
    }
    //抽象类继承抽象类,可以添加新的方法,有些方法可以不写,但是默认继承,其子类会被要求实现
    public abstract String getDescription();

}

具体扩展类,继承并实现装饰者抽象类

package com.pattern.decorator;

public class Macho extends CondimentDecorator {
    Beverage beverage;
    public Macho(Beverage beverage){
        this.beverage=beverage;
    }
    @Override
    public String getDescription() {
        // TODO Auto-generated method stub
        return beverage.getDescription()+",macho";//实现中必须调用方法,不能直接调用属性
    }

    @Override
    public double cost() {
        // TODO Auto-generated method stub
        return beverage.cost()+.20;
    }

}
package com.pattern.decorator;

public class Soy extends CondimentDecorator {
    Beverage beverage;
    public Soy(Beverage beverage){
        this.beverage=beverage;
    }
    @Override
    public double cost() {
        // TODO Auto-generated method stub
        return beverage.cost()+.10;
    }

    @Override
    public String getDescription() {
        // TODO Auto-generated method stub
        return beverage.getDescription()+",soy";
    }

}
package com.pattern.decorator;

public class Whip extends CondimentDecorator {
    Beverage beverage;
    public Whip(Beverage beverage){
        this.beverage=beverage;
    }
    @Override
    public String getDescription() {
        // TODO Auto-generated method stub
        return beverage.getDescription()+",whip";
    }

    @Override
    public double cost() {
        // TODO Auto-generated method stub
        return beverage.cost()+.30;
    }
    public void bubbling(){

    }
    public void bubbing() {
        // TODO Auto-generated method stub
        System.out.println("whip oO0");
    }

}

测试demon

package com.pattern.decorator;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Demo {
    public static void main(String[] args) throws Exception {
        Beverage beverage=new Espresso();
        beverage=new Macho(beverage);
        beverage.getDescription();
        beverage=new Soy(beverage);
        beverage=new Whip(beverage);
        beverage=new Whip(beverage);
        System.out.println(beverage.getDescription()+" $"+beverage.cost());

        ((Whip)beverage).bubbing();

        File file=new File("D:\\source.txt");
        FileInputStream fis=new FileInputStream(file);
        BufferedInputStream bis=new BufferedInputStream(fis);
        BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(new File("D:\\dest.txt")));
        byte[] b=new byte[1024];
        int len=0;
        while((len=bis.read(b))!=-1){
            bos.write(b, 0, len);
        }
        bis.close();
        bos.close();
    }
}

运行结果:
Espression,macho,soy,whip,whip $2.8899999999999997
whip oO0
说明:从上面可以看出,需要构建扩展类的实例对象的时候,需要传入已经有的基础咖啡类,由于装饰器中字段类型是超类Beverage,因此能调用的方法必须是超类包含的(比如调用子类独有的Bubbing()则需要强转,所以一般不会这么用,可以把这个方法在超类一已有的方法中调用它(把它私有化),有点像增强原有的方法)。
典型的例子就是I/O模型:
设计模式之装饰者模式_第2张图片
FilterInputStream(装饰器类:字段值为InputStrean in)子类扩展类中的BufferedInputStream中read等速度比较快,它是区别于不同的读取每次读取都是从磁盘读取,而它维护一个较大数组缓存,一次读取很多,然后read时是从缓存数组中读取,减少读取磁盘的操作。

你可能感兴趣的:(设计模式,装饰者模式)