设计模式学习----装饰器模式
这两天本来是自在学习java collection Framework的Fail Fast底层机制,看到核心的部分时,突然意识到设计模式的问题,上大学到现在我还没有真正理解过设计模式的概念,于是用了大半天好好的学习了一下装饰器模式,回头再看jdk的源码,舒服多了,的确验证了那句话,设计模式非学不可啊,可以说自己是个十足的菜鸟,连基本的java接口机制和继承都忘得差不多了,这一天全拾起来了~
首先解释一下忘记接口的同学难点,接口其实就是java的抽象机制,不提供方法的具体实现,但是可以有多个类来实现这个接口,一个类也可以实现多个接口,接口带来的好处是创建实例时,用户不必关注具体的实现,比如我例子中的DecoratorPattern.java文件中 ,创建实现Basket接口的一个实例时,返回值是接口,下面再使用show方法时,我们就不必去关注谁实现了。接口作为返回值的一个经典的应用是使用ArrayList时,他的iterator方法会返回一个Iterator接口。这样开发者使用it.next方法,再不用去研究每一种list是怎么实现查询了。
下面解释装饰器模式是如何引起的,深入浅出模式设计的例子很好,就是喝咖啡,有个调料的类,你可以加糖、冰、牛奶等等好多原料,那么生成调配方案时,可以通过继承来实现,但是大家也都知道排列组合,继承的类系统庞大可想而知了。
这就诞生了装饰器模式,他的原则是,保持原有的接口,并为原来的动态的添加新的功能。
下面是维基百科的解释:相信大家都可以看懂
“通过使用修饰模式,可以在运行时扩充一个类的功能。原理是:增加一个修饰类包裹原来的类,包裹的方式一般是通过在将原来的对象作为修饰类的构造函数的参数。装饰类实现新的功能,但是,在不需要用到新功能的地方,它可以直接调用原来的类中的方法。修饰类必须和原来的类有相同的接口。
修饰模式是类继承的另外一种选择。类继承在编译时候增加行为,而装饰模式是在运行时增加行为。
当有几个相互独立的功能需要扩充时,这个区别就变得很重要。在有些面向对象的编程语言中,类不能在运行时被创建,通常在设计的时候也不能预测到有哪几种功能组合。这就意味着要为每一种组合创建一个新类。相反,修饰模式是面向运行时候的对象实例的,这样就可以在运行时根据需要进行组合。一个修饰模式的示例是JAVA里的Java I/O Streams的实现”
//补充一下,还有个经典的例子是java Collection framework也就是我们经常使用的ArrayList的底层实现机制,也是利用了装饰器模式。
再引用网上的一个设计图,很清晰了,我在代码中的实现,并没有实现装饰器基类,而是直接去装饰了。
下面介绍我这个演示的demo,假设我们有一个水果篮子,厘米可以装苹果,香蕉、或者橘子。这是可以典型的应用装饰器模式,比如我们用三个修饰器来修饰水果篮子里面装的内容。假设我们使用继承的话,那么要想获得所有情况,根据排列组合那么就有8种可能,需要有7个子类(空篮子就是本身,不需继承了)。装饰器模式就简单多了
第一个是Basket接口
1 package uni.pattern.decorator;
2 /*
3 * 创建一个对象的抽象也就是接口
4 */
5 public interface Basket {
6 public void show();
7
8 }
下面是被装饰的对象,也就是对接口的一个实现,注意可以有多个实现
1 package uni.pattern.decorator;
2
3 /**
4 *身份:被装饰的对象
5 *一个对接口的实现,这个对象表示要我们将来要修饰的篮子里装内容,如果想修饰篮子的造型,还可以创建其他类实现Basket的接口,比如Shape
6 * 不理解的话可以查看java语言的接口抽象机制
7 */
8 public class Original implements Basket{
9 public void show(){
10 System.out.println("The original Basket contains");
11 }
12 }
接下来是三个装饰器的实现
1 package uni.pattern.decorator;
2
3 /**
4 *身份:装饰器
5 *为原来的类添加新的功能
6 */
7 public class AppleDecorator implements Basket{
8 private Basket basket;
9 public AppleDecorator( Basket basket){
10 super();
11 this.basket = basket;
12 }
13
14 public void show(){
15 basket.show();
16 System.out.println("An Apple");
17 }
18
19 }
1 package uni.pattern.decorator;
2
3 /**
4 *身份:装饰器
5 */
6 public class BananaDecorator implements Basket{
7 private Basket basket;
8 public BananaDecorator(Basket basket){
9 super();
10 this.basket = basket;
11 }
12
13 public void show(){
14 basket.show();
15 System.out.println("A Banana");
16 }
17
18 }
1 package uni.pattern.decorator;
2
3 /**
4 *身份:装饰器
5 */
6 public class OrangeDecorator implements Basket{
7 private Basket basket;
8 public OrangeDecorator(Basket basket){
9 super();
10 this.basket = basket;
11 }
12
13 public void show(){
14 basket.show();
15 System.out.println("An Oranage");
16 }
17
18 }
最后就是实现的效果,我们三个修饰器全部用到,装满了篮子,当然也可以只装一个苹果或香蕉
1 /*
2 * 设计模式:装饰器模式
3 * java 简单的演示
4 */
5 package decoratorpattern;
6 import uni.pattern.decorator.Original;
7 import uni.pattern.decorator.*;
8
9 /**
10 *
11 * @author octobershiner
12 * 2011 7 25
13 * SE.HIT
14 */
15 public class DecoratorPattern {
16
17 /**
18 * @param args the command line arguments
19 */
20 public static void main(String[] args) {
21 // TODO code application logic here
22 Basket basket = new Original();
23 //一个装饰的过程
24 Basket myBasket =new AppleDecorator(new BananaDecorator(new OrangeDecorator(basket)));
25 myBasket.show();
26 }
27 }
演示的结果:
run:
The original Basket contains
An Oranage
A Banana
an Apple
成功生成(总时间:0 秒)