建造者模式(Builder)

建造者模式是用来解决产品对象的创建过程是由多个零件组成的情况,这些零件与产品本身是组合关系,也就是部分与整体,这些零件的创建顺序,还有一些创建中的逻辑,都是稳定的,可以封装起来的.

例如,一个邮件对象,要成功的使用前,需要设置主题,收件人,发件人,正文,附件等零件,这些零件都与邮件对象是组合关系,如果将这些创建逻辑散落在调用处,每次使用邮件对象时都要进行繁琐的装配零件工作,而且还有可能会有一定的业务逻辑掺在这其中.

建造者模式除了将构建产品零件的算法封装起来,还可以支持消费的产品对象的动态选择,当然这也是面向对象不变的话题,封装变化点,依赖倒置.具体产品是一个对象还是一系列,这个根据实际的业务设计有所不同.

在上图中展示了一个基础的建造者模式的结构,为了尽量说明实际情况的模式环境,我们这里描绘了一个系列的产品对象.红色字体部分代表的是实现层,也就是依赖倒置原则中所讲的,不依赖实现,而依赖抽象.这里的实现层在系统中肯定是频繁变化的,而且可以随时以扩展的方式改变功能(开闭原则),而蓝色表示的是系统中的抽象层,要求是稳定的,不太能够应对频繁的功能变化.

产品对象

先从产品类来讲起,这一块通常是核心的业务骨架,对于一组产品对象,现实系统中肯定比这里的结构还要复杂,读者视自身业务情况来设计,在上图中,Product代表的是抽象产品接口,这个接口描述依赖着ProductPart,ProductPart2两个抽象的零件.这之间的关系是组合关系,换言之,就是Product的生成是需要先创建ProductPart与ProductPart2两个零件.具体的实现零件则是ConcretePart与ConcretePart2两个类来完成. ConecreteProduct是产品的具体实现类.

可以看出,红色部分的几个Conecrete开头的类,都是可以应对系统变化的,也就是我们随时可以加入ConecretePratXX 或者 ConecreteProductXXX这样的新的实现来丰富我们的系统.

封装产品的创建过程

在介绍完上边的产品结构之后,我们应该了解到Product是依赖着ProductPart与ProductPart2这两个零件的,建造者模式要封装的是这个对象的创建过程,比如:先创建Part1再创建part2,或者说part2的必须是10个以上.这就是对创建算法的封装.

Builder是抽象的建造者,其中描述buildPart()与buildPart2()两个方法分别构建不同的零件.getProduct()返回最终的产品对象Product.

ConcreteBuilder是具体的构建实现,这里与ConcretePart,ConcretePart2两个具体零件对象是关联着的,如果加入新的一套不同风格的零件,则也相应的要增加XXXConcreteBuilder,当然,如果我们很确定系统只有一种风格,那大哥不必将Builder抽象化.

Director是一个导演类,用为将具体稳定的创建算法封装在这里,比如刚才所讲的,要求创建10个Part2对象.

最后我们来看Client类,这里是指代码调用处,依赖着产品的抽象层,完全不关心具体层,在调用时只需要选择不同的ConcreteBuilder就可以完成不同风格产品的组装过程.值得说明的一点,风格是指加入不同的实现类,比如再加一套新风格,就需要加入新的派生自Product , ProductPart , ProductPart2 ,Builder的几个实现类.

具体举例说明

写到这里,也不免俗套的要举一个其实和实际开发相距甚远,还有些套路化的例子了,虽然园子里关于设计模式的文章如汗牛充栋,也有很多口号讲,不要重复搞轮子.但小弟还是认为,搞轮子和写这些文章对个人的提高是很大的,同时也能在过程中得到与别人的互动交流,设计模式本来就还有一层意思,那就是交流.我们大家都约定俗成,交流起来就更方便了不是吗,好了,各们大哥,我可以开始了吗?

假如我们有一个游戏场景,需要一个房屋,这个房屋由多面墙壁,一块地板,一块天花板组成.我们很自然的可以写出房屋,墙壁,地板,天花板对象,而且房屋与其它对象是组合关系,表现在代码中应该就是成员变量.

由于系统要求房屋有着不同的风格,比如一款普通风格,另一款精致风格.这时我们很自然的应该将房屋,地板,天花板,墙壁都抽象化.这些对象就对应前面所讲的产品结构.


package com.j2kaka.coolka.examples.pattern.builder;

/**
 * 抽象房顶
 *
 * @author aladdinty
 * @create 2018-01-10
 **/
public abstract  class AbsRoof
{
    public abstract  String getRoofInfo() ;
}

package com.j2kaka.coolka.examples.pattern.builder;

/**
 * 抽象墙壁
 *
 * @author aladdinty
 * @create 2018-01-10
 **/
public abstract  class AbsWall
{
    public abstract String getWallInfo() ;
}

package com.j2kaka.coolka.examples.pattern.builder;

/**
 * 抽象地板
 *
 * @author aladdinty
 * @create 2018-01-10
 **/
public abstract class AbsFloor
{
    public abstract  String getFloorInfo() ;
}

package com.j2kaka.coolka.examples.pattern.builder;

import java.util.ArrayList;
import java.util.List;

/**
 * 抽象的房子类
 * @author aladdinty
 * @create 2018-01-10
 **/
public abstract  class AbsHouse
{
    private List<AbsWall> wallList ;
    private AbsFloor floor ;
    private AbsRoof roof ;

    /**添加墙壁*/
    public void addWall (AbsWall wall)
    {
        if( this.wallList == null )
        {
            this.wallList = new ArrayList<AbsWall> () ;
        }

        this.wallList.add ( wall ) ;
    }

    /**设置地板*/
    public void setFloor( AbsFloor floor )
    {
        this.floor = floor ;
    }

    /**设置天花板*/
    public  void setRoof( AbsRoof roof )
    {
        this.roof = roof ;
    }

    /**获取天花板*/
    public AbsRoof getRoof ()
    {
        return roof;
    }

    /**获取地板*/
    public AbsFloor getFloor ()
    {
        return floor;
    }

    /**获取所有墙壁*/
    public List<AbsWall> getAllWall ()
    {
        return wallList;
    }

    public String getInfo()
    {
        StringBuffer sb = new StringBuffer () ;

        for( AbsWall wall : this.wallList )
        {
            sb.append ( wall.getWallInfo () + "|") ;
        }

        return "房子的配置是这样的:" + "有几面墙:" + wallList.size () + "->" + sb.toString () + "->"+this.roof.getRoofInfo () +"->" + this.floor.getFloorInfo () ;
    }
}

好抽象层的产品描述完成了,具体产品要有对应的实现了,这里分别提供普通款与精致款风格的不同实现.

package com.j2kaka.coolka.examples.pattern.builder;

/**
 * 普通地板
 *
 * @author aladdinty
 * @create 2018-01-10
 **/
public class CommonFloor extends AbsFloor
{
    @Override
    public String getFloorInfo ()
    {
        return "普通地板";
    }
}

package com.j2kaka.coolka.examples.pattern.builder;

/**
 * 普通天花板
 *
 * @author aladdinty
 * @create 2018-01-10
 **/
public class CommonRoof extends AbsRoof
{
    @Override
    public String getRoofInfo ()
    {
        return "普通天花板";
    }
}

package com.j2kaka.coolka.examples.pattern.builder;

/**
 * 普通风格的墙面
 *
 * @author aladdinty
 * @create 2018-01-10
 **/
public class CommonWall extends AbsWall
{
    @Override
    public String getWallInfo ()
    {
        return "普通墙面";
    }
}

package com.j2kaka.coolka.examples.pattern.builder;

import java.util.ArrayList;
import java.util.List;

/**
 * 普通房子风格实现
 *
 * @author aladdinty
 * @create 2018-01-10
 **/
public class CommonHouseImpl extends  AbsHouse
{
}

再来一款精致款式实现

package com.j2kaka.coolka.examples.pattern.builder;

/**
 * 精致地板
 *
 * @author aladdinty
 * @create 2018-01-10
 **/
public class FinesseFloor extends AbsFloor
{
    @Override
    public String getFloorInfo ()
    {
        return "精致地板";
    }
}

package com.j2kaka.coolka.examples.pattern.builder;

/**
 * 精致天花板
 *
 * @author aladdinty
 * @create 2018-01-10
 **/
public class FinesseRoof extends AbsRoof
{
    @Override
    public String getRoofInfo ()
    {
        return "精致天花板";
    }
}

package com.j2kaka.coolka.examples.pattern.builder;

/**
 * 精致的的墙面
 *
 * @author aladdinty
 * @create 2018-01-10
 **/
public class FinesseWall extends AbsWall
{
    @Override
    public String getWallInfo ()
    {
        return "精致墙面";
    }
}

package com.j2kaka.coolka.examples.pattern.builder;

/**
 * 精致风格实现
 *
 * @author aladdinty
 * @create 2018-01-10
 **/
public class FinesseHouseImpl extends  AbsHouse
{
}

现目前为止,我们实现了产品的抽象化,不过还没体现出建造者模式的核心,我们开头就说过,要封装的是建造过程,同时可以动态选择产品的不同实现.让客户端毫不知情,下面代码中抽象的构建器描述我们的产品创建过程中用到的动作.最后要求返回房屋对象.

package com.j2kaka.coolka.examples.pattern.builder;

/**
 * 抽象建造者
 *
 * @author aladdinty
 * @create 2018-01-10
 **/
public abstract  class AbsBuilder
{
    public abstract void buildFloor() ;
    public abstract void buildRoof() ;
    public abstract void buildWall() ;
    public abstract AbsHouse getHouse() ;
}

具体实现不同的构建器,因为我们这个举例中有2套风格,分别是普通与精致风格,产品结构也有了相应的抽象体现,所以Builder的实现也是一一对应的.在这两个具体实现类里边,都是直接关联了具体的对象产品.

package com.j2kaka.coolka.examples.pattern.builder;

/**
 * 普通风格的构建器实现
 *
 * @author aladdinty
 * @create 2018-01-10
 **/
public class CommonBuilderImpl extends AbsBuilder
{
    private AbsHouse house = new CommonHouseImpl () ;

    @Override
    public void buildFloor ()
    {
        house.setFloor ( new CommonFloor ());
    }

    @Override
    public void buildRoof ()
    {
        house.setRoof ( new CommonRoof ());
    }

    @Override
    public void buildWall ()
    {
        house.addWall ( new CommonWall () );
    }

    @Override
    public AbsHouse getHouse ()
    {
        return this.house;
    }
}

package com.j2kaka.coolka.examples.pattern.builder;

/**
 * 精致风格房屋构建器实现
 *
 * @author aladdinty
 * @create 2018-01-10
 **/
public class FinesseBuilderImpl extends AbsBuilder
{
    private AbsHouse house = new FinesseHouseImpl () ;

    @Override
    public void buildFloor ()
    {
        house.setFloor ( new FinesseFloor ());
    }

    @Override
    public void buildRoof ()
    {
        house.setRoof ( new FinesseRoof ());
    }

    @Override
    public void buildWall ()
    {
        house.addWall ( new FinesseWall () );
    }

    @Override
    public AbsHouse getHouse ()
    {
        return this.house;
    }
}

好了,构建器完成了,产品对象也完成了,现在到我们的工头出场了,他一声令下,给我盖..这里的工具其实是对应之前结构中的Director类,将稳定的对象结构创建步骤和算法封装起来,我们这里简单要求,要有4面墙壁,还有一个地板和一个天花板.

```package com.j2kaka.coolka.examples.pattern.builder;

/**

  • 工队领头人
  • 这个类中代表的是稳定的构建算法,是不能适应频繁变化的.
  • @author aladdinty
  • @create 2018-01-10

    **/

    public class Foreman

    {

    public static AbsHouse createMyHouse( AbsBuilder builder )

    {

    //先盖地板
    builder.buildFloor ();
    
    //接着修建四面墙壁
    for (int i = 0; i < 4; i++)
    {
        builder.buildWall ();
    }
    
    //把房顶盖上..
    builder.buildRoof ();
    
    return builder.getHouse () ;

    }

    }


最后我们看看调用处

package com.j2kaka.coolka.examples.pattern.builder;

/**

  • 调用处代码
  • @author aladdinty
  • @create 2018-01-10

    **/

    public class Client

    {

    public static void main(String[] args )

    {

    AbsHouse house = Foreman.createMyHouse ( new FinesseBuilderImpl () ) ;

    System.out.println ( house.getInfo ());

    AbsHouse house2 = Foreman.createMyHouse ( new CommonBuilderImpl () ) ;
    System.out.println ( house2.getInfo ());

    }

    }

```

其实忙活了半天,只是为调用处以后可以应对变化时不做调整,变化全部封在了后面的结构中.在这里只需要知道产品的抽象接口,调用工头类,决定使用哪种风格的构建器就可以了.

好了,欢乐时光总是过的特别快,感谢您能看到这里,希望我的付出可以给您带来一点点的帮助,如果不爽请轻虐,如果疑问欢迎留言交流

建造者模式(Builder)-宏观的使用角度的更多相关文章

  1. 【原】iOS设计模式之:建造者模式Builder Pattern,用于改进初始化参数

    本文主要讨论一下iOS中的Builder Pattern.与网上很多版本不同,本文不去长篇大论地解释建造者模式的概念,那些东西太虚了.设计模式这种东西是为了解决实际问题的,不能为了设计模式而设计模式, ...

  2. iOS设计模式之:建造者模式Builder Pattern,用于改进初始化参数

    转自:http://www.cnblogs.com/wengzilin/p/4365855.html 本文主要讨论一下iOS中的Builder Pattern.与网上很多版本不同,本文不去长篇大论地解 ...

  3. 乐在其中设计模式(C#) - 建造者模式(Builder Pattern)

    原文:乐在其中设计模式(C#) - 建造者模式(Builder Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 建造者模式(Builder Pattern) 作者:webabc ...

  4. 【设计模式】建造者模式 Builder Pattern

    前面学习了简单工厂模式,工厂方法模式以及抽象工厂模式,这些都是创建类的对象所使用的一些常用的方法和套路, 那么如果我们创建一个很复杂的对象可上面的三种方法都不太适合,那么“专业的事交给专业人去做”,2 ...

  5. 建造者模式(Builder Pattern)

    建造者模式(Builder Pattern) 它可以将多个简单的对象一步一步构建成一个复杂的对象. 意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示. 主要解决:主要解决在软 ...

  6. 二十四种设计模式:建造者模式(Builder Pattern)

    建造者模式(Builder Pattern) 介绍将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 示例用同样的构建过程创建Sql和Xml的Insert()方法和Get()方 ...

  7. 建造者模式(Builder)——从组装电脑开始

    建造者模式(Builder)--从组装电脑开始 建造者模式概括起来就是将不同独立的组件按照一定的条件组合起来构成一个相对业务完整的对象.调用者无需知道构造的过程. 我们从组装电脑开始 让我们从买组装电 ...

  8. 设计模式—建造者模式(Builder)

    title: 设计模式-建造者模式 建造者模式(Builder)是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节.建造者模式属于对 ...

  9. 设计模式系列之建造者模式(Builder Pattern)——复杂对象的组装与创建

    说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...

随机推荐

  1. cronlog分割tomcat catalina.out日志

    Tomcat 下日志文件 catalina.out 过大,几百兆或几个G,进而造成再也无法写入更多的日志内容,至使 Tomcat 无法处理请求,所以依靠cronlog来分割: 具体步骤如下: 1.安装 ...

  2. hdu 5288||2015多校联合第一场1001题

    pid=5288">http://acm.hdu.edu.cn/showproblem.php?pid=5288 Problem Description OO has got a ar ...

  3. Java中File的使用

    File 代表文件或者目录的类 构造函数 File(File parent,String child)---代表了指定父目录下的指定的子文件或者子目录 File(String pathname)--- ...

  4. 自学Zabbix3.9.2-模板Templates-linking/unlinking

    自学Zabbix3.9.2-模板Templates-linking/unlinking HOST链接模板之后,便继承了模板里定义的item,trigger等等,使用这个方法,配置zabbix监控会减少 ...

  5. jsp中EL表达式不起作用的问题1

    问题:在jsp页面中使用el表达式取值,取不到值,但是使用jsp中嵌套java代码可以取到值,对应代码如下: 解决: 只要在 jsp中 头文件中写上 : <%@page isELIgnored= ...

  6. 腾讯WeTest《2017中国移动游戏质量白皮书》开放预约,再为国内手游把把脉

    产品为王,质量先行.如果说2016年是爆款手游相继崛起的一年,那么2017年则更像是打磨精品.建立生态的高手切磋之年.守住一个游戏的质量生命线,方能建立健康生态,方能在如火如荼的行业竞争中角逐到最后. ...

  7. nginx日常维护常用命令

    http://www.jb51.net/article/47750.htm 一.简明nginx常用命令 1. 启动 Nginx poechant@ubuntu:sudo ./sbin/nginx 2. ...

  8. Android Studio 提示android.support.v4不存在的解决方法

    最近想学习仿QQ列表的侧滑删除功能,看完资料之后,发现有一堆错误,看了一下,说是不存在android.support.v4包不存在,浪费了一个多小时,终于是找到了解决方法,便是记录下来 打开file- ...

  9. plugins/python/uwsgi_python.h:2:20: fatal error: Python.h: No such file or directory

    装一台新服务器环境的时候,装uwsgi报错: plugins/python/uwsgi_python.h:2:20: fatal error: Python.h: No such file or di ...

  10. 506. Relative Ranks

    Given scores of N athletes, find their relative ranks and the people with the top three highest scor ...