透视设计模式之装饰者模式

概述

说到装饰者设计模式,大家并不陌生。在jdk源码中的 IO框架大量使用了装饰者设计模式,所以学习好装饰者设计模式对我们理解java 的 io框架有很大的帮助。


1、定义

装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

1.2、装饰者模式UML图

在这里插入图片描述

1.3、 装饰者模式具备的特点
  • 装饰者和被装饰对象有相同的超类型。
  • 你可以用一个或多个装饰者包装一个对象。
  • 既然装饰者和被装饰对象有相同的超类型,所以在任何需要原始对象(被包装的)的场合,
    可以用装饰过的对象代替它。
  • 装饰者可以在所委托被装饰者的行为之前与 / 或之后,加上自己的行为,以达到特定的目的。
  • 对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰
    对象。
1.4、 大白话解释装饰者模式
  1. 在不改变接口的前提下,动态扩展对象的访问。
  2. 动态继承,让类具有在运行期改变行为的能力。
  3. 装饰模式,突出的是运行期增加行为,这和继承是不同的,继承是在编译期增加行为。因为具体的执行扩展能力我们动态添加的,而不是像继承那样,在编译的时候就已经完成。这样如果我们需要修改或者增加功能,必然需要修改继承代码。违反了设计模式的基本设计原则。装饰者模式动态的将责任附加到对象上,若要扩展功能,装饰者提供了比继承更具有弹性的替代方案
  4. 装饰者模式很好的满足了设计模式中的开闭原则。
  5. 我们从类结构图中可以看出,装饰者实例Decorator 中会有Component的一个引用。这里主要是满足了设计模式中所提倡的多用组合,少用继承的理念。

2、 入门案例

入门案例我们就采用《Head First 设计模式》中的星巴兹咖啡馆。比如咖啡店有HouseBlend(混合咖啡)和darkRoast(深焙咖啡)等原始咖啡。客户可以根据自己的喜好,在这些原始口味的上面加上自己喜欢的调料。这里比如有牛奶,摩卡(mocha),Milk(牛奶)等…。

在此基础上,我们抽象说所有咖啡的接口:Beverage,调味品装饰类:CondimentDecorator,以及他们的实现类等,整个类的基础图如下:
在这里插入图片描述

2.1、 代码实现
  1. 抽象构件类(Component):Beverage 接口
public abstract class Beverage { 
    // 描述咖啡详情
    String description = "咖啡的描述";
    
    public String getDescription(){
        return description;
    }
   
    // 获取当前咖啡的价格
    public abstract double cost();
}
  1. 被修饰者:DarkRoast (深焙咖啡)
public class DarkRoast extends Beverage{
    
    public DarkRoast(){
        description = "深焙咖啡";
    }    
    
    @Override
    public double cost() {
        return 1.0;
    }
}
  1. 被修饰者:HouseBlend(混合咖啡)
public class HouseBlend extends Beverage{
   
    public HouseBlend() {
        description = "混合咖啡";
    }

    @Override
    public double cost() {
        return .89;
    }

}
  1. 装饰者类(Descorator):ConimentDecorator
public abstract class CondimentDecorator extends Beverage{

    public abstract String getDescription();
    
}
  1. 具体装饰者类(ConcreteDescorator):Mocha(摩卡)
public class Mocha extends CondimentDecorator{

    Beverage beverage;
    
    public Mocha(Beverage beverage){
        this.beverage = beverage;
    }
    
    @Override
    public String getDescription() {
        return beverage.getDescription() + ",摩卡";
    }

    @Override
    public double cost() {
        return beverage.cost() + .20;
    }

}
  1. 具体装饰者类(ConcreteDescorator):Milk(牛奶)
public class Milk extends CondimentDecorator{

    Beverage beverage;
    
    public Milk(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + " ,牛奶";
    }

    @Override
    public double cost() {
        return beverage.cost() + .10;
    }

}

7.客户端(Client)

public class StarbuzzCoffee {
	public static void main(String args[]) {
		Beverage beverage2 = new DarkRoast();
		beverage2 = new Mocha(beverage2);
		beverage2 = new Mocha(beverage2);
		beverage2 = new Milk(beverage2);
		System.out.println(beverage2.getDescription()
		+ " $" + beverage2.cost());
		Beverage beverage3 = new HouseBlend();
		beverage3 = new Milk(beverage3);
		beverage3 = new Milk(beverage3);
		beverage3 = new Mocha(beverage3);
		System.out.println(beverage3.getDescription()
		+ " $" + beverage3.cost());
	}
}

3、装饰者模式在Java IO 流框架中的实现
3.1 、 IO流中InputStream的UML继承结构图

在这里插入图片描述
从继承结构图中,我们可以发现ObjectInputStream,ByteArrayInputStream,FileInputStream是被修饰者。FilterInputStream是装饰者类。DataInputStream,BufferInputStream是装饰者类的具体实例。具体的IO源码分析我们会在Netty源码分析的章节中进行详细分析部分案例类。


4、面试提问:装饰者和代理模式的区别

其实装饰者模式和代理模式在类的继承结构图上几乎是一样的。但是两个的侧重点是不同的。装饰者模式侧重点是动态的增加类行为。而代理模式更多的是控制具体对象实例的访问。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值