设计模式之装饰模式
装饰模式(Decorator):
动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更加灵活。
(再来一波生硬的概念...)"Component"是定义一个对象接口,可以给这些对象动态地添加职责。ConcreteComponent是定义了一个具体的对象,也可以给这个对象添加一些职责。Decorator,装饰抽象类,继承了Component,从外类来扩展Component类的功能,但对于Component来说,是无需知道Decorator的存在的。至于ConcreteDecorator就是具体的装饰对象,起到个Component添加职责的功能。
案例走起
现在公司有很多钢笔,纸张和书本,笔记本电脑等等...有桌子和书柜等...这些东西放在哪里完全由你决定...例如桌子,开始是个空桌子,用什么来"修饰"呢?我可以放钢笔也可以放纸张...接下来看看怎么实现的把!
1.根据上面的uml图,首先我们来创建家具()把,赋予它放置东西的能力(行为)
1 package component; 2 3 /** 4 * 家具 5 * @author DeepSleeping 6 * 7 */ 8 public interface Furniture { 9 10 /** 11 * 放置物品 12 */ 13 void place(); 14 }
2.接下来我们创建具体被修饰类(这里我就创建桌子table把)
1 package component.concreteComponent; 2 3 import component.Furniture; 4 5 /** 6 * 具体被装饰类 7 * 桌子 8 * @author DeepSleeping 9 * 10 */ 11 public class Table implements Furniture{ 12 13 @Override 14 public void place() { 15 System.out.println("桌子..."); 16 } 17 18 }
3.然后就是创建抽象修饰类把
1 package decoration; 2 3 import component.Furniture; 4 5 /** 6 * 装饰抽象类 7 * @author DeepSleeping 8 * 9 */ 10 public class Decorator implements Furniture{ 11 12 //持有被装饰类的引用 13 Furniture furniture; 14 15 //通过构造方法传入被装饰类 16 public Decorator(Furniture furniture){ 17 18 this.furniture = furniture; 19 } 20 21 22 @Override 23 public void place() { 24 //调用被装饰类的方法 25 furniture.place(); 26 } 27 28 }
4.抽象修饰类下面自然是那些用来修饰具体被修饰类(桌子、书柜...)的具体修饰类(钢笔,纸张...)
1 package decoration.concreteDecoration; 2 3 import component.Furniture; 4 import decoration.Decorator; 5 6 /** 7 * 具体修饰类(纸张) 8 * @author DeepSleeping 9 * 10 */ 11 public class Paper extends Decorator{ 12 13 /** 14 * 因为父类Decorator中写了有参构造方法,所以无参构造方法就会没有了 15 * 子类继承父类会默认实现父类的无参构造方法,现在必须得手动实现父类中的有参构造方法... 16 * 这样就把被装饰类传进来了... 17 * @param furniture 18 */ 19 public Paper(Furniture furniture) { 20 super(furniture); 21 22 } 23 24 /** 25 * 修饰 26 */ 27 @Override 28 public void place() { 29 super.place(); 30 //添加自己对应的修饰内容 31 System.out.print("放置了一张纸...\t"); 32 } 33 34 35 }
1 package decoration.concreteDecoration; 2 3 import component.Furniture; 4 import decoration.Decorator; 5 6 /** 7 * 具体修饰类(钢笔) 8 * @author DeepSleeping 9 * 10 */ 11 public class Pen extends Decorator { 12 13 Furniture furniture; 14 15 public Pen(Furniture furniture) { 16 super(furniture); 17 } 18 19 @Override 20 public void place() { 21 super.place(); 22 System.out.println("放置了一支钢笔..."); 23 } 24 }
5.好了,接下来就是测试了...
1 package test; 2 3 import component.Furniture; 4 import component.concreteComponent.Table; 5 import decoration.concreteDecoration.Paper; 6 import decoration.concreteDecoration.Pen; 7 8 9 public class TestDecorator { 10 11 public static void main(String[] args) { 12 //实例化被装饰类的对象 13 Furniture table = new Table(); 14 15 System.out.println("******************领导A:放一张纸到桌子上...******************"); 16 table = new Paper(table); 17 table.place(); 18 19 System.out.println(); 20 //再放一支钢笔在桌子上 21 System.out.println("******************领导B:放一支钢笔到桌子上...******************"); 22 table = new Pen(table); 23 table.place(); 24 25 System.out.println(); 26 System.out.println("******************领导C:放4支钢笔和一张纸到桌子上...******************"); 27 //再放4支钢笔和一张纸在桌子上 28 table = new Pen(new Pen(new Pen(new Pen(new Paper(table))))); 29 table.place(); 30 } 31 }
6.运行结果...
小结:
从上述代码中很明显可以看的出来,首先是一个空的桌子我们可以用钢笔或者纸张等来"修饰"这个桌子..
如果需要拓展,可以继续写书柜,然后添加 书,各种修饰,书柜中想放什么动态添加就是了,非常的方便,如果有新的东西比如运来了一批海鲜,添加个海鲜类就好了,至于想放在书柜上还是书桌上由你自己来定
不需要去修改之前的代码。
一个软件肯定会有需求的变更拓展,这时候只要增加那些"修饰"就可以了,这里就是"开闭原则"的良好体现把!
"开放-封闭原则是面向对象设计的核心所在。遵循这个原则可以带来面向对象技术所声称的巨大好处,也就是可维护、可拓展、可复用、灵活性好。开发人员应该仅对程序中呈现出频繁变化的哪些部分做出抽象,然而,对于应用程序中的每个部分都刻意地进行抽象同样不是一个好主意。拒绝不成熟的抽象和抽象本身一样重要。"
学习心得:
学习设计模式以及了解与设计有关的东西或者看看源码,对自己的思想有了一些启发把,还是挺有作用的,学习应该心平气和脚踏实地。
不过目前呢给我的感觉还是"干嘛这么麻烦...就那样放一起不就好了,有改变的话改下代码就好了",不过在学习中,发现,到处都在强调"开闭"等,拓展性啥的。。
基础!基础!基础!基础真的很重要!之前看代理模式完全看不懂,去补了一下多态,这里我觉得又是很好的利用了多态来进行"通信"
多态,反射,注解,各种,还有多线程啊好多好多需要去学习和巩固深入的,漫漫长路共勉吧!
装饰模式在JAVA中的IO流就是很好的例子...):
具体的例子以及前辈运用装饰模式自定义IO流的demo在下面的参考博客中有体现...
本文参考
博客:https://blog.csdn.net/android_zyf/article/details/68343953
书籍:《大话设计模式》