Builder模式 初体验
http://www.iteye.com/topic/71175
了解构造器模式对于系统的重构,也是很有帮助的。例如,可以优化多构造器类的设计。
首先,我先寻找一个应用场景。拿民工和设计师来写固然可以,但觉得有点类似写Hello word的感觉。学习编程语言和设计模式,很多时候只有将学到的东西和实际应用结合起来的时候,才会深入体会,获取精髓。
Effective Java里说,当遇到多个构造器参数时,考虑用构造器模式。里面有个商品的例子。这让我想到了熟悉的学生信息管理系统。
拿研究生来说吧,入学考试后先进行面试和体检,然后是录取,最后是入学分班。这几个阶段对学生的信息需求是不一样的。
我们首先基于以下假设:
1、体检时只需要知道我们的姓名、性别、年龄和身高等信息。
2、录取的时候,需要在体检基本信息的基础上添加院系、年级等信息。
3、入学分班后,需要添加班号(班级编号)等信息。
4、正式开学后,为了便于管理,又需要完善身份证、学号、实验室名称和宿舍地址等信息。
好吧,现在我们动手写这个学生信息管理系统。先要创建一个名为Student的类,为了满足4个阶段创建用户信息的需要
,我们可能需要4个构造函数。
- package com.icecode.data;
- public class Student {
- private String name;
- private int age;
- private int height;
- private int sex; //0表示男性,1表示女性,其它值非法
- private String schoolName;
- private String profession;
- //要求分班的时候,名字相同的同学不能分配到一个班级
- private int gradeNo;//年级编号
- //扩展信息
- private String idCard;//身份证号
- private String stuNo;//学号
- private String labName;//实验室名称
- private String dormitoryAddress;//宿舍地址
- /**
- * 创建一个基本学生信息 ,例如在研究生入学体检时,不需要专业、年级信息,
- * 因此,可以只适用必须的参数创建一个基本信息
- * @param name
- * @param age
- * @param height
- * @param sex
- */
- public Student(String name, int age, int height, int sex) {
- super();
- this.name = name;
- this.age = age;
- this.height = height;
- this.sex = sex;
- }
- /**
- * 创建一个基本学生信息 ,研究生正式录取后,学校的学生信息管理系统需要学生基本信息
- * @param name
- * @param age
- * @param height
- * @param sex
- * @param schoolName
- * @param profession
- */
- public Student(String name, int age, int height, int sex,
- String schoolName, String profession) {
- super();
- this.name = name;
- this.age = age;
- this.height = height;
- this.sex = sex;
- this.schoolName = schoolName;
- this.profession = profession;
- }
- /**
- * 开学了,为了教学方便,学校进行了分班,同时要求在创建分班的时候,
- * 要求名字相同不分到同一个班级
- * @param name
- * @param age
- * @param height
- * @param sex
- * @param schoolName
- * @param profession
- * @param gradeNo
- * @throws Exception
- */
- public Student(String name, int age, int height, int sex,
- String schoolName, String profession, int gradeNo) throws Exception {
- super();
- this.name = name;
- this.age = age;
- this.height = height;
- this.sex = sex;
- this.schoolName = schoolName;
- this.profession = profession;
- this.gradeNo = gradeNo;
- if(isValidStudent() == false)
- throw new Exception("不合法的学生信息,同名的学生不能分到同一个班级...");
- }
- /**
- * 学生信息合法性校验
- * @return
- */
- public boolean isValidStudent(){
- boolean flag = true;
- //TODO 进行用户信息合法性校验
- return flag;
- }
- public Student(String name, int age, int height, int sex,
- String schoolName, String profession, int gradeNo, String idCard,
- String stuNo, String labName, String dormitoryAddress) {
- super();
- this.name = name;
- this.age = age;
- this.height = height;
- this.sex = sex;
- this.schoolName = schoolName;
- this.profession = profession;
- this.gradeNo = gradeNo;
- this.idCard = idCard;
- this.stuNo = stuNo;
- this.labName = labName;
- this.dormitoryAddress = dormitoryAddress;
- }
- }
当然,以上这个Student类,可以就创建一个构造器,当然这个构造器必须是参数最多的那个。但是这样,编写体检中心信息管
理的程序员不愿意了,它不愿意使用一个需要这么多参数的构造器,因为对他有用的参数就4个。其它模块的程序可能也不大高兴,
因为他们也不愿意使用这样的构造器。同时,如果学校的某个部门突然提出需要其它一些学生信息,比如说学生的4、6级成绩,这
个看似通用的构造器就不适用了,而且修改该构造器代价很大。其它模块的程序员都得配合。
也许有人会问,为什么不使用JavaBean使用的Set方法呢?这种方法有一个缺陷,因为构造过程被分配到了几个调用中,在构
造过程中JavaBean可能处于不一致状态。类无法仅仅通过检验构造器参数的有效性来保证一致性。(引用:《Effective Java》)
是啊,我们总不能控制类的使用者按照一定顺利来调用不同参数的Set方法,再在最后一个set方法中做校验吧?
所以比较满意的方法是根据大家的需要创建不同的构造器。
这样,当参数不断增多的时候,大家都根据自己的需要创建一个自己的构造器。慢慢的,构造器越来越多,代码变得越来越难
理解。即使有一天,系统的设计者想重新设计这个构造器,也变得异常困难。
当系统的设计者正在为这种需求苦恼的时候,我们发现了Builder模式,好吧,我们现在就想想怎么用Builder模式来解决我们
的需求难题。
试想,哪些信息是必须有的,我们只需要一个基础构造器。其它的信息通过类似JavaBean所使用的Set方法set进去,一样可以
达到我们的目的。具体怎么做?我们先贴出代码吧。
- package com.icecode.data;
- public class Student {
- private final String name;
- private final int age;
- private final int height;
- private final int sex; //0表示男性,1表示女性,其它值非法
- private final String schoolName;
- private final String profession;
- //要求分班的时候,名字相同的同学不能分配到一个班级
- private final int gradeNo;//年级编号
- //扩展信息
- private final String idCard;//身份证号
- private final String stuNo;//学号
- private final String labName;//实验室名称
- private final String dormitoryAddress;//宿舍地址
- private Student(Builder builder) {
- this.name = builder.name;
- this.age = builder.age;
- this.height = builder.height;
- this.sex = builder.sex;
- this.schoolName = builder.schoolName;
- this.profession = builder.profession;
- this.gradeNo = builder.gradeNo;
- this.idCard = builder.idCard;
- this.stuNo = builder.stuNo;
- this.labName = builder.labName;
- this.dormitoryAddress = builder.dormitoryAddress;
- }
- public static class Builder{
- private String name;
- private int age;
- private int height;
- private int sex; //0表示男性,1表示女性,其它值非法
- private String schoolName;
- private String profession;
- //要求分班的时候,名字相同的同学不能分配到一个班级
- private int gradeNo;//年级编号
- //扩展信息
- private String idCard;//身份证号
- private String stuNo;//学号
- private String labName;//实验室名称
- private String dormitoryAddress;//宿舍地址
- public Builder(String name, int age, int height, int sex) {
- super();
- this.name = name;
- this.age = age;
- this.height = height;
- this.sex = sex;
- }
- public Builder setSchoolName(String schoolName) {
- this.schoolName = schoolName;
- return this;
- }
- public Builder setProfession(String profession) {
- this.profession = profession;
- return this;
- }
- public Builder setGradeNo(int gradeNo) {
- this.gradeNo = gradeNo;
- return this;
- }
- public Builder setIdCard(String idCard) {
- this.idCard = idCard;
- return this;
- }
- public Builder setStuNo(String stuNo) {
- this.stuNo = stuNo;
- return this;
- }
- public Builder setLabName(String labName) {
- this.labName = labName;
- return this;
- }
- public Builder setDormitoryAddress(String dormitoryAddress) {
- this.dormitoryAddress = dormitoryAddress;
- return this;
- }
- //构造器入口
- public Student build(){
- return new Student(this);
- }
- }
- @Override
- public String toString() {
- return "Students [name=" + name + ", age=" + age + ", height=" + height
- + ", sex=" + sex + ", schoolName=" + schoolName
- + ", profession=" + profession + ", gradeNo=" + gradeNo + "]";
- }
- }
测试代码
- public class Test {
- public static void main(String[] args){
- Student stu = new Student.Builder("icecode", 22, 178, 1)
- .setSchoolName("BUPT").setProfession("Computer Science and
- Technology").
- setGradeNo(20091012)
- .build();
- System.out.println(stu.toString());
- }
- }
由上看见,使用Builder模式减少了构造器,提供了通用的入口,便于进行合法性校验。前面系统设计中的问题,也迎刃而解了。
当然了,构造器的用途很多,自己只是拿它在多构造器类的重构中的使用来体验。
Builder模式 初体验的更多相关文章
- rabbitmq镜像模式初体验
rabbitmq-01: yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm wget ...
- 多线程--future模式初体验
第一次使用多线程,虽然理解的不是很透彻,但是也值得记录下.用的是future模式. 创建个线程池:private ExecutorService cachedThreadPool = Executor ...
- Java Builder模式 体验(二)
在上篇文章中,对Java Builder模式的使用体验主要是从Builder对构造器改造方面的优秀特性来说的,感觉并没有从Java Builder模式本身的功能和作用去写,因此决定再从Build ...
- Java8初体验(二)Stream语法详解---符合人的思维模式,数据源--》stream-->干什么事(具体怎么做,就交给Stream)--》聚合
Function.identity()是什么? // 将Stream转换成容器或Map Stream<String> stream = Stream.of("I", & ...
- Android开发学习之路--百度地图之初体验
手机都有gps和网络,通过gps或者网络可以定位到自己,然后通过百度,腾讯啊之类的地图可以显示我们的地理位置.这里学习下百度地图的使用.首先就是要申请开发者了,这个详细就不多讲了.http://dev ...
- flutter初体验
flutter初体验 和flutter斗争了两个周末,基本弄清楚了这个玩意的布局和一些常用组件了. 在flutter里面,所有东西都是组件Widget.我们像拼接积木一样拼接Widget,拼接的关键词 ...
- 痞子衡嵌入式:MCUXpresso Config Tools初体验(Pins, Clocks, Peripherals)
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是MCUXpresso Config Tools三大件(Pins, Clocks, Peripherals). 不知道大家有没有这样的感受 ...
- .NET平台开源项目速览(15)文档数据库RavenDB-介绍与初体验
不知不觉,“.NET平台开源项目速览“系列文章已经15篇了,每一篇都非常受欢迎,可能技术水平不高,但足够入门了.虽然工作很忙,但还是会抽空把自己知道的,已经平时遇到的好的开源项目分享出来.今天就给大家 ...
- Xamarin+Prism开发详解四:简单Mac OS 虚拟机安装方法与Visual Studio for Mac 初体验
Mac OS 虚拟机安装方法 最近把自己的电脑升级了一下SSD固态硬盘,总算是有容量安装Mac 虚拟机了!经过心碎的安装探索,尝试了国内外的各种安装方法,最后在youtube上找到了一个好方法. 简单 ...
随机推荐
- DC综合流程
Design Compiler and the Design Flow 步骤 将HDL描述的设计输入到Design Compiler中 Design Compiler使用technology libr ...
- Hibernate简单的基础理论
和Hibernate有关的概念,是掌握Hibernate必须了解的知识.就个人经验来说,可以在了解如何简单开发Hibernate之后,再来学习这些概念,这样可以有个比较清楚的认识.Hibernate是 ...
- Linux命令之文件与用户权限
1.文件管理 在Linux里,任何软件和I/O设备都被视为文件.Linux中的文件名最大支持256个字符,分别可以用A-Z.a-z.0-9等字符来命名. 和Windows不同,Linux中文件是区分大 ...
- js精度丢失解决办法
/** * 加法运算,避免数据相加小数点后产生多位数和计算精度损失. * * @param num1加数1 | num2加数2 */ function numAdd(num1, num2) { var ...
- pd的django个人博客教程----1:效果展示等
开发环境同to do list 1:首页:localhost/pd/ 2:导航栏测试或者生活点入: 测试:localhost/category/?cid=1 3:点击文章后进入文章显示页面 e.g:进 ...
- 前端笔试题目总结——应用JavaScript函数递归打印数组到HTML页面上
数组如下: var item=[{ name:'Tom', age:70, child:[{ name:'Jerry', age:50, child:[{ name:'William', age:20 ...
- 你好,C++(19)“老师,我这次四级考试过了没有?”——4.2 条件选择语句
4.2 条件选择语句 “老师,我这次四级考试过了没有?” 如果老师被问到这个问题,他会如何回答?是的,他会根据不同的条件选择不同的回答: 如果考试成绩大于等于60,那就回答:“恭喜你,你通过了这次考 ...
- uva 10922 - 2 the 9s
題目意思:讀取一數字,此數字最大有1000位.計算該數字是否為九的倍數?如是,再計算其階層數. ※判斷是否為九的倍數:所有位數相加 ÷ 9=0,即為九的倍數. ※計算階層數:所有位數相加後得出的第一個 ...
- DHTML【2】--HTML
通过题目,大家已经明确知道,从这一节开始介绍DHTML中的最基础的部分HTML,对于HTML等概念上一节已经做了概述,这一节不再赘余.在学习HTML之前,先告诉大家一个好消息,HTML不难,比C++. ...
- 织梦DEDECMS网站首页如何实现分页翻页
织梦DEDECMS模板网站首页如何实现首页分页和翻页 方法如下:(三种方法,自己选择一种来实现分页吧) 第一种:调用ajax和参数的(不推荐)1.必须在DEDE首页模板中的<head>&l ...