装饰者模式

MM们要过生日了 ,怎么也得表示下吧。最起码先送个蛋糕。蛋糕多种多样了。巧克力,冰淇淋,奶油等等。这都是基本的了 ,再加点额外的装饰,如蛋糕里放点花。放贺卡。放点干果吃着更香等等。看看我是如何设计的。

      我想既然是蛋糕,那我就把蛋糕作为一个抽象类,剩下的蛋糕子类型来继承它,每个子类都有吃该蛋糕的感觉 ^_^,看起来真的不错。蛋糕的子类分别是奶酪蛋糕,巧克力蛋糕,冰淇淋蛋糕,插花的冰淇淋蛋糕,放贺卡的冰淇淋蛋糕。某个MM的生日蛋糕喜欢带花的冰淇淋蛋糕。还好我早有准备。但是有几次失策了。。她们要的蛋糕我这都没有。比如带鲜花的巧克力蛋糕。带果仁的牛奶蛋糕。带鲜花带果仁的蛋糕。。。。那我还要继续添加蛋糕的子类。。问题出现了。这样会造成大量的蛋糕子类 。真是噩梦啊。

 

那么我要好好思考这个问题了。发现了刚才的设计确实有问题。。发现了真正的要关注的主体是蛋糕。。而贺卡,花,果仁等等只不过是装饰 的作用。

 

思路来了。蛋糕作为主体,其他的东西都加到蛋糕上。MM要啥我就加啥呗。呵呵。

到现在我们要明确的是:

  • 蛋糕是主体。
  • 花,贺卡,果仁等等是装饰者。
  • 可以用装饰者包装蛋糕。

来看看什么是装饰器模式吧:

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

 


  • Component:抽象出的主体对象。
  • ConcreteComponent:是要动态扩展的对象,它继承自Component.
  • Decorator:是装饰器的接口。(这里的接口并不是指java的interface)。
  • ConcreteDecoratorA:实现Decorator的类,包含了一个Component引用,这样就可以扩展Component的方法了。

说完理论了。可能还一头雾水吧。。。还是接着蛋糕的例子继续说。先看图吧。



基本符合了上面所提到的装饰者模式的框架结构了。再看看代码:

Cake

Java代码 复制代码  收藏代码
  1. package decorator.demo;   
  2.   
  3. /**  
  4.  * 蛋糕基类  
  5.  * @author Nicholas  
  6.  *  
  7.  */  
  8. public abstract class Cake {   
  9.     String remark = "蛋糕";   
  10.     public String getRemark() {   
  11.         return remark;   
  12.     }   
  13.     public abstract String getImpression();//用来描述吃蛋糕的感觉。。。。   
  14. }  
package decorator.demo;

/**
 * 蛋糕基类
 * @author Nicholas
 *
 */
public abstract class Cake {
	String remark = "蛋糕";
	public String getRemark() {
		return remark;
	}
	public abstract String getImpression();//用来描述吃蛋糕的感觉。。。。
}

 Cake是个抽象类,它已经实现了getRemark的方法。但没有实现getImpression.这个方法必须被子类实现。

 

再看看装饰器的抽象类

OtherDecorator

Java代码 复制代码  收藏代码
  1. package decorator.demo;   
  2.   
  3. /**  
  4.  * 其他用来添加蛋糕的东西  
  5.  * @author Nicholas  
  6.  *  
  7.  */  
  8. public abstract class OtherDecorator extends Cake{   
  9.     Cake cake;   
  10.     /**  
  11.      * 引用一个Cake.  
  12.      * 让被装饰者进入装饰者之中。这里用的是构造方法注入。  
  13.      * 这样就可以调用Cake实例的方法了。  
  14.      * @param cake  
  15.      */  
  16.     public OtherDecorator(Cake cake){   
  17.         this.cake=cake;   
  18.     }   
  19.     /**  
  20.      * 让装饰器的子类都去实现getRemark方法。业务需要每个装饰器都要有描述。  
  21.      */  
  22.     public abstract String getRemark();   
  23. }  
package decorator.demo;

/**
 * 其他用来添加蛋糕的东西
 * @author Nicholas
 *
 */
public abstract class OtherDecorator extends Cake{
	Cake cake;
	/**
	 * 引用一个Cake.
	 * 让被装饰者进入装饰者之中。这里用的是构造方法注入。
	 * 这样就可以调用Cake实例的方法了。
	 * @param cake
	 */
	public OtherDecorator(Cake cake){
		this.cake=cake;
	}
	/**
	 * 让装饰器的子类都去实现getRemark方法。业务需要每个装饰器都要有描述。
	 */
	public abstract String getRemark();
}

 

下面让我们实现一个蛋糕吧。^_^。。

Java代码 复制代码  收藏代码
  1. package decorator.demo;   
  2. /**  
  3.  * 乳酪蛋糕  
  4.  * @author Nicholas  
  5.  *  
  6.  */  
  7. public class CheeseCake extends Cake{   
  8.     /**  
  9.      * 乳酪蛋糕的构造方法  
  10.      */  
  11.     public CheeseCake(){   
  12.         super.remark="乳酪蛋糕";//修改乳酪蛋糕的描述。   
  13.     }   
  14.   
  15.     /**  
  16.      * 实现了Cake抽象类的getImpression  
  17.      * 吃乳酪蛋糕的感觉。。  
  18.      */  
  19.     public String getImpression() {   
  20.         return "香甜感受";   
  21.     }   
  22.   
  23. }  
package decorator.demo;
/**
 * 乳酪蛋糕
 * @author Nicholas
 *
 */
public class CheeseCake extends Cake{
	/**
	 * 乳酪蛋糕的构造方法
	 */
	public CheeseCake(){
		super.remark="乳酪蛋糕";//修改乳酪蛋糕的描述。
	}

	/**
	 * 实现了Cake抽象类的getImpression
	 * 吃乳酪蛋糕的感觉。。
	 */
	public String getImpression() {
		return "香甜感受";
	}

}

 

其他实现Cake的类就不列出了,道理是一样的。

下面我们要开始实现具体的装饰器了。

Java代码 复制代码  收藏代码
  1. package decorator.demo;   
  2.   
  3. /**  
  4.  * 给蛋糕添加的花  
  5.  * @author Nicholas  
  6.  *  
  7.  */  
  8. public class FlowerDecorator extends OtherDecorator{   
  9.        
  10.     /**  
  11.      * 构造函数  
  12.      * 传入一个cake实例,也就是前面所实现的Cake的子类,如奶酪蛋糕,巧克力蛋糕等等。  
  13.      * @param cake  
  14.      */  
  15.     public FlowerDecorator(Cake cake){   
  16.         super(cake);//调用父类的构造方法,可以获取Cake的实例了。就可以调用Cake实例的方法.   
  17.         super.remark="一朵玫瑰花";   
  18.     }   
  19.        
  20.     /**  
  21.      * 实现了装饰器抽象类的getImpression方法。  
  22.      */  
  23.     public String getImpression() {   
  24.         //这是重点。我们通过构造方法传入的cake实例。对cake进行了装饰,增加了新的功能。   
  25.         return cake.getImpression()+","+"看到一朵花真是happy";   
  26.     }   
  27.   
  28.     public String getRemark() {   
  29.         return cake.getRemark()+"+"+super.remark;   
  30.     }   
  31. }  
package decorator.demo;

/**
 * 给蛋糕添加的花
 * @author Nicholas
 *
 */
public class FlowerDecorator extends OtherDecorator{
	
	/**
	 * 构造函数
	 * 传入一个cake实例,也就是前面所实现的Cake的子类,如奶酪蛋糕,巧克力蛋糕等等。
	 * @param cake
	 */
	public FlowerDecorator(Cake cake){
		super(cake);//调用父类的构造方法,可以获取Cake的实例了。就可以调用Cake实例的方法.
		super.remark="一朵玫瑰花";
	}
	
	/**
	 * 实现了装饰器抽象类的getImpression方法。
	 */
	public String getImpression() {
		//这是重点。我们通过构造方法传入的cake实例。对cake进行了装饰,增加了新的功能。
		return cake.getImpression()+","+"看到一朵花真是happy";
	}

	public String getRemark() {
		return cake.getRemark()+"+"+super.remark;
	}
}

 到现在终于大功告成了。。这样方便了很多,可以通过装饰器生成很多种类的蛋糕。

Java代码 复制代码  收藏代码
  1. package decorator.demo;   
  2.   
  3. public class MyGirlB {   
  4.     public static void main(String[] args){   
  5.         //用果仁,花包装巧克力蛋糕。   
  6.         Cake nutsFlowerChocolateCake = new NutsDecorator(new FlowerDecorator(new ChocolateCake()));   
  7.         System.out.println("remark "+nutsFlowerChocolateCake.getRemark());   
  8.         //吃蛋糕的感受已经发生了改变。   
  9.         System.out.println("impression "+nutsFlowerChocolateCake.getImpression());   
  10.     }   
  11. }  
package decorator.demo;

public class MyGirlB {
	public static void main(String[] args){
		//用果仁,花包装巧克力蛋糕。
		Cake nutsFlowerChocolateCake = new NutsDecorator(new FlowerDecorator(new ChocolateCake()));
		System.out.println("remark "+nutsFlowerChocolateCake.getRemark());
		//吃蛋糕的感受已经发生了改变。
		System.out.println("impression "+nutsFlowerChocolateCake.getImpression());
	}
}

 

这个模式的缺点也挺明显的 ,看看如下图片


 

 

为了扩展cake的功能,加入了许多的装饰类。。当然用户也可以继承OtherDecorator来继续扩展。但是对API使用者是个困扰。。所以API要说明哪些类是用来包装的。。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值