资讯详情

重学设计模式(三、设计模式-装饰器模式)

通常,我们使用继承或组合来扩展一个类的行为,但这些都是在编译过程中完成的。它适用于所有类的例子。随着扩展功能的增加,子类将非常膨胀。我们不能在操作过程中添加或删除任何现有行为以达到重用的目的。为了解决这个问题,有一个装饰模式。

比如我们熟悉的java IO类中就有大量装饰器模式的使用。例如FilterInputStream、FilterOutputStream、FilterReader、BufferedWriter等。

  • 定义

装饰器(Decorator)结构设计模式是一种替代继承的技术,是指在不改变现有对象结构的情况下,动态地向当前对象添加一些额外的功能。

装饰模式结构:

1)抽象构件(Component)角色:为了规范子类对象的行为,定义抽象接口,所有包装(装饰对象)和包装(真实对象)都继承了该接口。io流中InputStream、OutPutStream、Reader、Writer;

2)具体构件(ConcreteComponent)角色:指包装类的实现类(真实对象)。io流中FileInputStream、FileOutputStream、ObjectInputStream等;

3)装饰(Decorator)角色:所有包装类别都继承自Decorator(抽象)类可以通过其子类扩展特定部件的功能。io流中的FilterInputStream、FilterOutputStream;

4)具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,用于扩展包装功能。io流中的BufferedInputStream、DataInputStream、BufferedOutputStream;

对于java io对于流中的输入流,其系统结构如上图所示。

Component角色:InputStream声明输入流实现规范;

ConcreteComponent角色:FileInputStream,ObjectInputStream、ByteArrayInputStream、PipedInputStream为不同场景提供输入流;

Decorator角色:FilterInputStream抽象装饰是为了增强ConcreteComponent人物抽象;

ConcreteDecorator角色:BufferedInputStream、DataInputStream是装饰的实现,是增强的具体方法。

以前我们用io流去阅读文件时,是否经常添加缓冲流来提高数据读取效率。

InputStream in = new FileInputStream("D:\\bigTest.txt"); InputStream bin = new BufferedInputStream(in); byte[] data = new byte[1024]; while (bin.read(data) != -1) {     //... }

那为什么不直接给呢?FileInputStream访问缓存功能或添加缓存功能FileInputStream的子类呢?从上图可以看出,如果InputStream只有一个实现类的话,这样做完全没有问题,可是InputStream有许多实现类。如果每个子类都添加了增强功能的子类,可以想象此时的子类数量非常大。而我们的装饰模式是用来代替继承和增强对象的。

1.2.装饰模式的优缺点

  • 优点

1)装饰模式是继承的替代模式,可以动态扩展实现功能;

2)多种行为可以通过将一个对象包装到多个装饰器中来组合;

3)大可变整体也可分为小类,更符合单一职责原则;

4)装饰模式完全遵循开关原则。

  • 缺点

装饰模式会增加很多子类,过度使用会增加程序的复杂性。

1.3、创建方式

1)根据装饰模式的结构依次创建

/**  * Component-抽象构件  */ public interface ICar {   void assemble(); ////定义汽车组装行为 }  /**  * ConcreteComponent-具体构件  */ class BasicCar implements ICar{  @Override  public void assemble() {   System.out.println("最低配置的普通车");  } }  /**  * Decorator-抽象装饰角色  */ abstract class AbstractCar implements ICar{  private ICar car;  public AbstractCar(ICar car){   this.car = car;  }  @Override  public void assemble() {   car.assemble();  }  ///作为抽象方法,一些希望子类实现的功能可以声明 }  //ConcreteDecorator-具体装饰器(普通越野款) class SportsCar extends AbstractCar{   public SportsCar(ICar car) {   super(car);  }   @Override  public void assemble() {   super.assemble();   System.out.println("装配高底盘,我是越野款");  }   }  //ConcreteDecorator-具体装饰器(高端款) class LuxuryCar extends AbstractCar{   public LuxuryCar(ICar car) {   super(car);  }    @Override  public void assemble() {   super.assemble();   System.out.println("装配高端发动机,我是高档款");  }   }

2)创建客户端

public class Client {   public static void main(String[] args) {   //最基本的车   BasicCar car = new BasicCar();   car.assemble();      System.out.println("客户1:第一次改装:-----------");   SportsCar sp1 = new SportCar(car);  //已有对象增加/修改一些功能
		sp1.assemble();
		
		System.out.println("顾客二:第一次改装:-----------");
		LuxuryCar lc2 = new LuxuryCar(car); //已有对象增加/修改一些功能
		lc2.assemble();
		
		System.out.println("顾客一:第二次改装:-----------");
		LuxuryCar lc1 = new LuxuryCar(sp1);  //传SportsCar,就是在此版本上修改,这样组装非常灵活
		lc1.assemble();
		
	}
}
  • 案例效果

    在java io流中,我们也可以对原有对象实现自己的一些特殊处理。比如,下面的案例自定义实现转大写装饰器

public class toUpperCaseInputStream extends FilterInputStream{

	protected toUpperCaseInputStream(InputStream in) {
		super(in);
	}

	@Override
    public int read() throws IOException {
        int c = super.read();
        return (c == -1 ? c : Character.toUpperCase(c));
    }
	
	public static void main(String[] args) throws IOException {
		int c;
		//使用自定义的装饰器去装饰ByteArrayInputStream对象
        InputStream in = new toUpperCaseInputStream(new ByteArrayInputStream(new String("abcd").getBytes()));
        try {
            while ((c = in.read()) >= 0) {
                System.out.print((char) c);  //ABCD
            }
        } finally {
            in.close();
        }
	}
}

1.4、总结及建议

    装饰器提供运行时修改能力,因此更加灵活。当可供选择的数量越多时,使用装饰器模式会更加灵活。

应用场景:

    1)

    2)

    3)

JDK中装饰器模式的应用:

    java io流中的FilterInputStream、FilterOutputStream、FilterReader、BufferedWriter等都是抽象装饰类。

   

标签: 电容接触器lc1d40k

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台