您的位置:首页 > 编程语言 > Java开发

JAVA设计模式(七)——装饰模式

2015-01-10 09:41 323 查看

1、装饰模式

        装饰模式又被称为包装模式,通过一种对客户端透明的方式来扩展的功能,是继承关系的一个替换方案。

        上面这句话,主要体现两个意思:一是扩展客户端的功能,二是继承关系的一个转换。等下我们在后面的设计原则和结构示意图中会详细说明一下。

2、设计原则

1)多用组合,少用继承。

利用继承设计子类的行为,是在编译时静态决定的,而且所有的子类都会继承到相同的行为。然而,如果能够利用组合的做法扩展对象的行为,就可以在运行时动态地进行扩展。

2)类应设计的对扩展开放,对修改关闭。

3、结构视图

3.1 结构视图

      按照我写博客的惯例,这里应该丢出一个示例结构图示,这也是我从网上copy下来的,我只是做个说明就好了,没必要重复画一个一样的图示:



        从结构图示中,我们可以看到,最上层是一个接口,而不是类,我们使用了接口的实现,这就符合我们在第2条中的原则,用接口的实现替代类的实现。

3.2 角色和职责

抽象组件角色:一个抽象接口,是被装饰类和装饰类的父类接口。(Component)

具体组件角色:抽象组件的实现类。(ConcreteComponent)

抽象装饰角色:包含一个组件的引用,并定义了与抽象组件一致的接口。(Decorator)

具体装饰角色:抽象装饰的实现类,负责具体的装饰实施操作。(ConcreteComponent)

4、基础示例代码

        抽象组件,抽象接口代码示例:

public interface Car {

/**
* 展示
*/
public void show();

/**
* 跑
*/
public void run();
}

        具体组件,Car接口的实例类,CarRun,表示会跑的车:
public class CarRun implements Car{

@Override
public void show() {
// TODO Auto-generated method stub
this.run();
}

@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("我可以跑-----");
}

}

       抽象装饰类,也是一个抽象的类,示例如下:
/**
* 车的装饰类,本身持有一个对car的引用
*
* @author ljtyzhr
*
*/
public abstract class CarDecorator{

private Car car ;
public CarDecorator(Car car) {
this.car = car;
}

public abstract void show();

public Car getCar() {
return car;
}

public void setCar(Car car) {
this.car = car;
}
}

        具体的装饰类实例对象,这里写一个会“飞”的车,示例如下:
public class FlyCarDecorator extends CarDecorator{

public FlyCarDecorator(Car car) {
super(car);
}

@Override
public void show() {
// TODO Auto-generated method stub
this.getCar().show();
this.fly();
}

public void fly(){
System.out.println("可以飞^_^");
}
}

        写完上面的代码之后,我们可以使用一个测试类来看看,如下:
public class MainClass {

public static void main(String[] args) {
CarRun run = new CarRun();
CarDecorator flyCarDecorator = new FlyCarDecorator(run);
flyCarDecorator.show();
}
}

       这里,通过装饰模式,就可以让会飞的车,既能够普通的跑,也能特殊的飞。

5、扩展代码示例

       单纯的看上面的代码,似乎装饰模式也没有什么特别的地方,如果我们需要写一个会“游泳”的汽车,可以添加一个装饰模式实例类。那么装饰模式与之前我们所提到的继承关系又有什么区别呢?我们完全可以使用类的继承来实现呀。

       但是,如果我们提出,一辆汽车,既能够具备基本的会跑,也有两项高级的技能——“游泳”和“飞”,这个时候怎么办呢?难道我们要单独写一个装饰类,重复写着刚才写下的代码吗?No,装饰模式的优势,就是在此刻得到体现的。

      不过这里需要比上面的代码,有一个不同之处,就是我们的装饰实例对象,也要实现抽象组件这个接口,代码如下:

/**
* 会游泳的车
*
* @author ljtyzhr
*
*/
public class SwimCarDecorator extends CarDecorator {

public SwimCarDecorator(Car car) {
super(car);
}

@Override
public void show() {
// TODO Auto-generated method stub
this.getCar().show();
this.swim();
}

public void swim() {
System.out.println("可以游泳~~");
}

@Override
public void run() {
// TODO Auto-generated method stub

}

}

        测试案例如下,我们需要一个既能够游泳,也能够飞的车,那么代码如下:
public class MainClass {

public static void main(String[] args) {
CarRun run = new CarRun();
CarDecorator swimCarDecorator = new SwimCarDecorator(run);
CarDecorator flySwimCarDecorator = new SwimCarDecorator(flyCarDecorator);
flySwimCarDecorator.show();
}

}

5、适用性

以下情况使用Decorator模式

1)需要扩展一个类的功能,或给一个类添加附加职责。

2)需要动态的给一个对象添加功能,这些功能可以再动态的撤销。

3)需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。

6、装饰总结

        Decorator模式与继承关系的目的都是要扩展对象的功能,但是Decorator可以提供比继承更多的灵活性。通过使用不同的具体装饰类以及这些装饰类的排列组合,我们可以创造出很多不同行为的组合。

       这种比继承更加灵活机动的特性,装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。

7、Java实例

      读者如果对上面代码仔细研读,联想一下,是否能够想起,在Java中有地方就使用到了这种模式呢?也许大家接触过,一时想不起,实际上,在java的IO流中,就使用了装饰模式。最基本的IO流只能读取文件,封装过的类文件,可以采用多种读取类型。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息