设计模式——构建器(Builder)模式
来源:互联网 发布:linux deploy汉化版 编辑:程序博客网 时间:2024/04/28 13:43
在面向对象的编程中对象的创建是最基本的动作,但是创建对象的方法有很多种,但是归根结底都是直接或者间接使用类的构造器完成实例的创建,包括静态工厂方法、JavaBean方式或者下面的要说的构建器模式,但是对于不同的情况,使用这几种方法各有利弊,这里使用一个实际的问题来引出这种对比。
【实际需求】
对一个包含10几个参数的类进行实例化,其中有些参数不是必须的,但是有些参数必须存在。
【问题分析】
首先对于实例化的这个动作,对于有编程经验的人再简单不过,第一个直接的想法就是写一个包含所有参数的构造器,但是回想一下这样真的好吗?每次初始化类的时候都会把自己弄晕,这个参数究竟是什么意思?
方法一:重载构造器
接触过Exception类构造器写法的人可能选择重载多个构造器的方法,如下:
public Exception()public Exception(String message)public Exception(String message, Throwable cause)public Exception(Throwable cause)protected Exception(String message, Throwable cause, boolean enableSuppression,boolean writableStackTrace)
然后通过构造器之间的调用来完成初始化,但是当面对大量的实例参数时,需要扩展很多的构造器,显然这种方式的扩展性很差。
方法二:使用JavaBean方式
这种方式其实是不通过构造器传递参数,而是通过setter方法,如下:
public class User { private Integer userId; private String userName; private String userPwd; private String userFullName; private Date createDate; public void setUserId(Integer userId) { this.userId = userId; } public void setUserName(String userName) { this.userName = userName; } public void setUserPwd(String userPwd) { this.userPwd = userPwd; } public void setUserFullName(String userFullName) { this.userFullName = userFullName; } public void setCreateDate(Date createDate) { this.createDate = createDate; }}
这种方式是我们最熟悉的,在我了解构建器模式之前一直使用的就是这种方式,因为这种方式对于编程者是友好的, 但是在使用的过程中,我就有过一些怀疑,如果调用10个参数的setter方法来实例化该类,但是出于一些原因,这10个调用中只执行了5个,那么这个类怎么办?这不是就出问题了吗?尤其是在多线程的环境下,任何对setter方法的调用都可能出错。
这也是《Effective Java》中所说的会使JavaBean出于不一致的状态的原因,而且还需要使用额外的手段来保证线程安全,因为JavaBean实例是可变的类。
方法三:使用构建器(Builder) 模式
这种方法对编程者非常友好,但是同时也能解决JavaBean对象面向多线程环境的固有缺陷,提高安全性。它是通过以下几种方式完成的:
- 为了解决安全性问题,使用final限制属性不可变并移除setter方法等;
- 为了解决可读性和扩展性问题,通过使用静态嵌套类,在其中设置可变参数方法等;
具体的实现看如下实例。
【具体实现】
public class User { // 所有属性为final, 保证该类为不可变类 // 在构造器实例化的时候完成,不能在方法中完成 private final String userName; private final String userPwd; private final String userFullName; private final Date createDate; // 构造器是私有的,确保类实例化只能通过builder模式 // 并且不提供setter方法 private User(Builder builder){ this.userName = builder.userName; this.userPwd =builder.userPwd; this.userFullName =builder.userFullName; this.createDate =builder.createDate; } // 静态嵌套类,不能直接访问User的非静态变量,保证安全 public static class Builder{ // 必选参数为final, 在实例化Builder类的时候必须提供 // 而不能由方法来完成 private final String userName; private final String userPwd; // 可选参数可以提供默认参数 private String userFullName = "default"; private Date createDate = new Date(); // 包括全部必选参数,它们初始化必须提供参数 public Builder(String userName, String userPwd){ this.userName = userName; this.userPwd = userPwd; } // 可选参数方法, 提高扩展性 public Builder userFullName(String userFullName){ this.userFullName = userFullName; return this; } public Builder createDate(Date createDate){ this.createDate = createDate; return this; } // 实例化外部参数 public User builder(){ return new User(this); } }}
在外部使用的时候,实例化如下:
public static void main( String[] args ){ User.Builder builder = new User.Builder("lmy86263", "123"); User user = builder.userFullName("lmy86263").createDate(new Date()).builder();}
使用这种方式也可以灵活地调整类实例化的步骤,使类的实例化更有弹性,而且可以向用户隐藏内部的具体实现。这种方式在很多的设计中有很多的例子,比如Android中的AlertDialog类等。
- 设计模式——构建器(Builder)模式
- 设计模式—构建器模式(Builder Pattern)
- 设计模式——__构建者模式 Builder模式
- 设计模式:构建器模式(Builder)
- 设计模式——构建者模式(Builder)
- 构建者模式——Builder模式
- 设计模式之构建Builder
- Builder 构建器模式
- 设计模式入门学习 构建Builder模式
- 创建型设计模式---构建模式(Builder)
- 设计模式之构建者Builder模式
- 设计模式之Builder构建者模式
- 设计模式8—Builder设计模式
- Java设计模式—Builder
- c++设计模式—Builder
- Builder模式——设计模式学习
- Android设计模式——Builder模式
- Java设计模式——Builder模式
- 人人都应该了解的十大算法
- 前端开源项目周报0207
- 题目1068:球的半径和体积
- leetcode [Palindrome Number]
- BP神经网络-总结
- 设计模式——构建器(Builder)模式
- Android 那些你所不知道的Bitmap对象详解
- 原型模式 prototype
- 小A点菜
- 8个 UX设计技术
- 正确使用Handler
- XML【介绍、用途、了解XML技术架构、语法】
- 学习设计模式(4)——桥接模式
- c# 给dornetbar中combobox赋值