[设计模式]-装饰器模式(Decorator)

装饰器模式——对象结构型模式

定义
动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式比生成子类更为灵活。
类图


  • Component(抽象构件角色):它是具体构件和抽象装饰类的共同父类,以规范准备接受附加责任的对象
  • ConcreteComponent(具体构件):抽象构件角色的子类(或实现),具体的组件对象,装饰器可以给它增加额外的职责
  • Docorator(装饰器):也是抽象构件角色的子类,持有一个抽象构件角色的引用 ,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,以达到装饰的目的
  • ConcreteDecorator(具体装饰类):具体的装饰类,实现为需要装饰的构件添加新的职责
注:该引用不一定是最原始的那个对象了,也可能是被其他装饰器装饰过后的对象,反正是实现同一个接口(父类),也就是同一类型

Java代码实现

如果我们要实现一个咖啡屋的订单系统,设计类时,如果要为m种咖啡(浓缩、深焙。。。)搭配的n种调料(豆浆、摩卡、糖、牛奶。。) 分别设计一个类。。简直是一个噩梦,这还没有考虑可能的新的需求变动
如何避免类爆炸问题,而又不违反开闭原则的基础上,弹性的搭配新的行为来应对未知的需求变动?装饰器模式正适合解决这类问题
咖啡屋订单实例

//饮料-抽象构件
public abstract class Beverage {
	String description = "";
	public String getDescription() {
		return description;
	}
	public abstract double cost();
}
//浓缩咖啡-具体构件1
public class Espresso extends Beverage{
	public Espresso() {
		description = "浓缩咖啡(Espresso)";
	}

	@Override
	public double cost() {
		return 1.99;
	}
}
//调料-抽象装饰器
public abstract class CondimentDecorator extends Beverage{
	@Override
	public abstract String getDescription();
}
//糖调料-具体装饰器
public class Sugar extends CondimentDecorator{
	Beverage beverage ;
	public Sugar(Beverage beverage) {
		this.beverage = beverage;
	}

	@Override
	public String getDescription() {
		return beverage.getDescription()+" + 糖 ";
	}

	@Override
	public double cost() {
		return 0.20+beverage.cost();
	}
}
咖啡屋订单
public static void main(String[] args) {
		Beverage coffee = new Espresso();//一杯浓缩咖啡
		System.out.println(coffee.getDescription()+" : $"+coffee.cost());
		coffee = new Milk(coffee);
		System.out.println(coffee.getDescription()+" : $"+coffee.cost());
		coffee = new Sugar(coffee);
		System.out.println(coffee.getDescription()+" : $"+coffee.cost());
		//+双份糖的深焙咖啡
		coffee = new DarkRoast();
		coffee = new Sugar(new Sugar(coffee));
		System.out.println(coffee.getDescription()+" : $"+coffee.cost());
	}/* Output:
		浓缩咖啡(Espresso): $1.99
		浓缩咖啡(Espresso) + 牛奶 : $2.29
		浓缩咖啡(Espresso) + 牛奶  + 糖 : $2.49
		深焙咖啡(DarkRoast) + 糖  + 糖  : $1.29
	 */

对象组合
装饰器模式能够动态地为对象添加功能,是从一个对象外部来给对象添加功能,相当于改变了对象的外观。从外部使用系统的角度看,就不再是使用原始的那个对象了,而是使用被一系列装饰器装饰过后的对象。这样就能够灵活的改变一个对象的功能,只要动态组合的装饰器发生了改变,那么最终所得到的对象的功能就发生了改变。另一个好处是装饰器功能的复用,可以给一个对象多次增加同一个装饰器,也可以用同一个装饰器来装饰不同的对象。而且符合面向对象设计中的一条基本规则:"尽量使用对象组合,而不是对象继承"

Java中装饰器模式

装饰模式在Java中最经典的应用就是I/O流,回忆一下,当我们使用流式操作读取文件内容时,怎么实现呢?示例如下:
public static void main(String[] args) throws IOException {
		DataInputStream dis = null;
		try {
			dis = new DataInputStream(
					new BufferedInputStream(
							new FileInputStream("D:/IOTest.txt")
							)
					);
			byte[] bs = new byte[dis.available()];
			dis.read(bs);
			System.out.println("文件内容====>"+new String(bs));
		} finally{
			dis.close();
		}
	}

FileInputStream对象就相当于被装饰的对象,而BufferedInputStream对象和DataInputStream对象则相当于装饰器。而事实上Java I/O流的类图结构和装饰模式类图结构几乎是一样的

装饰器模式总结

装饰器模式的本质:动态组合
优点
  • 比继承更灵活。继承是静态的,而且一旦继承所有子类都有一样的功能。而装饰模式采用把功能分离到每个装饰器中,然后通过对象组合的方式,在运行时动态的组合功能,每个被装饰的对象最终有哪些功能,是由运行期动态组合的功能决定的
  • 更容易复用功能。有利于装饰器功能的复用,可以给一个对象多次增加同一个装饰器,也可以用同一个装饰器来装饰不同的对象
  • 简化高层定义。装饰模式可以通过组合装饰器方式给对象增添任意多的功能,因此在进行高层定义的时候,只需要定义最基本的功能就可以了,需要的时候结合相应装饰器完成需要的功能
缺点
可能会产生很多细粒度的对象

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值