1.装饰者模式(结构型模式)
装饰者模式由Component(抽象组件),ConcreteComponent(具体组件),Decorator(抽象装饰类),ConcreteDecorator(具体装饰类)组成.
装饰者模式
:动态地将责任附加到对象上,对扩展功能来说,装饰者模式比继承更有弹性更灵活.(因为子类继承父类扩展功能的前提是已知要扩展的功能是什么样的,而这是在编译期就要确定的,但是装饰者模式可以实现动态(在运行时)去扩展功能).
设计原则中一个重要的原则就是
: 类应该对扩展开放,对修改关闭.
符合
开闭原则(开闭原则:对扩展开放,对修改关闭).
JAVA中
IO流的设计就大量运用了装饰模式,如:
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("..")));
2.装饰者模式结构
Component:定义一个对象接口,可以给这些对象动态地添加职责;
ConcreteComponent:定义了一个具体的对象,也可以给这个对象添加一些职责;
Decorator:装饰抽象类,继承了Component,从外类来扩展Component类的功能,但对Component来说,是无需知道Decorator存在.
ConcreteDecorator:就是具体的装饰对象,起到给Component添加职责的功能.
3.装饰者模式使用条件
装饰者模式提供组合的方式扩展对象的特性,这种方式允许我们在任何时候对对象的功能进行扩展甚至是运行时扩展.使用条件如下
:
(1).装饰者类和被装饰者类必须实现同一个接口或继承同一个类.
(2).在装饰者类中必须要有被装饰者类的引用.
(3).在装饰者类中对需要增强的方法进行增强.
(4).在装饰者类中对不需要增强的方法调用原来的逻辑.
4.装饰者模式弊端
如果被装饰者的对象有大量的方法,我们只需装饰其中一个方法,对于不需要装饰的方法调用原有的逻辑,这样的工作量太大.
5.装饰者模式的代码实例
public interface Car{
//抽象方法
void run();
void color();
}
//被装饰者类
public class QQ implements Car{
@Override
public void run(){
System.out.println("qq车以每秒1米的速度在挪动...");
}
@Override
public void color(){
System.out.println("宝强绿...");
}
}
//装饰者抽象类
public abstract class QQWarpper implements Car{
private QQ qq;
public QQWarpper(QQ qq){
this.qq = qq;
}
@Override
public void run(){
qq.run();
}
//对不需要装饰的方法,调用原有逻辑
@Override
public void color(){
qq.color();
}
}
//装饰者抽象类
public class QQFly extends QQWarpper{
public QQFly(QQ qq){
QQWarpper.(qq);
}
//被装饰的方法
@Override
public void run(){
supper.run();
System.out.println("嗖嗖嗖~~~");
}
//对不需要装饰的方法,调用原有逻辑
@Override
public void color(){
supper.color();
}
}
//测试类
public class QQTest{
Car qqFly = new QQFly(new QQ());
qqFly.color();
qqFly.run();
}
6.装饰者模式和代理模式的区别
因为装饰者模式和代理模式的结构和实现方式比较相像,所以在此分析两种代理模式的区别
:
装饰模式:以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案;Java IO的设计即是装饰者模式。
代理模式:给一个对象提供一个代理对象,并有代理对象来控制对原有对象的引用;spring的(AOP)动态代理即使用的代理模式。
装饰模式应该为所装饰的对象增强功能;代理模式对代理的对象施加控制,并不提供对象本身的增强功能.
装饰者模式结构上类似于代理模式,但是和代理模式的目的是不一样的,装饰者是用来动态地给一个对象添加一些额外的职责,装饰者模式为对象加上行为,而代理则是控制访问。
在装饰器模式和代理模式之间还是有很多差别的。装饰器模式关注于在一个对象上动态的添加方法,然而代理模式关注于控制对对象的访问。换句话说,用代理模式,代理类(proxy class)可以对它的客户隐藏一个对象的具体信息。因此,当使用代理模式的时候,我们常常在一个代理类中创建一个对象的实例。并且,当我们使用装饰器模式的时候,我们通常的做法是将原始对象作为一个参数传给装饰者的构造器。
我们可以用另外一句话来总结这些差别:使用代理模式,代理和真实对象之间的的关系通常在编译时就已经确定了,而装饰者能够在运行时递归地被构造。