一、建造者模式概述

建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

二、建造者模式结构与实现

2.1 建造者模式结构

建造者模式包含以下4个角色:

  1. Builder(抽象建造者):它为创建一个产品对象的各个部件指定抽象接口,在该接口中一般声明两类方法,一类方法是buildPartX(),它们用于创建复杂对象的各个部件;另一类方法是getResult(),它们用于返回复杂对象。Builder可以是抽象类,也可以是接口。
  2. ConcreteBuilder(具体建造者):它实现了Builder接口,实现各个部件的具体构造和装配方法,定义并明确所创建的复杂对象,还可以提供一个方法返回创建好的复杂产品对象。
  3. Product(产品):它是被创建的复杂对象,包含多个组成部件,具体建造者创建该产品的内部表示并定义它的装配过程。
  4. Director(指挥者):它负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系,可以在construct()建造方法中调用建造者对象的部件构造与装配方法,完成复杂对象的建造。客户端一般只需要与指挥者进行交互,在客户端确定具体建造者的类型,并实例化具体建造者对象,然后通过指挥者类的构造函数或者Setter方法将该对象传入指挥者类中。

3.2 建造者模式的实现

用一个练习的demo来举个栗子:

复杂产品对象的代码:

/*** 视频播放软件实体model*/
public class VideoPlayer {private String menu;//菜单private String playlist;//播放列表private String mainWindow;//主窗口private String controlStrip;//控制条private String favoritesList;//收藏列表public String getMenu() {return menu;}public void setMenu(String menu) {this.menu = menu;}//getset方法省略...}

抽象建造者的代码:

/*** 抽象建造者*/
public abstract class VideoPlayerBuilder {protected VideoPlayer videoPlayer = new VideoPlayer();public abstract void  buildMenu();public abstract void  buildPlaylist();public abstract void  buildMainWindow();public abstract void  buildControlStrip();public abstract void  buildFavoritesList();//钩子方法,用于区分是什么模式,子类可以重新此方法public String getModelType(){return "";}public VideoPlayer createVideoPlayer(){return videoPlayer;}
}

具体建造者的代码:

/*** 完整模式*/
public class FullPlayerBuilder extends VideoPlayerBuilder{@Overridepublic void buildMenu() {System.out.println("主模式-菜单");}@Overridepublic void buildPlaylist() {System.out.println("主模式-播放列表");}@Overridepublic void buildMainWindow() {System.out.println("主模式-主窗口");}@Overridepublic void buildControlStrip() {System.out.println("主模式-控制条");}@Overridepublic void buildFavoritesList() {}@Overridepublic String getModelType() {return "full";}
}/*** 记忆模式*/
public class MemoryPlayerBuilder extends VideoPlayerBuilder{@Overridepublic void buildMenu() {}@Overridepublic void buildPlaylist() {}@Overridepublic void buildMainWindow() {System.out.println("记忆模式-主窗口");}@Overridepublic void buildControlStrip() {System.out.println("记忆模式-控制条");}@Overridepublic void buildFavoritesList() {System.out.println("记忆模式-收藏列表");}@Overridepublic String getModelType() {return "memory";}
}/*** 网络模式*/
public class NetworkPlayerBuilder extends VideoPlayerBuilder{@Overridepublic void buildMenu() {System.out.println("网络模式-菜单");}@Overridepublic void buildPlaylist() {System.out.println("网络模式-播放列表");}@Overridepublic void buildMainWindow() {System.out.println("网络模式-主窗口");}@Overridepublic void buildControlStrip() {System.out.println("网络模式-控制条");}@Overridepublic void buildFavoritesList() {System.out.println("网络模式-收藏列表");}@Overridepublic String getModelType() {return "network";}
}/*** 精简模式*/
public class StreamlinePlayerBuilder extends VideoPlayerBuilder{@Overridepublic void buildMenu() {}@Overridepublic void buildPlaylist() {}@Overridepublic void buildMainWindow() {System.out.println("精简模式-主窗口");}@Overridepublic void buildControlStrip() {System.out.println("精简模式-控制条");}@Overridepublic void buildFavoritesList() {}@Overridepublic String getModelType() {return "streamline";}
}

指挥者的代码:

/*** VideoPlayerController充当指挥者角色*/
public class VideoPlayerController {/*** 逐步构建复杂对象** @param builder* @return*/public VideoPlayer construct(VideoPlayerBuilder builder) {VideoPlayer videoPlayer;builder.buildMainWindow();builder.buildControlStrip();String modelType = builder.getModelType();if ("full".equals(modelType)) {builder.buildMenu();builder.buildPlaylist();} else if ("memory".equals(modelType)) {builder.buildFavoritesList();} else {builder.buildMenu();builder.buildPlaylist();builder.buildFavoritesList();}videoPlayer = builder.createVideoPlayer();return videoPlayer;}
}

配置文件:

<?xml version="1.0" encoding="UTF-16" ?><config><className>creationalpatterns.builderpattern.MemoryPlayerBuilder</className>
</config>

工具类:

public class XMLUtil {//该方法用于从XML配置文件提取具体类的类名,并返回一个实例对象public static Object getBean() {try {DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();DocumentBuilder documentBuilder = dFactory.newDocumentBuilder();Document document = documentBuilder.parse("src/resources/builderconfig.xml");NodeList nodeList = document.getElementsByTagName("className");Node firstChild = nodeList.item(0).getFirstChild();String cName = firstChild.getNodeValue();Class<?> c = Class.forName(cName);Object obj = c.newInstance();return obj;} catch (Exception e) {e.printStackTrace();return null;}}
}

客户端的代码:

public class Client {public static void main(String[] args) {/*** 案例需求描述:* 某公司要开发一个视频播放软件,为了给用户的使用提供方便,该播放软件提供多种界面显示模式,* 如完整模式,精简模式,记忆模式,网络模式等。在不同的显示模式下主界面的组成元素有所差异,* 如在完整模式下将显示菜单、播放按钮、主窗口、控制条等,* 在精简模式下只显示主窗口和控制条,* 在记忆模式下将显示主窗口、控制条、收藏列表等。* 请使用建造者模式设计该软件。* (ps:此案例为笔者的练习demo,可能存在问题,仅供参松,谢谢)*/VideoPlayerBuilder vpb;vpb = (VideoPlayerBuilder)XMLUtil.getBean();VideoPlayerController vpc = new VideoPlayerController();VideoPlayer vp = vpc.construct(vpb);System.out.println("ok");}}

三、指挥者类的深入探讨

3.1 省略Director

为了简化系统结构,可以将Director和抽象建造者Builder进行合并,在Builder中提供逐步构建复杂产品对象的construct()方法。
示例代码:

/*** 抽象建造者*/
public abstract class VideoPlayerBuilder {protected VideoPlayer videoPlayer = new VideoPlayer();public abstract void  buildMenu();public abstract void  buildPlaylist();public abstract void  buildMainWindow();public abstract void  buildControlStrip();public abstract void  buildFavoritesList();//钩子方法,用于区分是什么模式,子类可以重新此方法public String getModelType(){return "";}public VideoPlayer createVideoPlayer(){return videoPlayer;}//逐步构建复杂产品对象的construct方法public VideoPlayer construct(VideoPlayerBuilder builder) {VideoPlayer videoPlayer;builder.buildMainWindow();builder.buildControlStrip();String modelType = builder.getModelType();if ("full".equals(modelType)) {builder.buildMenu();builder.buildPlaylist();} else if ("memory".equals(modelType)) {builder.buildFavoritesList();} else {builder.buildMenu();builder.buildPlaylist();builder.buildFavoritesList();}videoPlayer = builder.createVideoPlayer();return videoPlayer;}
}

这种省略方法不影响系统的灵活性和可扩展性,同时简化了系统结构,但是加重了抽象建造者类的职责。如果construct方法比较复杂,待构建产品的组成部分较多,建议还是将construct()方法单独封装在Director中,这样更符合单一职责原则。

3.2 钩子方法的引入

通过引入钩子方法,可以在Director中对复杂产品的构建进行精细的控制,不仅指定buildPartX()方法的执行顺序,还可以控制是否需要执行某个buildPartX()方法。

四、建造者模式优缺点与适用环境

4.1 建造者模式的优点

  1. 在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的构建过程可以创建不同的产品。
  2. 每一个具体构建者都相对独立,而与其他的具体构建者无关,因此可以很方便第替换具体构建者或增加新的具体构建者。
  3. 可以更加精细地控制产品的创建过程。

4.2 建造者模式的缺点

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

4.3 建造者模式的适用环境

  1. 需要生成的产品对象具有复杂的内部结构,这些产品对象通常包含多个成员变量。
  2. 需要生成的产品对象的属性相互依赖,需要指定生成顺序。
  3. 对象的创建过程独立于创建该对象的类。
  4. 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。

【参考文献】:
本文是根据刘伟的《Java设计模式》一书的学习笔记,仅供学习用途,勿做其他用途,请尊重知识产权。

【本文代码仓库】:https://gitee.com/xiongbomy/java-design-pattern.git

【设计模式】第6章·建造者模式相关推荐

  1. 【设计模式2022】第六章 建造者模式

    [设计模式2022]第六章 建造者模式 文章目录 [设计模式2022]第六章 建造者模式 一.建造者模式 1.结构 2.案例 3.分析 4.使用场景 5.扩展 6.对比工厂模式 一.建造者模式 将一个 ...

  2. 北风设计模式课程---7、建造者模式

    北风设计模式课程---7.建造者模式 一.总结 一句话总结: 设计模式都是对生活中好的做事方法的一些抽象,使得各司其职,减少出错. 建造者模式可以看做模仿的生活中:设计师,施工队做复杂房子交给客户的场 ...

  3. 第 8 章 建造者模式

    第 8 章 建造者模式 1.盖房项目实际需求 需要建房子:这一过程为打桩. 砌墙.封顶 房子有各种各样的,比如普通房,高楼,别墅,各种房子的过程虽然一样,但是各自实现的细节不同 请编写程序,完成需求 ...

  4. 设计模式(五)——建造者模式

    设计模式(五)--建造者模式 一.建造者模式简介 1.建造者模式简介 建造者模式将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示. 建造者模式和抽象工厂模式在功能上很相似,都是用来 ...

  5. 肝一肝设计模式【四】-- 建造者模式

    系列文章目录 肝一肝设计模式[一]-- 单例模式 传送门 肝一肝设计模式[二]-- 工厂模式 传送门 肝一肝设计模式[三]-- 原型模式 传送门 肝一肝设计模式[四]-- 建造者模式 传送门 肝一肝设 ...

  6. 设计模式(五)——建造者模式详解

    设计模式(五)--建造者模式详解 概述 结构 代码案例 优缺点 使用场景 模式扩展 创建者模式对比 工厂方法模式和建造者模式 抽象工厂模式和建造者模式 概述 建造者模式就是说将一个复杂对象的构建和表示 ...

  7. 《大话设计模式》读书笔记-第13章 建造者模式

    1.建造者模式(Builder),又叫生成器模式,它是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的比奥斯.如果我们用了建造者模式,那么用户就只需指定需要建造的类型就可以得到它们 ...

  8. 23种设计模式(第二章创建者模式5种)

    第二章创建者模式 单例模式 单例模式有 3 个特点: 单例类只有一个实例对象: 该单例对象必须由单例类自行创建: 单例类对外提供一个访问该单例的全局访问点. 单例模式的实现 单例设计模式分类两种: ​ ...

  9. 大战设计模式【17】—— 建造者模式

    建造者模式(Builder) 设计模式使用的例子https://github.com/LinkinStars/DesignPatternsAllExample 一.定义 将一个复杂对象的构建与它的表示 ...

最新文章

  1. oracle增量备份如何恢复,【Oracle】增量备份和全库备份怎么恢复数据库
  2. JAVAOO 14 16章
  3. 用Advanced Installer制作DotNetBar for Windows Forms 12.0.0.1_冰河之刃重打包版详解
  4. E打开https网站时,提示此网站的安全证书有问题(证书无效)
  5. LDAP常用命令解析
  6. javafx 和swing_Swing和JavaFX:使用JFXPanel
  7. 前端学习(2595):后台系统的权限控制和管理--动态路由
  8. UNIX(进程间通信):04---孤儿进程
  9. (转自YYW'S BLOG)IListT 转换成 DataSet
  10. chrom浏览器flash_flash插件
  11. extmail mysql数据库 重启_linux下安装和配置extmail
  12. 洛谷 P5602 小E与美食 (尚贤)
  13. 迅雷x导入未完成任务失败的解决办法。
  14. matlab演示波粒二象性,MATLAB实验电子波动性的Matlab仿真
  15. ceph rbd mysql_怎样配置ceph rbd存储类型?
  16. XPath之电影天堂数据爬取
  17. 快排 找第k大的数字
  18. firefox windows旧版本下载
  19. CDH6中的各种目录
  20. Arduino与Proteus仿真实例-密码门禁控制仿真

热门文章

  1. 技术人员必须具备的四种能力|关于技术对话与思考
  2. python输出星号等腰三角形_Python打印矩形、直角三角形、等腰三角形、菱形
  3. html5 svg画钟表,html5 svg创意卡通粒子时钟动画特效
  4. 线程大法修炼(多线程详解)
  5. win10输入法问题,已禁止IME 问题解决
  6. VR联姻AI?8月31日爱奇艺王西颖博士告诉你答案
  7. HTML:一种标记语言而不是编程语言(12.0)
  8. 小学计算机期末评价方案,小学信息技术学科期末考核评价方案
  9. UVA - 10881(思维题)------蚂蚁走竹竿
  10. Redis 安装总结