28 Jul 2014

Java设计模式:生成器模式

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

生成器模式的核心功能是引入了逐步构造事物的过程. 例如: 每个产品的生产都会遵循相同的过程, 即使每一步都是不同的.

在下面的例子中, 我们定义了一个饮料的生成器StarbucksBuilder, 此生成器用于生产Starbucks饮品. StarbucksBuilder在生产饮料过程中包含若干个步骤, 例如buildSize()和buildDrink(), 以及最终返回的饮料.

1. 生成器模式类图

builder-design-pattern

2. 生成器模式的Java样例代码

package designpatterns.builder;

// produce to be built
class Starbucks {
    private String size;
    private String drink;

    public void setSize(String size) {
        this.size = size;
    }

    public void setDrink(String drink) {
        this.drink = drink;
    }
}

//abstract builder
abstract class StarbucksBuilder {
    protected Starbucks starbucks;

    public Starbucks getStarbucks() {
        return starbucks;
    }

    public void createStarbucks() {
        starbucks = new Starbucks();
        System.out.println("a drink is created");
    }

    public abstract void buildSize();
    public abstract void buildDrink();
}

// Concrete Builder to build tea
class TeaBuilder extends StarbucksBuilder {
    public void buildSize() {
        starbucks.setSize("large");
        System.out.println("build large size");
    }

    public void buildDrink() {
        starbucks.setDrink("tea");
        System.out.println("build tea");
    }

}

// Concrete builder to build coffee
class CoffeeBuilder extends StarbucksBuilder {
    public void buildSize() {
        starbucks.setSize("medium");
        System.out.println("build medium size");
    }

    public void buildDrink() {
        starbucks.setDrink("coffee");
        System.out.println("build coffee");
    }
}

//director to encapsulate the builder
class Waiter {
    private StarbucksBuilder starbucksBuilder;

    public void setStarbucksBuilder(StarbucksBuilder builder) {
        starbucksBuilder = builder;
    }

    public Starbucks getstarbucksDrink() {
        return starbucksBuilder.getStarbucks();
    }

    public void constructStarbucks() {
        starbucksBuilder.createStarbucks();
        starbucksBuilder.buildDrink();
        starbucksBuilder.buildSize();
    }
}

//customer
public class Customer {
    public static void main(String[] args) {
        Waiter waiter = new Waiter();
        StarbucksBuilder coffeeBuilder = new CoffeeBuilder();

        //Alternatively you can use tea builder to build a tea
        //StarbucksBuilder teaBuilder = new TeaBuilder();

        waiter.setStarbucksBuilder(coffeeBuilder);
        waiter.constructStarbucks();

        //get the drink built
        Starbucks drink = waiter.getstarbucksDrink();

    }
}

3. 生成器模式的现实应用

生成器模式被广泛应用于多个类库. 然而, 对此有一个普遍的误区. 参考如下样例, StringBuilder是一个JSL中的类. 它是否应用了生成器模式?

StringBuilder strBuilder= new StringBuilder();
strBuilder.append("one");
strBuilder.append("two");
strBuilder.append("three");
String str= strBuilder.toString();

在JSL中, StringBuilder继承于AbstractStringBuilder.

append()方法是类似于Starbucks例子中的一个步骤. toString方法则是过程中的最好一个步骤. 然后, 区别是没有Waiter. Waiter类在生成器模式中饰演了导演的角色. 由于没有这样一个角色, 因此上例并非生成器模式.

当然, 这不是唯一的原因. 你可以比较两者的类图, 从而找出另一个原因.

4. 生成器与工厂模式的区别

生成器模式作用的场景是:通过很多步骤去创建对象. 工厂模式的场景则是: 简单的调用一个方法就可以创建出整个对象.


Tags:
0 comments