浅谈设计模式--建造器模式(Builder Pattern)
建造器模式,是于创建带有大量参数的对象,并避免因参数数量多而产生的一些问题(如状态不一致-JavaBean的setter模式)。
如果参数多且有些是必须初始化的,有些是不一定需要初始化的时候,创建对象是非常麻烦的,因为不得不为每种情况都添加一个构造方法。建造器模式,就是为了解决这个问题的。
使用Builder模式并不难:
1.创造一个静态内部建造类(Builder Class. e.g. UserBuilder)
2.类的构造方法必须设置为private,防止类被正常构造
3.建造类提供public方法,来设置可选的参数,并返回Builder对象
4.最后建造类提供build()方法,真正创建原来的类的对象
public class User {
private final String firstName; // required
private final String lastName; // required
private final int age; // optional
private final String phone; // optional
private final String address; // optional
private User(UserBuilder builder) {
this.firstName = builder.firstName;
this.lastName = builder.lastName;
this.age = builder.age;
this.phone = builder.phone;
this.address = builder.address;
}
// a list of getter method
@Override
public String toString() {
return firstName + " " + lastName + "-" + age + " , " + phone + "/"
+ address;
}
// Builder Class
public static class UserBuilder {
private final String firstName;
private final String lastName;
private int age;
private String phone;
private String address;
public UserBuilder(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public UserBuilder age(int age) {
this.age = age;
return this;
}
public UserBuilder phone(String phone) {
this.phone = phone;
return this;
}
public UserBuilder address(String address) {
this.address = address;
return this;
}
public User build() {
return new User(this);
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(new User.UserBuilder("Jhon", "Doe").age(30)
.phone("1234567").address("Fake address 1234").build()
.toString());
}
}
另外,在build()方法里,也可以检验参数的正确性,例如:
public User build() {
User user = new user(this);
if (user.getAge()<120) {
throw new IllegalStateException(“Age out of range”); // thread-safe
}
return user;
}
这是线程安全的做法,因为user已经是不可变对象。下面的非线程安全做法,应该避免:
public User build() {
if (age 120) {
throw new IllegalStateException(“Age out of range”); // bad, not thread-safe
}
// This is the window of opportunity for a second thread to modify the value of age
return new User(this);
}
但是,这种建造器的使用方法,其实是有隐患的:
1. 它没有指引用户,一步步的进行构建对象;用户并不知道何时何地用何方法
2. 状态不一致的风险仍然存在
如果需要构建顺序的话,可以做如下修改,来使建造器模式更加人性化:
public class NewUser {
private final String firstName; // required
private final String lastName; // required
private final int age; // optional
private final String phone; // optional
private final String address; // optional
private NewUser(UserBuilder builder) {
this.firstName = builder.firstName;
this.lastName = builder.lastName;
this.age = builder.age;
this.phone = builder.phone;
this.address = builder.address;
}
// a list of getter method
@Override
public String toString() {
return firstName + " " + lastName + "-" + age + " , " + phone + "/"
+ address;
}
public static interface FirstNameStep {
LastNameStep firstName(String name);
}
public static interface LastNameStep {
AgeStep lastName(String lastName);
}
public static interface AgeStep {
PhoneStep age(int age);
}
public static interface PhoneStep {
AddressStep phone(String phone);
}
public static interface AddressStep {
BuildStep address(String address);
}
public static interface BuildStep {
NewUser build();
}
// Builder Class
public static class UserBuilder implements FirstNameStep, LastNameStep,
AgeStep, PhoneStep, AddressStep, BuildStep {
private String firstName;
private String lastName;
private int age;
private String phone;
private String address;
private UserBuilder() {
}
public static FirstNameStep newBuilder() {
return new UserBuilder();
}
public LastNameStep firstName(String firstName) {
this.firstName = firstName;
return this;
}
public AgeStep lastName(String lastName) {
this.lastName = lastName;
return this;
}
public PhoneStep age(int age) {
this.age = age;
return this;
}
public AddressStep phone(String phone) {
this.phone = phone;
return this;
}
public UserBuilder address(String address) {
this.address = address;
return this;
}
public NewUser build() {
return new NewUser(this);
}
}
public static void main(String[] args) {
NewUser user = NewUser.UserBuilder.newBuilder().firstName("ABC")
.lastName("haha").age(10).phone("123").address("wa").build();
System.out.println(user.toString());
}
}
这个实现更加复杂,利用了接口的设计,使得建造器创建对象时,可以一步接着一步(firstName->lastName->age->phone->address),相当友好。缺点是,实现有点复杂,代码量比较大。
参考:
http://www.javacodegeeks.com/2013/01/the-builder-pattern-in-practice.html
http://rdafbn.blogspot.ie/2012/07/step-builder-pattern_28.html
浅谈设计模式--建造器模式(Builder Pattern)的更多相关文章
- 浅谈设计模式--装饰者模式(Decorator Pattern)
挖了设计模式这个坑,得继续填上.继续设计模式之路.这次讨论的模式,是 装饰者模式(Decorator Pattern) 装饰者模式,有时也叫包装者(Wrapper),主要用于静态或动态地为一个特定的对 ...
- 乐在其中设计模式(C#) - 建造者模式(Builder Pattern)
原文:乐在其中设计模式(C#) - 建造者模式(Builder Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 建造者模式(Builder Pattern) 作者:webabc ...
- 6. 星际争霸之php设计模式--建造器模式
题记==============================================================================本php设计模式专辑来源于博客(jymo ...
- 【设计模式】建造者模式 Builder Pattern
前面学习了简单工厂模式,工厂方法模式以及抽象工厂模式,这些都是创建类的对象所使用的一些常用的方法和套路, 那么如果我们创建一个很复杂的对象可上面的三种方法都不太适合,那么“专业的事交给专业人去做”,2 ...
- 二十四种设计模式:建造者模式(Builder Pattern)
建造者模式(Builder Pattern) 介绍将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 示例用同样的构建过程创建Sql和Xml的Insert()方法和Get()方 ...
- Python 设计模式之建造者模式 Builder Pattern
#引入建造者模式 肯德基的菜单上有 薯条, 鸡腿,鸡翅,鸡米花,可乐,橙汁,火腿汉堡,至尊虾汉堡,牛肉汉堡 , 鸡肉卷等这些单品,也有很多套餐. 比如 套餐1:鸡翅,至尊虾汉堡,可乐,薯条 套餐2:鸡 ...
- 设计模式-05建造者模式(Builder Pattern)
1.模式动机 比如我们要组装一台电脑,都知道电脑是由 CPU.主板.内存.硬盘.显卡.机箱.显示器.键盘和鼠标组成,其中非常重要的一点就是这些硬件都是可以灵活选择,但是组装步骤都是大同小异(可以组一个 ...
- 浅谈设计模式-visitor访问者模式
先看一个和visitor无关的案例.假设你现在有一个书架,这个书架有两种操作,1添加书籍2阅读每一本书籍的简介. //书架public class Bookcase { List<Book> ...
- 【UE4 设计模式】建造者模式 Builder Pattern
概述 描述 建造者模式,又称生成器模式.是将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 建造者模式将客户端与包含多个组成部分的复杂对象的创建过程分离,客户端无需知道复杂 ...
随机推荐
- Jexus-5.6.3使用详解、Jexus Web Server配置
一.Jexus Web Server配置 在 jexus 的工作文件夹中(一般是“/usr/jexus”)有一个基本的配置文件,文件名是“jws.conf”. jws.conf 中至少有 Site ...
- Java字符串中常见的10个问题
下面是Java中10个最常见的关于字符串的问题. 怎样比较字符串?使用==还是equals() 简单的说,“==”用于判断引用是否相等,equals()用于判断值是否相等.除非你要比较两个字符串是否是 ...
- Apache安装
记录安装Apache的流程,没有进行详细配置,只是记录搭建服务器的流程用于学习Ajax等知识,方便以后重新安装,不用每次都翻别人博客学习安装了,大神看到这里可以关掉这个粗糙简陋的博文了. 1. 官网上 ...
- Python基本语法,python入门到精通[二]
在上一篇博客Windows搭建python开发环境,python入门到精通[一]我们已经在自己的windows电脑上搭建好了python的开发环境,这篇博客呢我就开始学习一下Python的基本语法.现 ...
- Managed DirectX中的DirectShow应用(简单Demo及源码)
阅读目录 介绍 准备工作 环境搭建 简单Demo 显示效果 其他 Demo下载 介绍 DirectX是Microsoft开发的基于Windows平台的一组API,它是为高速的实时动画渲染.交互式音乐和 ...
- Ineedle驱动方式dpdk测试性能
这次主要是测试在dpdk方案下,ineedle的处理包的性能. 发包工具: 使用立永当时写的一个发包工具:linux_pcap 做法:大概是从网上抓取了一些数据包,将源ip替换为随即ip,sip替换为 ...
- 错误 未能找到类型或命名空间名称 (是否缺少 using 指令或程序集引用?)
有时发现,明明引用了,结果却提示未引用, 这时就有可能是两个程序集的目标框架类型不一致导致的(在程序集属性面板里改下即可).
- EarthWarrior3D游戏ios源码
这是一款不错的ios源码源码,EarthWarrior3D游戏源码, 并且游戏源代码支持多平台. 适用于cocos v2.1.0.0版本 源码下载:http://code.662p.com/view/ ...
- PHP读取超大文件的实例代码
数据量大带来的问题就是单个文件很大,能够打开这个文件相当不容易,记事本就不要指望了,果断死机 去年年底的各种网站帐号信息的数据库泄漏,很是给力啊,趁机也下载了几个数据库,准备学学数据分析家来分析一 ...
- 汽车4S店经验指标完成情况报表制作分享
集团公司一般为了加强下属的经营管理,以及项经营指标完情况,需要制定一些报表.我们平时也经常遇到这种情况,而这些报表要包括什么内容呢?该怎么制作呢?用什么制作呢?今天小编就以4s店为例,分享给大家一个报 ...