Builder(建造者)模式

本文深入讲解了建造者模式的基本概念及其应用场景,通过实例演示了如何使用该模式来创建复杂对象,探讨了不同实现方式及其适用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  Builder模式,也叫建造者模式,它将一个复杂对象的构建与它的表示分离,使得同样的创建过程可以创建不同的表示。它是一步一步创建一个复杂对象的创建型模式,允许用户在不知道内部构建细节的情况下,可以更精细的控制对象的构造流程。该模式是为了将构建复杂对象的过程和它的部件解耦,使得构建过程和部件的表示隔离开来。通常一个复杂对象有很多组成部分,就像一辆汽车有很多零件,把这些零件全部装配起来是一个庞大的工程,对于这种情况,为了在构建过程中对外部隐藏实现细节,就可以使用Builder模式将部件与组装分离,使得构建过程和部件都可以自由扩展,两者之间的耦合也降到最低。看完这一段话,其实不太好理解,其实这个设计模式我们都已经接触过,我们熟悉的AlertDialog.Builder就是Builder模式在安卓源码中的典型应用。通过Builder来设置Dialog的标题,Message,确定取消按钮等等,将Dialog的构造与表示分离。
  Builder模式的使用场景:
  (1)相同的方法,不同的执行顺序,产生不同的事件结果时。
  (2)多个部件或零件,都可以装配到一个对象中,但是产生的运 行结果又不相同时。
  (3)产品类非常复杂,或者产品类中的调用顺序不同产生了不同的作用。
  (4)当初始化一个对象特别复杂,如参数多,且很多参数都有默认值。
  
  一个标准的Builder模式一般有下面几个部分:
  Product产品类
  Builder:抽象Builder类,规范产品的组建,一般由子类实现具体的组建过程
  ConcreteBuilder:具体的Builder类
  Director:统一组装过程

  下面我们来看一个典型的Builder模式的工作流程。我们以电脑为例,简单分为三个部分,品牌,大小和操作系统。我们先看一下产品类Computer,和普通的实体类并没有什么区别,一般是一些复杂对象。实际开发中也经常定义出一个抽象产品类,用来继承实现具体的产品类。
  

/**
 * 产品类
 */
public class Computer {

    private String brand;// 品牌

    private String size;// 大小

    private String os;// 操作系统

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getSize() {
        return size;
    }

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

    public String getOs() {
        return os;
    }

    public void setOs(String os) {
        this.os = os;
    }

    public String toString() {
        return "Computer [brand=" + brand + ", size=" + size + ", os=" + os
                + "]";
    }
}

  接着定义一个抽象建造者(Builder)类,当然也可以是接口。它的作用是规范产品类各个部分的建造,同时提供一个方法来返回产品实例。这里的Builder类提供了设置品牌,设置大小,设置操作系统四个抽象方法,还有返回Computer实例的create方法。

/**
 * 抽象Builder类
 */
public abstract class Builder {

    // 设置品牌
    public abstract void setBrand(String brand);

    // 设置大小
    public abstract void setSize(String size);

    // 设置操作系统
    public abstract void setOs(String os);

    //创建Computer
    public abstract Computer create();

}

  我们通过继承Builder类,实现一个具体的ComputerBuilder类,这个具体的建造者类是直接和系统进行交流的,系统调用它来直接创建产品实例。 

/**
 * 具体的Builder类
 */
public class ComputerBuilder extends Builder {

    private Computer mComputer = new Computer();

    public void setBrand(String brand) {
        mComputer.setBrand(brand);
    }

    public void setSize(String size) {
        mComputer.setSize(size);
    }

    public void setOs(String os) {
        mComputer.setOs(os);

    }

    public Computer create() {
        return mComputer;
    }

}

  最后,通过导演(Director)类,调用具体建造者类来创建产品。产品的具体信息并不是导演类所有,而是导演类所持有的具体建造者类所有。 

/**
 * Director类,负责构造Computer
 */
public class Director {

    private Builder mBuilder = null;

    public Director(Builder builder) {
        mBuilder = builder;
    }

    public void construct(String brand, String size, String os) {
        mBuilder.setBrand(brand);
        mBuilder.setSize(size);
        mBuilder.setOs(os);
    }
}

  我们来测试一下,
  

public static void main(String[] a){
        Builder builder=new ComputerBuilder();
        Director director=new Director(builder);
        director.construct("Intel","15.6","Window 10");
        System.out.println(builder.create().toString());
    }

  输出结果是:Computer [brand=Intel, size=15.6, os=Window 10]
  这样,通过具体的Builder对象构建产品类,对象,Director类封装了构造复杂对象的过程,对用户隐藏细节。Builder和Director一起将一个复杂对象的构建和表示分离。当然在现实开发中,我们并不会完全按照上面的形式去使用Builder模式,有时候我们会省略掉Director,直接在产品类中写一个静态的内部Builder类,并让他的setter方法返回this以实现链式调用。什么是链式调用呢,想想最简单的AlertDialog.Builder的使用方法,

new AlertDialog.Builder(this).setTitle("是否退出").setMessage("请选择").setIcon(R.drawable.ic_launcher).create().show();

这样可以直接在后面追加调用方法就是链式调用,一定程度上简化了编码,提高工作效率。下面还是上面电脑的例子,用内部静态Builder类的模式看一下建造者模式的应用。

/**
 * Created by sun on 2016/1/26.
 * 静态内部Builder类
 */
public class Computer2 {

    //产品组成部分
    private String brand;

    private String size;

    private String os;

    //传入Builder对象,进行组成部分的构造
    private Computer2(Builder builder) {
        brand = builder.mBrand;
        size = builder.mSize;
        os = builder.mOs;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getSize() {
        return size;
    }

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

    public String getOs() {
        return os;
    }

    public void setOs(String os) {
        this.os = os;
    }

    @Override
    public String toString() {
        return "Computer2{" +
                "brand='" + brand + '\'' +
                ", size='" + size + '\'' +
                ", os='" + os + '\'' +
                '}';
    }

    //静态内部的Builder类
    public static class Builder {

        private String mBrand;

        private String mSize;

        private String mOs;

        //Builder构造函数,创建Builder类的时候传入一些公共的,或者默认的值
        public Builder(String brand) {
            mBrand = brand;
        }

        /**
         *提供组成部分的建造方法
         * 返回this实现链式调用
         */
        public Builder setSize(String size) {
            mSize = size;
            return this;
        }

        public Builder setOS(String os) {
            mOs = os;
            return this;
        }

        //返回产品实例
        public Computer2 create(){
            return  new Computer2(this);
        }
    }
}

  首先来测试一下这种写法,
  

public static  void main(String[] a){
        Computer2 computer2=new Computer2.Builder("MacBook").setSize("13.3").setOS("OS").create();
        System.out.println(computer2.toString());
    }

打印结果:Computer2{brand='MacBook', size='13.3', os='OS'}
  这种写法省略了Director类,看起来更容易理解一点。在产品类中嵌套一个静态Builder类,我们在产品类的构造函数中传入了Builder类,这样在Builder类中构建好的组成部分就传给了产品类。尽管这样看起来是增加了代码量,但是当产品类组成部分很多,即参数很多的时候,我们可能需要提供不止一种构造函数供外界使用,不同的构造函数在用户看来并不是那么容易看出来区别在哪里,代码可读性很差。而使用Builder模式的话用户就可以很容易的去创建自己需要的不同形式的产品。反之,当参数不多,只需要一个构造器就可以满足用户使用的时候,Builder模式反而是冗余的。
  根据自己的理解Builder模式可以有多种实现方式,万变不离其宗,思想是不会变化的。当我们构建对象时,参数很多,且部分参数有默认值,并不是所有参数都是必须需要的,不同的参数组合可以有不同的对象,或者当需要用多种构造函数来构建不同对象的时候,都可以考虑使用Builder模式,并且要知道Builder模式是建立在成倍增加代码量的基础上的,所以,总会有得不偿失的时候。

示例代码托管地址:https://github.com/lulululbj/JavaDesignPatterns

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值