9 Sep 2014

Java设计模式:装饰器模式

注:本文为译文,原文出处java-design-patterns-in-stories

装饰器模式为已存在的对象动态的添加额外的一些功能. 在这篇文章里, 我会用一个简单的例子 - 装饰你的女友 - 来举例说明装饰器模式的原理.

1.装饰器模式小故事

首先, 假设你正在找一个女朋友. 有很多来自不同国家的女孩, 例如:美国, 中国, 日本, 法国等. 她们有着不同的个性与爱好. 在约会网站例如eharmony.com, 如果每个类型的女孩是一个单独的Java类, 那么可能会有成千上万个类. 这是一个严重的问题, 我们称之为”类爆炸”. 此外, 这种设计也是不可扩展的. 只要有一个新的类型出现, 就需要创建一个新的类.

让我们来改变这种设计, 使每个爱好/个性成为一个装饰器, 并且可以动态关联到女孩上.

2.类图

java-design-pattern-decorator

女孩是一个顶层的抽象类, 我们有来在不同国家的女孩. 通过GirlDecorator类, 就可以利用添加新的装饰器来为女孩装饰任何特性.

3.装饰器模式Java代码

Girl.java

public abstract class Girl {
    String description = "no particular";

    public String getDescription(){
        return description;
    }
}

AmericanGirl.java

public class AmericanGirl extends Girl {
    public AmericanGirl(){
        description = "+American";
    }
}

EuropeanGirl.java

public class EuropeanGirl extends Girl {
    public EuropeanGirl() {
        description = "+European";
    }
}

GirlDecorator.java

public abstract class GirlDecorator extends Girl {
    public abstract String getDescription();
}

Science.java

public class Science extends GirlDecorator {

    private Girl girl;

    public Science(Girl g) {
        girl = g;
    }

    @Override
    public String getDescription() {
        return girl.getDescription() + "+Like Science";
    }

    public void calculateStuff() {
        System.out.println("scientific calculation!");
    }
}

可以给装饰器无限制的添加更多的方法, 例如: “Dance()”.

Art.java

public class Art extends GirlDecorator {

    private Girl girl;

    public Art(Girl g) {
        girl = g;
    }

    @Override
    public String getDescription() {
        return girl.getDescription() + "+Like Art";
    }

    public void draw() {
        System.out.println("draw pictures!");
    }
}

Main.java

package designpatterns.decorator;

public class Main {

    public static void main(String[] args) {
        Girl g1 = new AmericanGirl();
        System.out.println(g1.getDescription());

        Science g2 = new Science(g1);
        System.out.println(g2.getDescription());

        Art g3 = new Art(g2);
        System.out.println(g3.getDescription());
    }
}

输出:

+American
+American+Like Science
+American+Like Science+Like Art

We can also do something like this:

Girl g = new Science(new Art(new AmericanGirl()));

4. 装饰器模式在JSL中的应用

一个典型的装饰器模式的应用就是Java IO.

接下来是一个简单的例子 - BufferedReader 装饰 InputStreamReader.

BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
//System.in is an InputStream object

InputStreamReader(InputStream in) - 字节流转换为字符流的桥梁. InputSteamReader读取字节并通过指定的字符编码将之转换为字符.

BufferedReader(Reader in) - 在字符流中读取文本并缓冲字符, 从而提供高效的读取方法(例如: readLine()).


Tags:
0 comments