【设计模式】装饰模式

装饰模式

一 概述

什么是装饰模式

话不多说,先上概念:动态的给对象添加一些额外的职责,就功能来说,装饰模式相比生成子类更加灵活。
什么意思呢?举个例子,就拿明星来说,明星是一个抽象类,他的一个实例比如小蔡要出去表演,但是他只负责表演,不负责服装,如果没人负责他就光着身子唱,那怎么行。于是主办方就给他提供表演服。这里,小蔡就相当与一个被装饰者,主办方相当于一个装饰者。可以动态的添加一些功能。

二 模式的结构与使用

角色
  • 抽象组件:抽象组件是一个抽象类,他定义了被装饰者需要被进行装饰的方法
  • 具体组件:具体组件是抽象组件的一个子类,他的实例被称为被装饰者
  • 具体装饰:该类的实例被称为装饰者
具体实现
  • 抽象组件
/*
 * 明星类,规定了具体组件需要实现的方法
 */
public abstract class Star {
	public abstract String sing();
}
  • 具体组件
/*
 * 具体的明星类,实现了需要被装饰的方法
 */
public class Cxk extends Star{

	@Override
	public String sing() {
		return "小蔡唱歌";
	}

}
  • 具体装饰
/*
 * 装饰者的具体实现
 */
public class DecoratorOne extends Star{
	
	private final String s = "穿着西装的";
	//声明一个被装饰者变量
	private Star star;
	
	public DecoratorOne(Star star){
		this.star = star;
	}
	
	//对被装饰的方法进行强化
	@Override
	public String sing() {
		return eleSing()+star.sing();
	}
	
	public String eleSing(){
		return s;
	}
	
}
  • 主函数
public class MainClass {
	public static void main(String[] args) {
		Star s = new Cxk();
		Star d = new DecoratorOne(s);
		String str = d.sing();
		System.out.println(str);
	}
}

结果
在这里插入图片描述

三 关于装饰模式与继承机制的对比

  • 看了上面的内容,也许很多小伙伴发现继承,重写方法也能实现上面的功能,为什么不用继承呢?这里其实是考虑到了系统的扩充性,应当注意面向对象的一个基本原则:少用继承,多用组合。
    就拿上面的那个例子来说,主办方在给小蔡穿了西装表演以后获得了成功,但是换了一个地方发现观众不买账了,于是应观众的要求给小蔡换上了比基尼,又获得了成功,但是换了个地方后观众又要求穿西装。到了这里,如果用继承的话还需要反复改代码,用装饰者模式就可以再写一个装饰者类就可以。
  • 具体实现
    这里在上面的基础上再加一个装饰者类
/*
 * 第二个装饰者类
 */
public class DecoratorTwo extends Star{
	private final String s = "穿着比基尼的";
	private Star star;
	public DecoratorTwo(Star star) {
		this.star = star;
	}
	@Override
	public String sing() {
		return eleSing()+star.sing();
	}
	public String eleSing(){
		return s;
	}

}

主类

public class MainClass {
	public static void main(String[] args) {
		Star s = new Cxk();
		Star d = new DecoratorOne(s);
		String str = d.sing();
		System.out.println(str);
		System.out.println("===================");
		Star d1 = new DecoratorTwo(s);
		String str1 = d1.sing();
		System.out.println(str1);
	}
}

结果
【设计模式】装饰模式_第1张图片

  • 接着上面,等主办方再换地方,这个地方的观众更奇怪,他们要求小蔡穿着西装加拖鞋进行表演,这样用继承实现的就还需要改代码而装饰模式也可以轻松实现。
    具体实现
/*
 * 第三个装饰者类
 */
public class DecoratorThree extends Star{
	private final String s = "穿着拖鞋";
	private Star star;
	public DecoratorThree(Star star) {
		this.star = star;
	}
	@Override
	public String sing() {
		return eleSing()+star.sing();
	}
	public String eleSing(){
		return s;
	}
}

主函数

public class MainClass {
	public static void main(String[] args) {
		Star s = new Cxk();
		Star d = new DecoratorOne(s);
		String str = d.sing();
		System.out.println(str);
		System.out.println("===================");
		Star d1 = new DecoratorTwo(s);
		String str1 = d1.sing();
		System.out.println(str1);
		System.out.println("===================");
		Star d2 = new DecoratorThree(new DecoratorOne(s));
		String str2 = d2.sing();
		System.out.println(str2);
	}
}

结果
【设计模式】装饰模式_第2张图片

  • 看到这里是不是发现装饰模式比继承机制更加灵活。

三 Java IO与装饰模式

在Java IO包中有很多类是装饰模式的
比如Reader类与他的两个子类FileReader与BufferReader,其中FileReader相当于被装饰者,BufferReader相当于装饰者。BufferReader在使用read方法读取字符时,首先要委托FileReader对象将字符读入缓冲,然后BufferReader再从缓存中读取该字符。而且BufferReader中有一个readLine方法,这个方法首先要用FileReader读取足够的字符到缓存,然后BufferReader对象从缓存中读取一行字符

四 装饰模式的优点与适用场景

优点
  • 被装饰者与装饰者之间是松耦合,由于装饰仅仅依赖于抽象组件,因此具体装饰只知道他要装饰的对象是抽象组件某一个子类的实例,但不需要知道是哪一个具体子类
  • 装饰模式满足“开-闭原则”,不必修改具体组件,就可以增加新的针对该具体组件的具体装饰。
  • 可以使用多个具体装饰来装饰具体组件的实例。
适用场景
  • 程序希望动态的增强类的某个对象的功能,而不影响到该类的其他对象
  • 采用继承来增强对象功能不利于系统的扩展和维护。

这就是我理解的装饰模式,有什么问题欢迎大家指正。

你可能感兴趣的:(java,设计模式)