您的位置:首页 > 其它

扩展系统功能--装饰模式(Decorator)

2016-03-22 00:49 148 查看
顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例,关系图如下:

设计初衷:通常可以使用继承来实现功能的拓展,如果这些需要拓展的功能的种类很繁多,那么势必生成很多子类,增加系统的复杂性,同时,使用继承实现功能拓展,我们必须可预见这些拓展功能,这些功能是编译时就确定了,是静态的。

1 与适配器模式的区别与联系

适配器的运用场景往往是为了使两个已经存在,且不兼容的接口可以协同工作,可以兼容。采用的手段一般是两种:(1)extends其中一个类,然后implements另一个接口;也就是适配器的类版本。(2)就其中一个接口的类的实现的对象作为适配器的成员变量,然后implements另一个接口;也就是适配器的对象版本。

这样,利用这一个适配器对象,就可以同时操纵两个接口中的方法和数据;可以将一个接口的实例转化为另一个接口可以接收的实例;可以添加一些两个接口中都没有的方法;甚至,构建一个双向适配器。这种模式,模拟的就是现实中的“适配器”啊,所以,适配器的功能很强大,限制很少。

相比于适配器模式,装饰模式的应用场景限制多一些。首先,它是给某个对象,而不是整个类,甚至是整个接口添加一些东西。其次,一个重要限制,与被装饰类​继承同一个父类或者实现同一个接口。

这样的设计好处有两个:

(1)与被装饰类​继承同一个父类或者实现同一个接口而不是直接继承被包装类的好处就是降低了他们的耦合性,而java开发时的要求就是高内聚低耦合。

(2)其次装饰类可以对final修饰的类(最终类)进行装饰,而final修饰的类不能有子类。

2 使用装饰器

首先就是如何去定义一个装饰类,定义的时候用下面五步进行

*1.定义一个类,实现与被装饰类相同的接口

*2.定义一个成员变量,记住被装饰类的对象的引用

*3.定义构造方法,传入被装饰类的对象

*4.对于需要改写的方法,改写即可

*5.对于不需要改写的方法,调用原有被装饰类的对应方法

关于构造方法,只能有一个,那就是参数为被装饰类的对象的引用,只有这样才能保证装饰类可以调用被装饰类中的所有方法.在装饰类中要有一个被装饰类型的变量来接受传入的参数,除此以外也可以定义其他的成员变量,不过最好不要定义其他的,保持和被装饰类一样就是最好的。在改写方法(注意这里是改写不是重写或者重载)的时候可以将不需要改写的方法原模原样的写进来(用成员变量定义的对象名调用)。

代码实例:

public interface Sourceable {
public void method();
}


public class Source implements Sourceable {

@Override
public void method() {
System.out.println("the original method!");
}
}


public class Decorator implements Sourceable {

private Sourceable source;

public Decorator(Sourceable source){
super();
this.source = source;
}
@Override
public void method() {
System.out.println("before decorator!");
source.method();
System.out.println("after decorator!");
}
}


测试类:

public class DecoratorTest {

public static void main(String[] args) {
Sourceable source = new Source();
Sourceable obj = new Decorator(source);
obj.method();
}
}


总结



在装饰模式结构图中包含如下几个角色:

● Component(抽象构件):它是具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法,它的引入可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对象,实现客户端的透明操作。
● ConcreteComponent(具体构件):它是抽象构件类的子类,用于定义具体的构件对象,实现了在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法)。
● Decorator(抽象装饰类):它也是抽象构件类的子类,用于给具体构件增加职责,但是具体职责在其子类中实现。它维护一个指向抽象构件对象的引用,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,以达到装饰的目的。
● ConcreteDecorator(具体装饰类):它是抽象装饰类的子类,负责向构件添加新的职责。每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为。


由于具体构件类和装饰类都实现了相同的抽象构件接口,因此装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任,换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不需要创造更多子类的情况下,将对象的功能加以扩展。

装饰模式的核心在于抽象装饰类的设计,其典型代码如下所示:

class Decorator implements Component
{
private Compon
4000
ent component;  //维持一个对抽象构件对象的引用
public Decorator(Component component)  //注入一个抽象构件类型的对象
{
this.component=component;
}

public void operation()
{
component.operation();  //调用原有业务方法
}
}


在抽象装饰类Decorator中定义了一个Component类型的对象component,维持一个对抽象构件对象的引用,并可以通过构造方法或Setter方法将一个Component类型的对象注入进来,同时由于Decorator类实现了抽象构件Component接口,因此需要实现在其中声明的业务方法operation(),需要注意的是在Decorator中并未真正实现operation()方法,而只是调用原有component对象的operation()方法,它没有真正实施装饰,而是提供一个统一的接口,将具体装饰过程交给子类完成。

在Decorator的子类即具体装饰类中将继承operation()方法并根据需要进行扩展,典型的具体装饰类代码如下:

class ConcreteDecorator extends Decorator
{
public ConcreteDecorator(Component  component)
{
super(component);
}

public void operation()
{
super.operation();  //调用原有业务方法
addedBehavior();  //调用新增业务方法
}

//新增业务方法
public  void addedBehavior()
{
……
}
}


在具体装饰类中可以调用到抽象装饰类的operation()方法,同时可以定义新的业务方法,如addedBehavior()。

由于在抽象装饰类Decorator中注入的是Component类型的对象,因此我们可以将一个具体构件对象注入其中,再通过具体装饰类来进行装饰;此外,我们还可以将一个已经装饰过的Decorator子类的对象再注入其中进行多次装饰,从而对原有功能的多次扩展。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息