设计模式--装饰器(Decorator)模式

来源:互联网 发布:ff14国际服数据库app 编辑:程序博客网 时间:2024/06/03 00:00

    • 意图
    • 示例1汉堡的组合
    • 结构及角色
    • 示例2人的行为的组合
    • 何时使用
    • java IO

1. 意图

装饰器模式的意图是在运行时组合操作的新变化
动态地给一个对象添加一些额外的职责。相比生成子类更加灵活。

装饰模式能够实现动态的为对象添加功能,是从一个对象外部来给对象添加功能。通常给对象添加功能,要么直接修改对象添加相应的功能,要么派生对应的子类来扩展,抑或是使用对象组合的方式。显然,直接修改对应的类这种方式并不可取。在面向对象的设计中,而我们也应该尽量使用对象组合,而不是对象继承来扩展和复用功能。

装饰器模式就是基于对象组合的方式,可以很灵活的给对象添加所需要的功能。装饰器模式的本质就是动态组合。动态是手段,组合才是目的。总之,装饰模式是通过把复杂的功能简单化,分散化,然后再运行期间,根据需要来动态组合的这样一个模式。

2. 示例1:汉堡的组合

下面这个例子有助于理解 装饰的流程和作用
现在需要一个汉堡,主体是鸡腿堡,可以选择添加生菜、酱、辣椒等等许多其他的配料,这种情况下就可以使用装饰者模式。

汉堡基类(被装饰者)

package decorator;public abstract class Humburger {    private String name;    public String getName(){        return this.name;    public abstract double getPrice(); }

鸡腿堡类(被装饰者的初始状态)

package decorator;public class ChickenBurger extends Humburger{    private String name;    public ChickenBurger() {        this.name="鸡腿堡";    }    @Override    public double getPrice(){        return 10;    }    @Override    public String getName(){        return this.name;    }}

配料的基类(装饰者,用来对汉堡进行多层装饰,每层装饰增加一些配料)

package decorator;public abstract class Condiment extends Humburger{    public abstract String getName();}

生菜(装饰者的第一层)

package decorator;public class Lettuce extends Condiment{    private Humburger hum;    Lettuce(Humburger hum){        this.hum=hum;    }    @Override    public String getName(){        return hum.getName()+ " 加生菜";    }    @Override    public double getPrice(){        return hum.getPrice()+1.5;    }}

辣椒(装饰者的第二层)

package decorator;public class Chilli extends Condiment{    private Humburger hum;    public Chilli(Humburger hum) {        this.hum=hum;    }    @Override    public String getName(){        return hum.getName()+" 加辣椒";    }    @Override    public double getPrice(){        return hum.getPrice(); //辣椒免费    }}

测试

package decorator;public class Test {    public static void main(String[] args) {        Humburger hum = new Chilli(new Lettuce(new ChickenBurger()));        System.out.println(hum.getName());        System.out.println(hum.getPrice());         }}//结果鸡腿堡 加生菜 加辣椒11.5

3. 结构及角色

这里写图片描述

Component:组件对象的接口,可以给这些对象动态的添加职责;

ConcreteComponent:具体的组件对象,实现了组件接口。该对象通常就是被装饰器装饰的原始对象,可以给这个对象添加职责;

Decorator:所有装饰器的父类,需要定义一个与组件接口一致的接口(主要是为了实现装饰器功能的复用,即具体的装饰器A可以装饰另外一个具体的装饰器B,因为装饰器类也是一个Component),并持有一个Component对象,该对象其实就是被装饰的对象。如果不继承组件接口类,则只能为某个组件添加单一的功能,即装饰器对象不能在装饰其他的装饰器对象。

ConcreteDecorator:具体的装饰器类,实现具体要向被装饰对象添加的功能。用来装饰具体的组件对象或者另外一个具体的装饰器对象。

4. 示例2:人的行为的组合

组件接口

package decorator;public interface Human {    public void wearClothes();    public void walk();}

具体实现接口的对象

package decorator;public class Person implements Human{    @Override    public void wearClothes() {        System.out.println("穿什么呢");         }    @Override    public void walk() {        System.out.println("去哪里呢");         }}

装饰器接口(抽象类)

package decorator;public abstract class Decorator implements Human{    protected Human human;    public Decorator(Human human){        this.human = human;    }    public void wearClothes(){        human.wearClothes();    }    public void walk(){        human.walk();    }}

装饰器的具体实现对象A、B、C…

package decorator;public class Decorator_first extends Decorator{    public Decorator_first(Human human) {        super(human);           }    public void goRoom(){        System.out.println("进房子...");    }    public void findMap(){        System.out.println("找地图...");    }    @Override    public void wearClothes(){        super.wearClothes();        goRoom();    }    @Override    public void walk(){        super.walk();        findMap();    }}
package decorator;public class Decorator_two extends Decorator{    public Decorator_two(Human human) {        super(human);    }    public void goClothesPress(){        System.out.println("去衣柜找找...");    }    public void findPlaceOnMap(){        System.out.println("在Map上找找...");    }    @Override    public void wearClothes(){        super.wearClothes();        goClothesPress();    }    @Override    public void walk(){        super.walk();        findPlaceOnMap();    }}
package decorator;public class Decorator_three extends Decorator{    public Decorator_three(Human human) {        super(human);    }    public void findClothes(){        System.out.println("找到一件衣服");    }    public void findTarget(){        System.out.println("找到目的地");    }    @Override    public void wearClothes(){        super.wearClothes();        findClothes();    }    @Override    public void walk(){        super.walk();        findTarget();    }}

测试

package decorator;public class TestHuman {    public static void main(String[] args) {        Human human = new Person();        //链式调用        Decorator decorator = new Decorator_three(                new Decorator_two(new Decorator_first(human)));        decorator.wearClothes();        decorator.walk();    }}//结果穿什么呢进房子...去衣柜找找...找到一件衣服去哪里呢找地图...在Map上找找...找到目的地

5. 何时使用

在以下两种情况下可以考虑使用装饰器模式:

(1)需要在不影响其他对象的情况下,以动态、透明的方式给对象添加职责。(2)如果不适合使用子类来进行扩展的时候,可以考虑使用装饰器模式。

6. java I/O

java中的IO是明显的装饰器模式的运用。FilterInputStreamFilterOutputStreamFilterReadFilterWriter分别为具体装饰器的父类,相当于Decorator类,它们分别实现了InputStreamOutputStreamReaderWriter类(这些类相当于Component,是其他组件类的父类,也是Decorator类的父类)。

继承自InputStreamOutputStreamReaderWriter这四个类的其他类是具体的组件类,每个都有相应的功能,相当于ConcreteComponent类。而继承自FilterInputStreamFilterOutputStreamFilterReadFilterWriter这四个类的其他类就是具体的装饰器对象类,即ConcreteDecorator类。通过这些装饰器类,可以给我们提供更加具体的有用的功能。如FileInputStreamInputStream的一个子类,从文件中读取数据流,BufferedInputStream是继承自FilterInputStream的具体的装饰器类,该类提供一个内存的缓冲区类保存输入流中的数据。我们使用如下的代码来使用BufferedInputStream装饰FileInputStream,就可以提供一个内存缓冲区来保存从文件中读取的输入流。
图解如下:

①组件接口,相当于Component:    InputStream    OutputStream    Reader    Writer②组件的实现类,相当于ConcreteComponent    FileInputStream③装饰器接口,相当于Decorator    FilterInputStream    FilterOutputStream    FilterRead    FilterWriter④装饰器类    BufferedInputStream继承自FilterInputStream使用说明:我们可以用BufferedInputStream修饰FileInputStream

如:

BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); //其中file为某个具体文件的File或者FileDescription对象

再如:

FileWriter file = new FileWriter("sample.txt");BufferedWriter writer = new BufferedWriter(file);writer.write("a small amount of sample text");writer.newLine();writer.close();

特点:上述例子的特点是从一个流组合另一个流。

原创粉丝点击