装饰模式(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 @Override14 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 @Override23 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 furniture18 */19 public Paper(Furniture furniture) {20 super(furniture);21 22 }23 24 /**25 * 修饰26 */27 @Override28 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 @Override20 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
书籍:《大话设计模式》