您的位置:首页 > 其它

设计模式笔记--装饰模式

2016-01-13 09:13 274 查看
常用设计模式有23中,分为:

创建型模式(主要用于创建对象)

1、单例模式 2、工厂方法模式
3、抽象工厂模式 4、建造者模式 5、原型模式

行为型模式 (主要用于描述对象或类是怎样交互和怎样分配职责)

1、模板方法模式 2、中介者模式 3、命令模式
4、责任链模式 5、策略模式 6、迭代器模式

7、观察者模式 8、备忘录模式 9、访问者模式 10、状态模式 11、解释器模式
结构型模式(主要用于处理类或对象的组合)

1、代理模式 2、装饰模式
3、适配器模式 4、组合模式 5、外观模式(门面模式) 6、享元模式
7、桥梁模式

装饰模式

装饰模式(Decorator Pattern)是一种比较常见的模式,其定义如下:

动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。





在类图中,有四个角色需要说明:

● Component抽象构件
Component是一个接口或者是抽象类,就是定义我们最核心的对象,也就是最原始的对象,如上面的成绩单。
注意 在装饰模式中,必然有一个最基本、最核心、最原始的接口或抽象类充当Component抽象构件。

● ConcreteComponent 具体构件
ConcreteComponent是最核心、最原始、最基本的接口或抽象类的实现,你要装饰的就是它。

● Decorator装饰角色
一般是一个抽象类,做什么用呢?实现接口或者抽象方法,它里面可不一定有抽象的方呀,在它的属性里必然有一个private变量指向Component抽象构件。

● 具体装饰角色
ConcreteDecoratorA和ConcreteDecoratorB是两个具体的装饰类,你要把你最核心的、最原始的、最基本的东西装饰成其他东西

通用代码

先看抽象构件,如代码清单17-10所示。
<span style="font-size:18px;">代码清单17-10 抽象构件
public abstract class Component {
//抽象的方法
public abstract void operate();
}</span>


具体构件如代码清单17-11所示。
<span style="font-size:18px;">代码清单17-11 具体构件
public class ConcreteComponent extends Component {
//具体实现
@Override
public void operate() {
System.out.println("do Something");
}
}
</span>


装饰角色通常是一个抽象类,如代码清单17-12所示。
<span style="font-size:18px;">public abstract class Decorator extends Component {
private Component component = null;
//通过构造函数传递被修饰者
public Decorator(Component _component){
this.component = _component;
}
//委托给被修饰者执行
@Override
public void operate() {
this.component.operate();
}
}</span>


当然了,若只有一个装饰类,则可以没有抽象装饰角色,直接实现具体的装饰角色即可。

具体的装饰类如代码清单17-13所示。
<span style="font-size:18px;">public class ConcreteDecorator1 extends Decorator {
//定义被修饰者
public ConcreteDecorator1(Component _component){
super(_component);
}
//定义自己的修饰方法
private void method1(){
System.out.println("method1 修饰");
}
//重写父类的Operation方法
public void operate(){
this.method1();
super.operate();
}
}
 </span>
<span style="font-size:18px;">public class ConcreteDecorator2 extends Decorator {
//定义被修饰者
public ConcreteDecorator2(Component _component){
super(_component);
}
//定义自己的修饰方法
private void method2(){
System.out.println("method2修饰");
}
//重写父类的Operation方法
public void operate(){
super.operate();
this.method2();
}
}</span>


注意 原始方法和装饰方法的执行顺序在具体的装饰类是固定的,可以通过方法重载实现多种执行顺序。

我们通过Client类来模拟高层模块的耦合关系,

看看装饰模式是如何运行的,如代码清单17-14所示。
<span style="font-size:18px;">代码清单17-14 场景类
public class Client {
public static void main(String[] args) {
Component component = new ConcreteComponent();
//第一次修饰
component = new ConcreteDecorator1(component);
//第二次修饰
component = new ConcreteDecorator2(component);
//修饰后运行
component.operate();
}
}  </span>


实例 成绩单



其中Decorator的作用是封装SchoolReport类,如果大家还记得代理模式,那么很容易看懂这个类图,装饰类的作用也就是一个特殊的代理类,真实的执行者还是被代理的角色FouthGradeSchoolReport,如代码清单17-6所示。

<span style="font-size:18px;">public abstract class Decorator extends SchoolReport{
//首先我要知道是哪个成绩单
private SchoolReport sr;
//构造函数,传递成绩单过来
public Decorator(SchoolReport sr){
this.sr = sr;
}
//成绩单还是要被看到的
public void report(){
this.sr.report();
}
//看完还是要签名的
public void sign(String name){
this.sr.sign(name);
}
}</span>


装饰类还是把动作的执行委托给需要装饰的对象,Decorator抽象类的目的很简单,就是要让子类来封装SchoolReport的子类,怎么封装?重写report方法!

先看HighScoreDecorator实现类,如代码清单17-7所示。
<span style="font-size:18px;">代码清单17-7 最高成绩修饰
public class HighScoreDecorator extends Decorator {
//构造函数
public HighScoreDecorator(SchoolReport sr){
super(sr);
}
//我要汇报最高成绩
private void reportHighScore(){
System.out.println("这次考试语文最高是75,数学是78,自然是80");
}
//我要在老爸看成绩单前告诉他最高成绩,否则等他一看,就抡起扫帚揍我,我哪里还有机会说啊
@Override
public void report(){
this.reportHighScore();
super.report();
}
}</span>


重写了report方法,先调用具体装饰类的装饰方法reportHighScore,然后再调用具体构件的方法,我们再来看怎么汇报学校排序情况SortDecorator代码,如代码清单17-8所示。
<span style="font-size:18px;">代码清单17-8 排名情况修饰
public class SortDecorator extends Decorator {
//构造函数
public SortDecorator(SchoolReport sr){
super(sr);
}
//告诉老爸学校的排名情况
private void reportSort(){
System.out.println("我是排名第38名...");  </span>


看看老爸怎么看成绩单的,如代码清单17-9所示。

<span style="font-size:18px;">代码清单17-9 老爸查看修饰后的成绩单
public class Father {
public static void main(String[] args) {
//把成绩单拿过来
SchoolReport sr;
//原装的成绩单
sr = new FouthGradeSchoolReport();
//加了最高分说明的成绩单
sr = new HighScoreDecorator(sr);
//又加了成绩排名的说明
sr = new SortDecorator(sr);
//看成绩单
sr.report();
//然后老爸一看,很开心,就签名了
sr.sign("老三");
}
}  </span>


优点

● 装饰类和被装饰类可以独立发展,而不会相互耦合

● 装饰模式是继承关系的一个替代方案。

● 装饰模式可以动态地扩展一个实现类的功能

缺点

多层的装饰是比较复杂的 ,因此,尽量减少装饰类的数量,以便降低系统的复杂度。

使用场景

● 需要扩展一个类的功能,或给一个类增加附加功能。

● 需要动态地给一个对象增加功能,这些功能可以再动态地撤销。

● 需要为一批的兄弟类进行改装或加装功能,当然是首选装饰模式。

装饰模式是对继承的有力补充。

继承是静态地给类增加功能,而装饰模式则是动态地增加功能

装饰模式可以给我们很好的帮助,通过装饰模式重新封装一个类,而不是通过继承来完成,简单点说,三个继承关系Father、Son、GrandSon三个类,我要在Son类上增强一些功能怎么办?我想你会坚决地顶回去!不允许

为什么呢?你增强的功能是修改Son类中的方法吗?增加方法吗?对GrandSon的影响呢?特别是GrandSon有多个的情况,你会怎么办?这个评估的工作量就够你受的,所以这是不允许的,

那还是要解决问题的呀,怎么办?通过建立SonDecorator类来修饰Son,相当于创建了一个新的类,这个对原有程序没有变更,通过扩展很好地完成了这次变更。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: