设计模式--装饰者模式

装饰者模式


一、定义

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

那么,如何区分java的继承与组合呢?

继承:继承是给一个类添加行为的比较有效的途径。通过使用继承,可以使得子类在拥有自身方法的同时,还可以拥有父类的方法。但是使用继承是静态的,在编译的时候就已经决定了子类的行为,我们不便于控制增加行为的方式和时机。

组合:合即将一个对象嵌入到另一个对象中,由另一个对象来决定是否引用该对象来扩展自己的行为。这是一种动态的方式,我们可以在应用程序中动态的控制。

与继承相比,组合关系的优势就在于不会破坏类的封装性,且具有较好的松耦合性,可以使系统更加容易维护。但是它的缺点就在于要创建比继承更多的对象。


所以,在设计模式中有一个原则就叫做“多用组合,少用继承”。


二、模式类图

从上图可以看出,使用装饰者模式,需要这几种角色

抽象组件(被装饰者)

具体组件

抽象装饰者(装饰组件)

具体装饰者

三、实例应用

面馆里有各种面,同时每种面里都可以有客户根据自己的喜好加料或加菜(这里仅是为了说明装饰者模式而举的例子)

/**
 * 面条基类
 * @Author 先
 * @ClassName Client_Decorate.java
 * @Time 2017年3月22日 下午4:50:13
 */
abstract class Noodle{
	//价格
	protected double cost;
	//名称,空表示目前它只是单纯的面条
	protected String name = null;
	
	abstract double getCost();
	
	public String getName(){
		return name;
		
	}
}

/**
 * 意大利面,继承面条基类
 * @Author 先
 * @ClassName Client_Decorate.java
 * @Time 2017年3月22日 下午4:52:56
 */
class ItalyNoodle extends Noodle{

	public ItalyNoodle(){
		name = "意大利面";
	}
	
	@Override
	double getCost() {
		cost = 13.5;
		return cost;
	}
	
}

/**
 * 法式面,继承面条基类
 * @Author 先
 * @ClassName Client_Decorate.java
 * @Time 2017年3月25日 上午10:48:14
 */
class FrenchNoodle extends Noodle{

	public FrenchNoodle(){
		name = "法式面";
	}
	
	@Override
	double getCost() {
		cost = 10.5;
		return cost;
	}
	
}

/**
 * 装饰者基类
 * @Author 先
 * @ClassName Client_Decorate.java
 * @Time 2017年3月22日 下午5:41:10
 */
abstract class NoodleDecrator extends Noodle{
	//所有加料必须重新实验getName方法,因为每种料都不一样,所以在
	//装饰者基类把getName重新定义为abstract,就是强制让其子类重写
	public abstract String getName();
}

/**
 * 具体装饰者,加鸡蛋
 * @Author 先
 * @ClassName Client_Decorate.java
 * @Time 2017年3月22日 下午5:03:39
 */
class Egg extends NoodleDecrator{

	private Noodle noodle;
	
	public Egg(Noodle noodle){
		this.noodle = noodle;
	}
	
	@Override
	double getCost() {
		cost = 1.5;
		return cost + noodle.getCost();
	}

	@Override
	public String getName() {
		name = "鸡蛋";
		return name + noodle.getName();
	}
	
}

/**
 * 具体装饰者,牛肉
 * @Author 先
 * @ClassName Client_Decorate.java
 * @Time 2017年3月22日 下午5:14:33
 */
class Beef extends NoodleDecrator{

	private Noodle noodle;
	
	public Beef(Noodle noodle){
		this.noodle = noodle;
	}
	
	@Override
	double getCost() {
		cost = 4.0;
		return cost + noodle.getCost();
	}

	@Override
	public String getName() {
		name = "牛肉";
		return name + noodle.getName();
	}
	
}

我们来运行测试一下

/**
 * 装饰者模式
 * @Author 先
 * @ClassName Client_Decorate.java
 * @Time 2017年3月22日 下午5:40:20
 */
public class Client_Decorate {

	public static void main(String[] args) {
		//客户A要吃原味拉面
		Noodle n1 = new ItalyNoodle();
		System.out.println("您好A,您要的" + n1.getName() + ",共" + n1.getCost() + "元");
		
		//客户B要吃鸡蛋拉面
		//这句要这么理解,在原本的原味拉面n1上加鸡蛋
		Noodle n2 = new Egg(n1);
		System.out.println("您好B,您要的" + n2.getName() + ",共" + n2.getCost() + "元");
		
		//客户C要吃牛肉拉面
		Noodle n3 = new Beef(n1);
		System.out.println("您好C,您要的" + n3.getName() + ",共" + n3.getCost() + "元");
		
		//客户D要吃鸡蛋牛肉拉面(这时候就要对原味拉面装饰上两种)
		Noodle n4 = new Beef(new Egg(n1));
		System.out.println("您好D,您要的" + n4.getName() + ",共" + n4.getCost() + "元");
		
		//法式面类似
	}
}

输出结果

四、优缺点

优点

           1、装饰者模式可以提供比继承更多的灵活性

           2、可以通过一种动态的方式来扩展一个对象的功能,在运行时选择不同的装饰器,从而实现不同的行为。

           3、通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。

           4、具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。

缺点

           1、会产生很多的小对象,增加了系统的复杂性

           2、这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。


希望对读者有帮助!转载请注明出处!http://blog.csdn.net/h_xiao_x
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yeqiu1024

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值