04 设计模式自学笔记(Java)-建造者模式Builder[创建型模式]

一、建造者模式的本质

建造者模式的本质:一是封装/隐藏具体类实例对象的创建过程,这一点与工厂模式一样,因为毕竟建造者模式也是属于创建型模式;二是支持复杂对象的创建过程,同时对对象的创建过程进行灵活的定制化。

二、建造者模式目的

将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示,即使用同样的构建过程创建出不同的对象,这样对于客户端/使用者来说就不需要了解复杂的构建过程,只需要关注最终构建出来的对象是否满足要求即可。

三、示例场景

某个理财网站可提供理财产品售卖服务,用户下单后,系统后台需要生成购买人信息、理财产品合同、售卖方信息、理财经纪人信息等,按照监管部门要求,每家公司都需要先确定用户资质(即生成购买人信息,以确认资质),然后确定理财经纪人资质,然后依次生成合同和售卖方信息(这里假设为银行)。

注意事项:1)监管部门可能对监管要求有调整;2)每家公司可能会频繁发布新产品。

四、代码实现及对比

产品类定义,定义了产品属性。

public class Product {
    //具体产品类
    //产品中包含buyer和contract两个属性
    String buyer;
    String contract;

    public String getBuyer() {
        return buyer;
    }

    public void setBuyer(String buyer) {
        this.buyer = buyer;
    }

    public String getContract() {
        return contract;
    }

    public void setContract(String contract) {
        this.contract = contract;
    }

    @Override
    public String toString() {
        return "Product{" +
                "buyer=" + buyer +
                ", contract=" + contract +
                '}';
    }
}

抽象建造者类定义,定义了建造者需要实现的具体建造方法和产出物(即具体的产品类实例对象)。

public interface IProductBuilder {
    
    public void buildBuyer();
    public void buildContract();
    public Product getProduct();
}

具体建造者A类定义,实现了抽象建造者的建造方法。

public class ConcreteBuilderA implements IProductBuilder {

    Product product = new Product();
    @Override
    public void buildBuyer() {
        product.setBuyer("Alice");
        System.out.printf( "Alice: Buyer build complete.\n");
    }

    @Override
    public void buildContract() {
        product.setContract("This is the contract for Alice.");
        System.out.printf( "Alice: Contract build complete.\n");
    }

    @Override
    public Product getProduct() {
        return product;
    }
}

具体建造者B类定义,实现了抽象建造者的建造方法。

public class ConcreteBuilderB implements IProductBuilder {

    Product product = new Product();
    @Override
    public void buildBuyer() {
        product.setBuyer("Bob");
        System.out.printf( "Bob: Buyer build complete.\n");
    }

    @Override
    public void buildContract() {
        product.setContract("This is the contract for Bob.");
        System.out.printf( "Bob: Contract build complete.\n");
    }

    @Override
    public Product getProduct() {
        return product;
    }
}

指挥者类定义,针对具体建造者对象,指定了具体建造者的建造流程,通过一个建造方法实现。

public class Director {
    //Director定义了具体建造者需要执行的建造流程
    //具体建造者按照Director定义的流程进行建造,并通过自己的getProduct()方法交付一个具体产品类对象实例给Director
    public Product build(IProductBuilder iProductBuilder){
        iProductBuilder.buildBuyer();
        iProductBuilder.buildContract();
        return iProductBuilder.getProduct();
    }
}

客户端类定义,客户端创建一个具体建造者类实例对象和一个指挥者类对象实例,然后将具体的产品建造交给指挥者类实例对象实现。

public class Client {
    public static void main(String[] args) {
        //首先,客户端创建一个具体建造者类对象
        IProductBuilder iProductBuilder = new ConcreteBuilderA();
        //其次,客户端创建一个指挥者类对象
        Director director = new Director();
        //然后,将具体建造者对象作为参数交给指挥者类对象,由指挥者类指挥具体建造者类去完成产品对象的创建,如流程的定制等
        Product product = director.build(iProductBuilder);
        System.out.println(product);
    }
}

五、建造者模式的UML类图

(1)UML类图

建造者模式UML类图.png

建造者模式中的角色如下:

1)抽象建造者,声明在所有子类生成器中通用的产品构造步骤,如上图中的IBuilder;

2)具体建造者:供构造过程的不同实现,也可以构造不遵循通用接口的产品,如上图中的ConcreteBuilderA和ConcreteBuilderB;

3)产品:最终生成的产品对象,如上图中的Product;

4)指挥者:定义调用构造步骤的顺序,这样就可以创建和复用特定的产品配置,如上图中的Director。

(2)实现要点

建造者模式(附说明).png

1)抽象建造者-IBuilder,创建一个Product,提供Product响应元素的建造方法,需要提供Product对外提供的方法;

2)具体建造者-ConcreteBuilderA和ConcreteBuilderB:根据不同的构建者实现抽象建造者定义的方法;

3)产品-Product:需要定义最终产品的属性,也就定义了建造者可以建造的具体元素;

4)指挥者-Director:提供Product建造流程,并根据客户端制定的具体建造者来指挥具体建造者按照流程进行Product的建造。

此外,客户端需要创建具体建造者和指挥者,并通过指挥者的建造方法参数将具体建造者指定给指挥者。

六、建造者模式的优缺点

(1)优点

  • 封装性好,使用建造者模式可以使客户端不必知道产品内部组成的细节。
  • 建造者类之间相互独立,容易扩展,对系统的扩展非常有利。
  • 便于控制细节风险 由于具体的建造者类是独立的,因此可以对建造过程逐步细化,而不对其他的模块产生任何影响。

(2)缺点

  • 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,例如很多组成部分都不相同,不适合使用建造者模式,因此其使用范围受到一定的限制。
  • 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大,增加系统的理解难度和运行成本。

适用场景

  • 需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员属性。
  • 需要生成的产品对象的属性相互依赖,需要指定其生成顺序。
  • 对象的创建过程独立于创建该对象的类。在建造者模式中通过引入了指挥者类,将创建过程封装在指挥者类中,而不在建造者类和客户类中。
  • 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,029评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,238评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,576评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,214评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,324评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,392评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,416评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,196评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,631评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,919评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,090评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,767评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,410评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,090评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,328评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,952评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,979评论 2 351

推荐阅读更多精彩内容