设计模式之装饰者模式

装饰模式是在不必改变原类文件和使用继承的情况下, 动态地扩展一个对象的功能, 它是通过创建一个包装对象, 也就是装饰来包裹真实的对象.
装饰者模式在JAVA的IO中应用的很广泛:FilterInputStream 和 FilterOutputStream就是典型的应用

一个生活中常见的例子:盖浇饭

我们中午出去吃午饭,可能有人想吃米饭,有人想吃面条,还有人想喝粥等等,这个算是主食

此外还会点一些浇头,比如荷包蛋,青菜,大排等, 这些浇头就是装饰者了


先定义一个食物的接口Food:

public interface Food {
	public String getDesc();
	public double getPrice();
}


接下来是3种主食,都实现Food接口:

public class Noodle implements Food{

	@Override
	public String getDesc() {
		return " 面条 ";
	}

	@Override
	public double getPrice() {
		return 5;
	}
}

public class Rice implements Food{

	@Override
	public String getDesc() {
		return "米饭";
	}

	@Override
	public double getPrice() {
		return 2;
	}
}

public class Porridge implements Food{

	@Override
	public String getDesc() {
		return " 粥 ";
	}

	@Override
	public double getPrice() {
		return 3;
	}
}


接下来定义一个浇头的抽象类: 

public abstract class Garnish implements Food{

	public Food food;
	public Garnish(Food food) {
		this.food = food;
	}
	
	@Override
	public String getDesc() {
		return food.getDesc();
	}

	@Override
	public double getPrice() {
		return food.getPrice();
	}
}

接着就是浇头的具体实现类:

public class Vegetable extends Garnish{

	public Vegetable(Food food) {
		super(food);
	}
	
	@Override
	public String getDesc() {
		return "青菜+" + food.getDesc();
	}

	@Override
	public double getPrice() {
		return 4 + super.getPrice();
	}
}

public class Ribs extends Garnish{

	public Ribs(Food food) {
		super(food);
	}
	
	@Override
	public String getDesc() {
		return "大排+" + food.getDesc();
	}

	@Override
	public double getPrice() {
		return 8 + super.getPrice();
	}
}

public class Agg extends Garnish{

	public Agg(Food food) {
		super(food);
	}
	
	@Override
	public String getDesc() {
		return "荷包蛋+" + food.getDesc();
	}

	@Override
	public double getPrice() {
		return 2 + super.getPrice();
	}
}

浇头只负责装饰Food对象, 而不管这个Food是怎么来的, 可以对Food进过多次装饰, 每次装饰, 只加上自身属性, 和被装饰的属性

被装饰的对象,可以是已经被装饰过的对象

客户端实现:

public class FoodTest {

	public static void main(String[] args) {
		Food food = new Rice();
		Food agg = new Agg(food);
		Food vegetables = new Vegetable(agg);
		
		System.out.println("名称:" + vegetables.getDesc() + " 价格:" + vegetables.getPrice());
		
		Ribs ribs = new Ribs(agg);
		System.out.println("名称:" + ribs.getDesc() + " 价格:" + ribs.getPrice());
	}

}
输出结果:

名称:青菜+荷包蛋+米饭 价格:8.0
名称:大排+荷包蛋+米饭 价格:12.0

只需要先点一份主食,然后依次用想要的浇头装饰主食, 每次使用浇头进行装饰, 浇头只知道传进来的是一份主食,而不管是否已经被装饰过

同一份浇头也可以装饰多次


装饰者模式和代理模式的实现有点类似:都是实现同一个接口, 然后利用组合, 在原来对象的方法上添加额外的动作

然而,实际上,在装饰器模式和代理模式之间还是有很多差别的。装饰器模式关注于在一个对象上动态的添加方法,然而代理模式关注于控制对对象的访问。换句话 说,用代理模式,代理类(proxy class)可以对它的客户隐藏一个对象的具体信息。因此,当使用代理模式的时候,我们常常在一个代理类中创建一个对象的实例。并且,当我们使用装饰器模 式的时候,我们通常的做法是将原始对象作为一个参数传给装饰者的构造器。


你可能感兴趣的:(设计模式,JAVA,装饰者模式,设计模式)