浅谈建造者模式

建造者模式

  建造者模式就是将一个个简单的对象一步步构建成一个复杂的对象。
  我们生活中有很多可以用建造者模式来解释。譬如在生产汽车的流水线作业中,我们需要先将生产汽车所需的一个一个的内部构建建造出来,例如发动机,车门,车轮,方向盘,水箱等。对于我们用户来说,我们并不需要知道这个汽车是怎么建造出来的,各个部件是怎么组装的,销售人员也不需要知道这个汽车是怎么组装建造的,我们只需要知道这是一辆汽车,我们可以销售和使用就行了,对于销售人员只需要知道客户需要什么样的汽车,他告诉建造者模式中的指挥者去生产对应的车就可以了,哈哈哈,这都是工业4.0了;同样,我们看一个简单的例子,在一家快餐店中,服务员也不需要知道厨师是怎么炒菜和做饭的,她只需要告诉厨师客户需要什么样的套餐类型就可以了。像这样,建造者返回给客户一个完整的的产品对象,而客户端无须关心该对象所包含的额属性和组建方式,这就是建造者模式的设计动机。
  定义:建造者模式将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。
  建造者模式主要包含四个角色:
抽象建造者(Builder): 它声明为创建一个产品对象的各个部件指定的抽象接口,在该接口中一般声明两类方法,一类方法是buildPartX(),它们用于创建复杂对象的各个部件;另一类方法是getResult(),它们用于返回复杂对象。Builder既可以是抽象类,也可以是接口,
具体建造者(ConcreteBuilder): 实现抽象建造者接口,构建和装配各个部件,定义并明确它所创建的复杂对象,也可以提供一个方法返回创建好的复杂产品对象。
指挥者(Director): 它负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系,可以在其construct()建造方法中调用建造者对象的部件构造与装配方法,完成复杂对象的建造。客户端一般只需要与指挥者进行交互,在客户端确定具体建造者的类型,并实例化具体建造者对象(也可以通过配置文件和反射机制) ,然后通过指挥者类的构造函数或者Setter方法将该对象传入指挥者类中。它主要是用于创建一个复杂的对象,它主要有两个作用,一是:隔离了客户与对象的生产过程,二是:负责控制产品对象的生产过程。
产品(Product): 产品角色,一个具体的产品对象。
  我们看下代码实现:
第一步,创建一个产品Meal,由两个元素组成,主食staple和饮料drink。

package builder;

// 产品角色Meal,由两个元素组成,主食staple和饮料drink
public class Meal {

    private String staple;
    private String drink;

    public String getStaple() {
        return staple;
    }

    public void setStaple(String staple) {
        this.staple = staple;
    }

    public String getDrink() {
        return drink;
    }

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

    @Override
    public String toString() {
        return "Meal{" +
                "staple='" + staple + '\'' +
                ", drink='" + drink + '\'' +
                '}';
    }
}

第二步,创建一个抽象建造者类MealBuilder,包含建造各个元件的build方法和返回建造对象的getResult。

package builder;

//抽象建造者,包含建造各个元件的build方法和返回建造对象的getResult
public abstract class MealBuilder {

    Meal meal = new Meal();

    //必须是public,用于让派生的具体建造对象在指挥者类中调用
    public Meal getResult() {
        return meal;
    }

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

第三步,创建两个具体的建造者对象ConcreteMealA,ConcreteMealB继承自MealBuilder,并实现MealBuilder中的抽象方法。

package builder;

//具体的建造对象A,汉堡+可乐
public class ConcreteMealA extends MealBuilder {
    @Override
    public void buildStaple() {
        meal.setStaple("Burger");
    }

    @Override
    public void buildDrink() {
        meal.setDrink("Coca-Cola");
    }
}
package builder;

//具体的建造对象B,pizza+奶茶
public class ConcreteMealB extends MealBuilder {
    @Override
    public void buildStaple() {
        meal.setStaple("Pizza");
    }

    @Override
    public void buildDrink() {
        meal.setDrink("Milk Tea");
    }
}

第四步,创建一个指挥者类Waiter,负责实例化MealBuilder。

package builder;

// 指挥者类,负责创建对象的次序,实例化创建对象
public class Waiter {

    private String name;

    private MealBuilder mealBuilder;

    public void setMealBuilder(MealBuilder mealBuilder) {
        this.mealBuilder = mealBuilder;
    }

    public Meal construct() {
        mealBuilder.buildStaple();
        mealBuilder.buildDrink();
        return mealBuilder.getResult();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

第五步,测试。

package builder;

public class BuilderTest {
    public static void main(String[] args) {
        //叫了一个名为lisa的服务员
        Waiter waiter = new Waiter();
        waiter.setName("Lisa");
        //实例化一个我们所需的A类具体套餐产品
        MealBuilder mealBuilder = new ConcreteMealA();
        //将我们所需A类套餐产品实例传给服务员对象
        waiter.setMealBuilder(mealBuilder);

        Meal meal = waiter.construct();
        System.out.println("waiter: " + waiter.getName() + " prepares a meal for you, meal is " + meal);
    }
}

第六步,输出。

waiter: Lisa prepares a meal for you, meal is Meal{staple='Burger', drink='Coca-Cola'}

  总结,建造者模式很像我们在KFC中点餐模式,我们告诉服务员我们需要什么套餐,服务员根据我们的需求去那对应的套餐给我们,复杂的套餐是怎么做出来的,我们并不需要知道,在建造者模式中已经帮我们实现了,建造者模式和工厂模式很相似。总体上,建造者模式仅仅只比工厂模式多了一个“导演类”的角色。在建造者模式的类图中,假如把这个导演类看做是最终调用的客户端,那么图中剩余的部分就可以看作是一个简单的工厂模式了。但是建造者模式返回一个完整的复杂产品,而抽象工厂模式返回一系列相关的产品;在抽象工厂模式中,客户端通过选择具体工厂来生成所需对象,而在建造者模式中,客户端通过指定具体建造者类型并指导Director类如何去生成对象,侧重于一步步构造一个复杂对象,然后将结果返回。如果将抽象工厂模式看成一个汽车配件生产厂,生成不同类型的汽车配件,那么建造者模式就是一个汽车组装厂,通过对配件进行组装返回一辆完整的汽车。
优点:
(1) 在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
(2) 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。由于指挥者类针对抽象建造者编程,增加新的具体建造者无须修改原有类库的代码,系统扩展方便,符合“开闭原则”
(3) 可以更加精细地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。
缺点:
(1) 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,例如很多组成部分都不相同,不适合使用建造者模式,因此其使用范围受到一定的限制。
(2) 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大,增加系统的理解难度和运行成本。
使用场景:
(1) 需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员属性。
(2) 需要生成的产品对象的属性相互依赖,需要指定其生成顺序。
(3) 对象的创建过程独立于创建该对象的类。在建造者模式中通过引入了指挥者类,将创建过程封装在指挥者类中,而不在建造者类和客户类中。
(4) 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。

优点,缺点,使用场景都是摘自《Java设计模式》一书

猜你喜欢

转载自blog.csdn.net/rajayu/article/details/85246231