`
mojinglf
  • 浏览: 13142 次
  • 性别: Icon_minigender_1
  • 来自: 大连
最近访客 更多访客>>
社区版块
存档分类
最新评论

预览文章: 初学Java设计模式随记 -- 建造者(BUILDER)模式

阅读更多

 

建造者(BUILDER)模式又叫生成器(BUILDER)模式。它的定义如下:(参见GoF的设计模式与阎宏的《Java与模式》)

1. 用意:
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

 

2. 参与者:

• 抽象建造者(Builder): 为创建一个产品(Prodcut)对象的各个部件指定抽象接口。
• 具体建造者(ConcretBuilder):

    实现抽象建造者(Builder)的接口以构造和装配该产品的各个部件。
    定义并明确它所创建的表示。
    提供一个检索产品的接口。

• 导演者(Director):构造一个使用抽象建造者(Builder)接口的对象。
• 产品(Prodcut):

  表示被构造的复杂对象。具体建造者(ConcretBuilder)创建该产品的内部表示并定义它的装配过程。
  包含定义组成部件的类,包括将这些部件装配成最终产品的接口。

 

3. 结构:



 

根据GoF的设计模式,来描述一下建造者(BUILDER)模式使用时,各个角色之间的协作关系:

1. 客户创建导演者(Director)对象,并用它所想要的抽象建造者(Builder)的一个具体建造者(ConcretBuilder)对象进行配置。
2. 当产品的某个部件(PartOne, PartTwo, ...)需要被创建时,导演者(Director)就会通知具体建造者(ConcretBuilder)
3. 具体建造者(ConcretBuilder)处理导演者(Director)的请求,并将部件(PartOne, PartTwo, ...)添加到该产品(Prodcut)中。
4. 客户从具体建造者(ConcretBuilder)中检索产品(Prodcut)

 

===============小插曲===============================

在参看《设计模式可复用面向对象软件的基础》(GOF设计模式中文版)时,对于Builder模式中协作的第二条描述,无法理解:

一旦产品部件被生成,导向器就会通知生成器。(查看维基百科中文,也是这么翻译的)

对比英文原著,是这样描述的:

Director notifies the builder whenever a part of the product should be built.

 

那么,是不是应该翻译成下面的意思呢?

当产品的某个部件需要(应当)被创建的时候,导向器就会通知生成器。

(或者说,一旦产品部件需要被生成,导向器就会通知生成器。

  

这里,可能有点较真了,不过,个人觉得,前后两种中文表达的应该是不同的含义。

=====================================================

 

 

根据现实的例子,来理解建造者模式。还是用生产汽车来举例。例子9

顾客想购买一辆一汽大众的汽车。

汽车实际就是一个产品族,即一套(一系列)汽车零部件产品(产品族)组合。

汽车的构造可是非常复杂的。它要有轮子,方向盘,座椅,发动机,颜色等等。

 

怎么这个例子看起来这么熟悉?

1. 好像与前一篇随记初学Java设计模式随记 -- 抽象工厂(Abstract Factory)模式很相似:

它们都可以创建复杂对象(产品集合或产品族)。

在GoF的设计模式中是这么说的:

Abstract Factory与Builder相似,因为它也可以创建复杂对象。主要的区别是Builder模式着重于一步步构造一个复杂对象。而Abstract Factory着重于多个系列的产品对象(简单的或是复杂的)。

 

也就是说,Builder模式关心的是怎样把复杂的产品的各个部件(或部件产品)给组装起来;

而Abstract Factory模式关心的是把哪些部件(或部件产品)给组装起来。

 

2. 好像与之前的另一篇随记初学Java设计模式随记 -- 工厂模式(Factory Pattern)也很相似:

回顾工厂模式的优势,与建造者模式的用意比较一下:

利用工厂模式可以将对象的创建过程和使用进行分离(也就是解藕)。

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

个人觉得,

建造者模式更侧重于有规则或有序的创建(构建)过程;

工厂模式的创建(构建)过程比较随意。

  

 

其实,也可以从工厂建造者这两个名字来体会他们的差异:

建造者更像是工厂里的生产设备 

工厂只关心生产什么产品,他只知道这个产品是由什么组成的;

建造者需要考虑怎么生产产品,他需要考虑产品的组成规则和方法。

 

或者说,在某种程度上,建造者模式就好像把工厂模式工厂角色的一些职责工作内容,给做了一些细化。 

导演者(Director)指导产品的生产,由建造者实施具体的生产。

 

继续这个例子,来体会建造者模式:

 

抽象建造者: 

 

/*
 * 建造者 
 */
public interface CarBuilder {
	
	/**
	 * 建造汽车的框架
	 */
	public void buildeCarSkeleton();
	
	/**
	 * 给汽车装上发动机
	 */
	public void buildeCarEngine();
	
	/**
	 * 给汽车装上轮子
	 */
	public void buildeCarWheels();
	
	/**
	 * 给汽车装上导航设备
	 */
	public void buildeCarNavigation();
	
	/**
	 * 安装车身(包含车门、车窗的安装,涂颜色)
	 */
	public void buildeCarBody();

}

 

具体建造者:(生产奥迪A6)

  

导演者: 

这里,由导演者指导建造者以一定的方式生产汽车(安装了导航系统

 

/*
 * 导演者
 */
public class AudiDirector {
	
	CarBuilder builder;

	/**
	 * 为导演者配置一个建造者
	 */
	public AudiDirector(CarBuilder builder){
		this.builder = builder;
		
	}

	/**
	 * 按照一定的方式或规则建造汽车
	 */
	public void contruct(){
		
		builder.buildeCarSkeleton();
		
		builder.buildeCarEngine();
		
		builder.buildeCarNavigation();
		
		builder.buildeCarWheels();
		
		builder.buildeCarBody();
		
	}
}

 

奥迪汽车(产品): 

 

/*
 * 产品
 */
public class AudiCar {
	
	private String carSkeleton;
	private Engine carEngine;
	private String carWheels;
	private String carNavigation = "";
	
	private String carDoor;
	private String carWindscreen;
	private String carColor;
	
	public AudiCar(){	}
	
	/**
	 * 汽车的颜色
	 */
	public void setCarColor(String carColor) {
		this.carColor = carColor;
	}
	/**
	 * 汽车的车门
	 */
	public void setCarDoor(String carDoor) {
		this.carDoor = carDoor;
	}
	/**
	 * 汽车发动机,发动机在这里是一个对象
	 */
	public void setCarEngine(Engine carEngine) {
		this.carEngine = carEngine;
	}
	/**
	 * 汽车的框架
	 */
	public void setCarSkeleton(String carSkeleton) {
		this.carSkeleton = carSkeleton;
	}
	/**
	 * 汽车轮子
	 */
	public void setCarWheels(String carWheels) {
		this.carWheels = carWheels;
	}
	/**
	 * 汽车的挡风玻璃
	 */
	public void setCarWindscreen(String carWindscreen) {
		this.carWindscreen = carWindscreen;
	}
	/**
	 * 汽车导航
	 */
	public void setNavigation(String navigation) {
		this.carNavigation = navigation;
	}
	

	/**
	 * 一个汽车对象的描述
	 */
	public String toString(){
		return carSkeleton+ "," + carEngine.toString() +"," + carWheels + "," +
		carDoor + "," + carWindscreen + "," + carColor + "," + carNavigation;
	}
}

 

汽车的一个部件对象:

 

/*
 * 一个部件对象(汽车发动机)
 */
public class Engine {
	
	private String name;
	
	public Engine(String name){
		this.name = name;
	}
	
	public String toString(){
		return this.name;
	}

}

 

客户端:

 

/*
 * 客户端
 */
public class Clients {

	public static void main(String[] args) {
		
//		创建一个建造者对象
		AudiCarBuilder builder = new AudiCarBuilder();
		
//		创建一个导演者,并为它配置一个建造者
		AudiDirector director1 = new AudiDirector(builder);
		
//		导演者将通知建造者去创建产品
//		在这个过程中,建造者将会根据导演者的请求,去创建组织并创建产品对象
		director1.contruct();
		
//		从具体建造者中检索产品(返回的是带导航的汽车产品)。
		AudiCar audiCar = builder.retrieveCar();
		
		System.out.println(audiCar);	
	}
}

 

运行结果:

汽车框架,奥迪A6发动机,车轮,车门,挡风玻璃,黑色,汽车导航

 

如果想生产一款没有导航系统的奥迪A6汽车,怎么实现呢?

只需要修改一下导演者就可以了。

新的导演者:(指示建造者不安装导航系统

 

/*
 * 导演者
 */
public class AudiDirector {
	
	CarBuilder builder;

	/**
	 * 为导演者配置一个建造者
	 */
	public AudiDirector(CarBuilder builder){
		this.builder = builder;
		
	}

	/**
	 * 按照一定的方式或规则建造汽车
	 */
	public void contruct(){
		
		builder.buildeCarSkeleton();
		
		builder.buildeCarEngine();
		
//		不安装导航系统
//		builder.buildeCarNavigation();
		
		builder.buildeCarWheels();
		
		builder.buildeCarBody();
		
	}
}

 

运行结果:(没有导航系统

 

  

汽车框架,奥迪A6发动机,车轮,车门,挡风玻璃,黑色,

 

 

 

 如果想生产奥迪A8且带导航系统的汽车,怎么实现呢?

假设奥迪A6与奥迪A8的差别只是发动机

只需要修改建造者类就可以了。

 

建造者:(只是改变自己的内部实现--奥迪A6发动机改为奥迪A8发动机)

 

/*
 * 具体建造者
 */
public class AudiCarBuilder implements CarBuilder {
	
	private AudiCar audiCar = new AudiCar();

	/**
	 * 安装车身(包含车门、车窗的安装,涂颜色)
	 */
	public void buildeCarBody() {
		audiCar.setCarDoor("车门");
		audiCar.setCarWindscreen("挡风玻璃");
		audiCar.setCarColor("黑色");
	}

	/**
	 * 给汽车装上发动机
	 */
	public void buildeCarEngine() {
		Engine audiEngine = new Engine("奥迪A8发动机");
		audiCar.setCarEngine(audiEngine);
	}

	/**
	 * 给汽车装上导航设备
	 */
	public void buildeCarNavigation() {
		audiCar.setNavigation("汽车导航");
	}

	/**
	 * 建造汽车的框架
	 */
	public void buildeCarSkeleton() {
		audiCar.setCarSkeleton("汽车框架");
	}

	/**
	 * 给汽车装上轮子
	 */
	public void buildeCarWheels() {
		audiCar.setCarWheels("车轮");
	}
	
	public AudiCar retrieveCar(){
		return audiCar;
	}

}

 

 

运行结果:(更换成了奥迪A8发动机

汽车框架,奥迪A8发动机,车轮,车门,挡风玻璃,黑色,汽车导航

  

 

从这个例子就可以看出,建造者模式的优势:

1. 导演者可以指定不同的生产方式(是否安装导航),而建造者不需要做任何改变,就可以得到不同的产品

2. 导演者不需要改变期望的生产方式,只需要建造者改变自己的内部实现(选择什么型号的发动机),也可以得到不同的产品。

  

关于建造者模式带来的效果,参看GoF的《设计模式》。

/*
 * 具体建造者
 */
public class AudiCarBuilder implements CarBuilder {
	
	private AudiCar audiCar = new AudiCar();

	/**
	 * 安装车身(包含车门、车窗的安装,涂颜色)
	 */
	public void buildeCarBody() {
		audiCar.setCarDoor("车门");
		audiCar.setCarWindscreen("挡风玻璃");
		audiCar.setCarColor("黑色");
	}

	/**
	 * 给汽车装上发动机
	 */
	public void buildeCarEngine() {
		Engine audiEngine = new Engine("奥迪A6发动机");
		audiCar.setCarEngine(audiEngine);
	}

	/**
	 * 给汽车装上导航设备
	 */
	public void buildeCarNavigation() {
		audiCar.setNavigation("汽车导航");
	}

	/**
	 * 建造汽车的框架
	 */
	public void buildeCarSkeleton() {
		audiCar.setCarSkeleton("汽车框架");
	}

	/**
	 * 给汽车装上轮子
	 */
	public void buildeCarWheels() {
		audiCar.setCarWheels("车轮");
	}
	
	public AudiCar retrieveCar(){
		return audiCar;
	}

}

 

  • 大小: 7.5 KB
分享到:
评论

相关推荐

    java随记等

    根据提供的文件信息,我们可以分析出该段代码定义了一个名为 `UserRoleType` 的 Java 枚举类,用于描述不同用户角色的权限类型。接下来,我们将详细解释这个枚举类中的各个元素及其含义,并尝试理解其中的一些注释...

    NativeJS随记 - 浅析JavaScript Events

    标题中的“NativeJS随记 - 浅析JavaScript Events”表明这篇博客主要讨论的是JavaScript中的事件处理机制。JavaScript事件是Web开发中的重要组成部分,它允许我们响应用户的交互或浏览器的内部变化。在这里,我们将...

    读书笔记:Java并发编程之美阅读随记.zip

    读书笔记:Java并发编程之美阅读随记

    Java.util随记.doc

    Java.util包是Java标准库中的核心包之一,它包含了大量用于处理各种数据结构和集合的类和接口。在这个包中,我们经常会用到`Iterator`和`List`接口,这两个接口在Java编程中扮演着非常重要的角色。 首先,`Iterator...

    2021-2022年收藏的精品资料辛辛那提1000维修随记.doc

    【辛辛那提1000维修随记】是一份关于数控系统维修的珍贵文档,主要涉及美国辛辛那提·米拉克龙公司的ACRAMATIC系列数控装置,特别是1994年推出的先进CNC控制系统——A2100。这篇随记详细记录了从1950年代早期的数控...

    JAVA核心知识点整理.zip

    11. **设计模式**:常见的23种设计模式(如工厂模式、单例模式、观察者模式等)在Java中都有应用,是提升代码质量和可维护性的关键。 12. **Java EE**:对于Web开发者,Java Enterprise Edition(Java EE)提供了...

    .class文件反编译成.java文件工具:jd-gui(无需安装,下载直接使用)

    《深入理解Java类文件反编译:jd-gui工具详解》 在Java开发过程中,有时我们需要查看或理解已编译的.class文件中的源代码,这时就需要借助反编译工具。jd-gui是一款非常实用的Java反编译软件,它允许开发者直接查看...

    EHCache的使用随记

    **EHCache的使用随记** EHCache是一款广泛应用于Java环境中的高效、易用且功能丰富的内存缓存系统。它能够显著提升应用性能,通过将常用数据存储在内存中,避免了反复从数据库读取,降低了I/O延迟。本文将探讨...

    初学VB.NET使用心得随记

    在初学者的学习过程中,理解如何有效地使用`OleDbDataAdapter`来更新数据库至关重要。在提供的代码示例中,我们看到了一个简单的VB.NET应用程序,它使用`OleDbDataAdapter`从Access数据库(`.mdb`)中填充`DataSet`,...

    HL_Letter:个人随记

    【HL_Letter:个人随记】是一个以Java技术为核心的个人学习笔记项目,它可能是某位开发者记录自己在Java编程过程中的心得、技巧和问题解决...这对于Java初学者和有经验的开发者来说都是宝贵的资源,可以从中学习和借鉴。

    随记小时光设计书1

    在"随记小时光设计书1"中,我们主要讨论的是用户信息和手账信息的设计,特别是在数据库方面的应用。这个设计涉及到用户信息的多个关键组成部分,包括昵称、用户名、密码、邮箱、手机号以及权限和加密key的管理。下面...

    JSP PDF打印 随记 复杂模板设计

    本篇随记主要探讨的是如何在JSP环境中进行PDF打印,并涉及复杂的模板设计。PDF(Portable Document Format)是一种通用的文件格式,常用于生成保持原始文档格式不变的静态文档,适用于打印和共享。 首先,我们需要...

    VC++2010游戏开发随记之十三.pdf

    在VC++2010游戏开发中,处理用户输入是至关重要的,特别是键盘和鼠标作为最常见的人机交互工具。本章节重点讲述了如何处理鼠标的各类消息,以便在游戏中实现更丰富的交互功能。 首先,Windows系统提供了多种鼠标...

    随记:flex发送XML到servlet

    标题“随记:flex发送XML到servlet”指的是在Flex应用程序中向Java Servlet发送XML数据的过程,这通常涉及到客户端与服务器端的交互。Flex是一种基于Adobe AIR或Flash Player运行时的开发框架,常用于创建富互联网...

    2015年8月整理笔记本随记.ppt

    这篇随记内容涵盖了多个教育和德育相关的知识点,深入探讨了教育的本质、电子智慧教育的定义、学生文化的理解以及班主任的角色。以下是对这些知识点的详细解释: 1. **教育理念**: - "精准,精减,精彩":这强调...

    一些有关哈希函数的随记

    这篇随记将探讨哈希函数的基本概念、性质以及在实际应用中的重要性。 哈希函数,也称为散列函数,是一种特殊的算法,它将任意长度的输入(也称为预映射或消息)转化为固定长度的输出,这个输出通常被称为哈希值或...

    随记_电气_

    【压缩包子文件的文件名称列表】:随记.docx 指出文档的具体形式,是一个Microsoft Word文档,通常用于撰写报告、笔记或文章,其中的“随记”与标题相呼应,暗示这可能是一篇个人的电气知识总结。 接下来,我们将...

    c++随记.docx

    ### C++ 随记知识点总结 #### 一、内存管理与 new/delete 操作符 在 C++ 中,`new` 和 `delete` 是用于动态内存分配的关键字。`new` 用于在堆区分配内存,`delete` 用于释放之前通过 `new` 分配的内存。使用 `new`...

    oracle安装随记.doc

    2. **目录结构**:创建了`/oracle`目录,并指定了其所有者和权限。这一步是为了后续安装Oracle时指定安装路径。 3. **Shell Limit 设置**:为提高Oracle在Linux系统上的性能,设置了Oracle用户的软限制和硬限制,...

    随记app,微博与博客整合

    随记App是一款集成微博与博客功能的毕业设计项目,旨在为用户提供一个统一的平台来管理和分享他们的日常思考和生活点滴。这个项目分为客户端和服务端两部分,分别实现了用户交互界面和后台数据处理。 在Android...

Global site tag (gtag.js) - Google Analytics