设计模式-装饰模式(理解)

来源:互联网 发布:网络翻墙违法吗 编辑:程序博客网 时间:2024/03/29 12:42

看了《大话设计模式》pdf版的装饰模式和其他博客上的一些讲解,第一遍很难get到讲解的点在哪。经国深思,记录下深思的结果。


装饰模式,其实就是用递归的方式实现了面向切面(接口)编程。面向切面编程,可以从spring框架(AOP)那里学到,


模式用途,面向切面编程,在不用修改远代码的基础上,添加新的逻辑,比如,新增用户,addUser(User u)里面,直接将User插入到数据表,

那么,又有需求来了,要在插入之前记录一些信息,比如是谁插入的,插入的用户名叫什么,那么就可以不修改addUser方法将新增的逻辑加上,可以选择加在addUser方法的前面或者后面,都可以。


实现方法和举例:一个接口,两个类,一个是A,另一个装饰类B(有子类),子类位C和D。接口里 包含需要addUser方法的声明。两个类都实现了这个接口。

根据《大话设计模式》中客户端的代码,可以看出最终执行的是C或者D的方法,那么理解上就会很难,本来要A的对象去addUser,增加功能后却是装饰类调用addUser。


例子:

接口People(public void eatFood();),接口中有一个吃饭方法;

A类为PeopleImpl(实现People接口,重写eatFood()方法),

B类为DecoratePeople,实现People接口,有一个People接口引用类型的成员变量(命名为people,并完成getter和setter方法),重写eatFood方法,该方法中判断people是否为空,不为空则调用people.eatFood()。该类用于对A类进行“装饰”

C类为FemalePeople,继承自B类,用于把A类“装饰”成女性,c的eatFood方法先完成自己的逻辑----给食物拍照,然后再调用成员变量people的eatFood方法

D类为MalePeople,继承自B类,用于把A类“装饰”成男性,d的eatFood方法先完成自己的逻辑----喝酒,然后再调用成员变量people的eatFood方法

准备工作做好了,那么开始完成任务----人妖吃饭(此处声明,下文中的“默认方法”指的是PeopleImpl的eatFood方法)

1)借口引用指向PeopleImpl的对象

People ladyboy = new PeopleImpl();

2)定义两个对象,男性和女性

People female = new FemalePeople();

People male = new MalePeople();

3)开始装饰

一,让ladyboy在eatFood方法执行前执行拍照方法

female.setPeople(ladyboy);

ladyboy = female;

二,让ladyboy在eatFood方法执行前执行喝酒

male.setPeople(ladyboy);

ladyboy = male;

任务完成。代码理解:现在ladyboy指向male对象,那么ladyboy.eatFood()会先执行自己的逻辑--喝酒,然后在调用成员变量的eatFood方法

,而male的成员变量是FemalePeople对象(参见第三部的第二小步骤),那么下面会调用FemalePeople的eatFood方法,该方法先完成给食物拍照方法,再调用female的成员变量的eatFood;

female的成员变量是PeopleImpl对象,那么下面就执行该对象的eatFood方法

综上,在最后,ladyboy调用eatFood方法,会一次执行:喝酒-》给食物拍照-》PeopleImpl对象自己的eatFood方法

可以看出,已经完成了把新的逻辑加到默认eatFood方法之前的功能。

Spring的AOP语法中可以把一个方法注解成默认方法执行后再执行,装饰模式也可以,假设MalePeople类的对象的eatFood写成先执行成员变量的eatFood再执行喝酒,那么就把喝酒放到默认方法之后了


多个装饰的执行前后:从上面的例子可以看出,子类有两个,当子类有更多时,给待“装饰”的对象装饰更多的方法后,执行顺序是怎样的?

从后往前一次数,分成两队,一对是先执行自己的逻辑(队列a),一类是先执行成员变量的方法(队列b)

那么最终调用ladyboy.eatFood会按照以下顺序执行

先a队列里的,再执行默认方法,最后执行b队列里的

0 0