设计模式---装饰器模式

一. 概述

  • 定义
    动态的将新功能附加到对象上,在对象功能扩展方面,它比继承更有弹性,也体现了开闭原则(ocp)。
  • 原理
    装饰器模式就像打包一个快递。
    Component主体/被装饰者):比如:陶瓷、衣服 和包装两部分;
    Decorator包装:比如:报纸填充、塑料泡沫、纸板、木板
    UML类图如下:
    在这里插入图片描述
    在Component与ConcreteComponent之间,如果ConcreteComponent类很多,还可以设计一个缓冲层,将共有的部分提取出来,抽象层一个类 。

    其实,装饰器模式可以看成是对一个类的一种增强手段。从Decorator的类图来看,内部持有Component实例,真正执行方法时会调用Component实例方法和增强逻辑,这样,就相当于给Component方法增强了,整个的执行原理可以简单浓缩成一句话:是你(extends),还有你(持有实例),一切拜托你(调用实例方法)。

二. 场景示例
星巴克咖啡订单项目(咖啡馆):

  1. 咖啡种类/单品咖啡:Espresso(意大利浓咖啡)、ShortBlack、LongBlack(美式
    咖啡)、Decaf(无因咖啡)
  2. 调料:Milk、Soy(豆浆)、Chocolate
  3. 要求在扩展新的咖啡种类时,具有良好的扩展性、改动方便、维护方便
  4. 使用OO( 面向对象(Object Oriented,OO))的来计算不同种类咖啡的费用: 客户可以点单品咖啡,也可以单品咖啡+调料组合。
  • 装饰者模式解决星巴克咖啡订单
    在这里插入图片描述

  • 装饰者模式下的订单:2份巧克力+一份牛奶的LongBlack
    在这里插入图片描述

  1. Milk包含了LongBlack
  2. 一份Chocolate包含了(Milk+LongBlack)
  3. 一份Chocolate包含了(Chocolate+Milk+LongBlack)
  4. 这样不管是什么形式的单品咖啡+调料组合,通过递归方式可以方便的组合和维护。
  • 代码示例:
public abstract class Drink {

	public String des; // 描述
	private float price = 0.0f;

	public String getDes() {
		return des;
	}
	public void setDes(String des) {
		this.des = des;
	}
	public float getPrice() {
		return price;
	}
	public void setPrice(float price) {
		this.price = price;
	}

	//计算费用的抽象方法
	//子类来实现
	public abstract float cost();
}
public class Coffee  extends Drink {
	@Override
	public float cost() {
		return super.getPrice();
	}
}

public class ShortBlack extends Coffee{
	public ShortBlack() {
		setDes(" shortblack ");
		setPrice(4.0f);
	}
}

public class DeCaf extends Coffee {
	public DeCaf() {
		setDes(" 无因咖啡 ");
		setPrice(1.0f);
	}
}

public class Espresso extends Coffee {
	public Espresso() {
		setDes(" 意大利咖啡 ");
		setPrice(6.0f);
	}
}

public class LongBlack extends Coffee {
	public LongBlack() {
		setDes(" longblack ");
		setPrice(5.0f);
	}
}
public class Decorator extends Drink {
	private Drink obj;
	
	public Decorator(Drink obj) { //组合
		this.obj = obj;
	}
	
	@Override
	public float cost() {
		// getPrice 自己价格
		return super.getPrice() + obj.cost();
	}
	
	@Override
	public String getDes() {
		// obj.getDes() 输出被装饰者的信息
		return des + " " + getPrice() + " && " + obj.getDes();
	}
}

//具体的Decorator, 这里就是调味品
public class Chocolate extends Decorator {
	public Chocolate(Drink obj) {
		super(obj);
		setDes(" 巧克力 ");
		setPrice(3.0f); // 调味品 的价格
	}
}

public class Milk extends Decorator {
	public Milk(Drink obj) {
		super(obj);
		setDes(" 牛奶 ");
		setPrice(2.0f); 
	}
}

public class Soy extends Decorator{
	public Soy(Drink obj) {
		super(obj);
		setDes(" 豆浆  ");
		setPrice(1.5f);
	}
}
public class Client {
    public static void main(String[] args) {
        // 模拟客户点单:2份巧克力+一份牛奶的LongBlack
        Chocolate cho = new Chocolate(new Chocolate(new Milk(new LongBlack())));
        System.out.println(cho.cost()); //13.0
    }
}

三. 装饰器模式在JDK中的应用
JDK中的IO流设计就用到了装饰器模式。
比如:想读取一个二进制文件,可以这样获取一个输入流:

InputStream input = new DataInputStream(new BufferedInputStream(new FileInputStream("C:/test.exe")));

在这里插入图片描述
以如下代码为例从源码层面说明JDK中是如何应用装饰器模式的:

DataInputStream dis = new DataInputStream(new FileInputStream("D:\\test.txt"));

在这里插入图片描述

// 是一个抽象类,即Component,类似前面的Drink
public abstract class InputStream implements Closeable {}

// InputStream子类,类似前面的LongBlack,DeCaf
public class FileInputStream extends InputStream{  }

// InputStream子类,是一个装饰者类Decorator
public class FilterInputStream extends InputStream { 
   /**
     * The input stream to be filtered.
     * 被装饰的对象
     */
    protected volatile InputStream in; 
}

// InputStream子类,具体的修饰者,类似前面的Milk,Soy
public class DataInputStream extends FilterInputStream implements DataInput{ }

关于类的增强扩展:
Proxy 遇上 Decorator:https://my.oschina.net/huangyong/blog/162655

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值