设计模式之建造者(Builder)模式

  存在一些情况,比如,一些对象会有一些重要的属性,在这些属性没有恰当的值之前,对象不能作为一个完整的产品使用(如一个电子邮件最起码得有收件人地址);还有一些些情况,一个对象的一些属性必须按照一定的顺序赋值才有意义,在某个属性没有赋值之前,另一个属性则无法赋值。Builder模式非常适用于此种类型的情况。

  (一)什么是Builder模式

  Builder模式是一种对象创建模式,用来隐藏复合对象的创建过程。建造者模式利用一个导演者(Director)对象和具体构造者(Concrete Builder)对象一个一个地建造出所有属性(零件),从而建造出完整的产品对象。建造者模式将产品的结构和产品的零件建造过程对客户端隐藏起来,把对建造过程进行指挥的责任和具体建造者零件的责任分割开来,达到责任划分和封装的目的。

  (二)Builder模式中的角色

  抽象建造者(Builder)角色:给出一个抽象接口,以规范产品对象的各个组成部分的建造。一般此接口独立于应用程序的商业逻辑。这个接口一般包含两种方法,创建方法和返回方法。

  具体建造者(ConcreteBuilder)角色:它必须实现创造者Builder所声明的接口,在创在完成后,提供产品实例。一般来说,每有一个具体产品,就有一个相应的具体建造类。

  导演者(Director)角色:担任这个角色的类调用具体建造者角色以创建产品对象。

  产品(Product)角色:产品就是所建造的复杂对象,一个系统中会有多于一个的产品类,这些产品类并不一定有共同的接口,而完全可以是不相互关联的。导演者角色是与客户端打交道的角色,它将客户端创造产品的请求划分为多个零件的建造请求,再将这些请求委派给具体建造者角色,具体建造者角色是做具体建造工作的。

  Builder模式的结构图如下:

(三)建造者模式的具体实现

  想象一下,有这样一种业务场景:客户端向要建造一所房子 (可以是平房,也可以是公寓),房子由多个组件构成,包括地板、墙和天花板等,从程序的角度出发,能有哪些解决方案呢?

    1)客户端自己创建房子。

    2)客户端委托具体工程队建造房子

    3)客户端寻找设计师,并给设计师配备工程队建造房子 。

  (1)客户端自己建造房子。

  客户端自己创建房子的各个组件,如果建造平房就用相应的平房地板、墙、天花板

      House house = new House();
      house.setFloor("地板");
      house.setWall("墙");
      house.setCeil("天花板");

  (2)客户端委托工程队创建房子

  客户端委托工程队建造房子 ,如果要建造平房,就选择建造平房的工程队,如果建造公寓,就选择建造公寓的工程队。

        HouseBuilder builder = new PingFangBuilder();
builder.makeFloor();
builder.makeWall();
builder.makeCeil();
House pingFang = builder.getHouse();

  貌似这种方式,看起来已经比较完美,有点面向对象的意思。但仍存在缺点,封装不够,房子具体部件的创建仍然暴露在客户端(在这里可以理解为建造房子的时候,还需要需要客户端进行督工),倘若需要满足这样一种对象创建逻辑:必须按照地板、墙、天花板的顺序建造房子,在客户端创建容易出错。此时,这种方式创建对象不能满足要求,第三种方式却能满足。

  (3)客户端寻找设计师,并给设计师配备工程队建造房子

  客户端委托设计师创建房子,房子各个组件的创建顺序可以在设计师中具体指定,具体的建造仍然交给工程队,只要工程队的调度交给设计者,也可以称为管理者。这样设计者就需要一个具体的工程队,可以选择两种方式:1)每个设计师包含一个工程队属性。2)给设计师的相应方法传入一个具体 工程队。在这里我们选择第二种方式。

  以上叙述中,房子扮演者Product的角色,设计师扮演Director角色,工程队扮演Builder角色,而具体工程队(包括平房工程队和公寓工程队)扮演ConcreteBuilder角色。具体代码实现如下:

  1)Product:House

/*
* 房子
*/
public class House {
//地板
private String floor;
//墙
private String wall;
//屋顶
private String ceil;
public String getFloor() {
return floor;
}
public void setFloor(String floor) {
this.floor = floor;
}
public String getWall() {
return wall;
}
public void setWall(String wall) {
this.wall = wall;
}
public String getCeil() {
return ceil;
}
public void setCeil(String ceil) {
this.ceil = ceil;
}
}

  2)抽象建造者:HouseBuilder

public interface HouseBuilder {
//修地板
public void makeFloor();
//修墙
public void makeWall();
//修天花板
public void makeCeil(); //返回房子
public House getHouse();
}

  3)具体建造者:PingFangBuilder、ApartmentBuilder

public class PingFangBuilder implements HouseBuilder {
private House house = new House();
@Override
public void makeFloor() {
house.setFloor("平房---房顶");
} @Override
public void makeWall() {
house.setWall("平房---墙");
} @Override
public void makeCeil() {
house.setCeil("平房---天花板");
} @Override
public House getHouse() {
return house;
}
}
public class ApartmentBuilder implements HouseBuilder {
private House house = new House();
@Override
public void makeFloor() {
house.setFloor("公寓---地板");
} @Override
public void makeWall() {
house.setWall("公寓---墙");
} @Override
public void makeCeil() {
house.setCeil("公寓---天花板");
} @Override
public House getHouse() {
return house;
} }

  4)DIrector:HouseDirector

public class HouseDirector {
public House constructHouse(HouseBuilder builder) {
builder.makeFloor();
builder.makeWall();
builder.makeCeil();
return builder.getHouse();
}
}

  5)Client

HouseBuilder builder1 = new PingFangBuilder();
HouseDirector director1 = new HouseDirector();
House pingFang = director1.constructHouse(builder1); HouseBuilder builder2 = new ApartmentBuilder();
HouseDirector director2 = new HouseDirector();
House apartment = director2.constructHouse(builder2);

  (四)什么情况下使用建造模式

   需要生成的产品对象有复杂的内部结构,。

  需要生成的产品对象的属性相互依赖,即一个属性必须在一个属性被赋值后才可以被赋值。

  在对象创建过程中,会使用系统的其他一些对象,这些对象在产品创建的过程中不易得到。

  (五)抽象工厂模式和Builder模式的区别: 

  二者都是对象创建模式,在抽象工厂模式中,每调用一次工厂对象,都会返回一个完整的产品对象,客户端可能会把这些产品组装成一个更大更复杂的产品,也可能不会。建造者模式则不同,它一点一点地构造出一个复杂的产品,而这个产品的组装过程就发生在建造者角色内部,建造者模式的客户端拿到的是一个完成的产品。

  也就是说,建造者模式处于更加宏观的尺度上,而建造者模式处于更加具体的尺度上。建造者模式所创建产品的零部件可由抽象工厂创建完成。

设计模式之建造者(Builder)模式的更多相关文章

  1. Java设计模式-建造者(Builder)模式

    目录 由来 使用 1. 定义抽象 Builder 2. 定义具体 Builder类 3. 定义具体 Director类 4. 测试 定义 文字定义 结构图 优点 举例 @ 最近在看Mybatis的源码 ...

  2. 设计模式C++描述----07.建造者(Builder)模式

    一. 概述 Builder 模式要解决的问题是:当我们要创建的对象很复杂的时候(通常是由很多其他的对象组合而成),我们要要复杂对象的创建过程和这个对象的表示(展示)分离开 来,这样做的好处就是通过一步 ...

  3. 建造者(Builder)模式

    建造者模式是对象的创建模式.建造模式可以将一个产品的内部表象(internal representation)与产品的生产过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象. 产品的 ...

  4. Android 建造者(Builder)模式

    关于 Builder 模式 详述:http://blog.csdn.net/jjwwmlp456/article/details/39890699 先来张图 看到 Android  中 使用了 Bui ...

  5. 设计模式--建造者(Builder)模式

    将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示                                                         --<设计模 ...

  6. 设计模式之生成器(Builder)模式

    意图 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以表示不同的表示. 适用性 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时. 当构造过程必须允许被构造的对象有不同的表 ...

  7. Builder模式(建造者模式)

    在设计模式中对Builder模式的定义是用于构建复杂对象的一种模式,所构建的对象往往需要多步初始化或赋值才能完成.那么,在实际的开发过程中,我们哪些地方适合用到Builder模式呢?其中使用Build ...

  8. Builder模式在Java中的应用

    在设计模式中对Builder模式的定义是用于构建复杂对象的一种模式,所构建的对象往往需要多步初始化或赋值才能完成.那么,在实际的开发过程中,我们哪些地方适合用到Builder模式呢?其中使用Build ...

  9. Builder模式在Java中的应用(转)

    在设计模式中对Builder模式的定义是用于构建复杂对象的一种模式,所构建的对象往往需要多步初始化或赋值才能完成.那么,在实际的开发过程中,我们哪些地方适合用到Builder模式呢?其中使用Build ...

  10. Java设计模式之建造者模式(Builder)

    前言: 最近一直在学习okHttp,也对其做了一些整理,okHttp和Retrofit结合大大加速我们的开发效率,源码里面采用了很多设计模式,今天我们来学习一下其中的设计模式之一建造者模式. 建造者模 ...

随机推荐

  1. 【Java_多线程并发编程】基础篇—Thread类中start()和run()方法的区别

    1. start() 和 run()的区别说明 start()方法: 它会启动一个新线程,并将其添加到线程池中,待其获得CPU资源时会执行run()方法,start()不能被重复调用. run()方法 ...

  2. vuex其实超简单,只需3步

    前言 之前几个项目中,都多多少少碰到一些组件之间需要通信的地方,而因为种种原因,event bus 的成本反而比vuex还高, 所以技术选型上选用了 vuex, 但是不知道为什么,团队里的一些新人一听 ...

  3. 使用 HTML5 Geolocation 构建基于地理位置的 Web 应用学习网站分享

    HTML5 中的新功能 HTML5 是最新一代的 HTML 规范,是 W3C 与 WHATWG 合作的结果,目前仍外于开发中.自从上一代 HTML4,Web 世界已经发生了巨大的变化,HTML5 的到 ...

  4. 【css】【动画】【转发】旋转动画

    <!DOCTYPE HTML> <html> <head>     <meta charset="utf-8">     <s ...

  5. docker:安装mysql

    文章来源:https://www.cnblogs.com/hello-tl/p/9234429.html 1.添加镜像 docker pull mysql 2.在/data下新建文件夹mysql,进入 ...

  6. (原)剑指offer之栈和队列

    题目描述 用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型. 设两个栈为stack1,stack2: 1:首先想到最简单的方法:是入栈时将数据压入stack1,出栈时 ...

  7. Spring,Mybatis,Springmvc框架整合项目(第二部分)

    一.创建数据库表 打开Navicat Premium,点击左上角连接,选择mysql   输入你的数据库用户名和密码信息,可以先点击下测试连接,如果显示连接成功,说明能连接到数据库,然后点击确定.如果 ...

  8. js-dom-EventUtil

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. .net提高文章

    文章:.NET程序性能的基本要领 文章:你的字典里有多少元素? 文章:快速自检电脑是否被黑客入侵过(Windows版) 文章:关于DNS,你应该知道这些

  10. 【Luogu】P3627抢掠计划(缩点最短路)

    题目链接在此 有环当然一定尽量走环,这是搞缩点的人都知道的常识. 建了新图之后搞点权SPFA跑最长路.枚举每个酒吧选择最大值. 发现我的博客写的越来越水了 #include<cstdio> ...