看来Java构造器模式,决定动手体验下。构造器模式是什么?干什么用的?推荐大家看下ITEYE的一篇文章 
    http://www.iteye.com/topic/71175 
    了解构造器模式对于系统的重构,也是很有帮助的。例如,可以优化多构造器类的设计。 
    首先,我先寻找一个应用场景。拿民工和设计师来写固然可以,但觉得有点类似写Hello word的感觉。学习编程语言和设计模式,很多时候只有将学到的东西和实际应用结合起来的时候,才会深入体会,获取精髓。 
     Effective Java里说,当遇到多个构造器参数时,考虑用构造器模式。里面有个商品的例子。这让我想到了熟悉的学生信息管理系统。 
     拿研究生来说吧,入学考试后先进行面试和体检,然后是录取,最后是入学分班。这几个阶段对学生的信息需求是不一样的。

我们首先基于以下假设: 
    1、体检时只需要知道我们的姓名、性别、年龄和身高等信息。 
    2、录取的时候,需要在体检基本信息的基础上添加院系、年级等信息。 
    3、入学分班后,需要添加班号(班级编号)等信息。 
    4、正式开学后,为了便于管理,又需要完善身份证、学号、实验室名称和宿舍地址等信息。 
    
   好吧,现在我们动手写这个学生信息管理系统。先要创建一个名为Student的类,为了满足4个阶段创建用户信息的需要

,我们可能需要4个构造函数。

  1. package com.icecode.data;
  2. public class Student {
  3. private String name;
  4. private int age;
  5. private int height;
  6. private int sex; //0表示男性,1表示女性,其它值非法
  7. private String schoolName;
  8. private String profession;
  9. //要求分班的时候,名字相同的同学不能分配到一个班级
  10. private int gradeNo;//年级编号
  11. //扩展信息
  12. private String idCard;//身份证号
  13. private String stuNo;//学号
  14. private String labName;//实验室名称
  15. private String dormitoryAddress;//宿舍地址
  16. /**
  17. *  创建一个基本学生信息 ,例如在研究生入学体检时,不需要专业、年级信息,
  18. *  因此,可以只适用必须的参数创建一个基本信息
  19. * @param name
  20. * @param age
  21. * @param height
  22. * @param sex
  23. */
  24. public Student(String name, int age, int height, int sex) {
  25. super();
  26. this.name = name;
  27. this.age = age;
  28. this.height = height;
  29. this.sex = sex;
  30. }
  31. /**
  32. * 创建一个基本学生信息 ,研究生正式录取后,学校的学生信息管理系统需要学生基本信息
  33. * @param name
  34. * @param age
  35. * @param height
  36. * @param sex
  37. * @param schoolName
  38. * @param profession
  39. */
  40. public Student(String name, int age, int height, int sex,
  41. String schoolName, String profession) {
  42. super();
  43. this.name = name;
  44. this.age = age;
  45. this.height = height;
  46. this.sex = sex;
  47. this.schoolName = schoolName;
  48. this.profession = profession;
  49. }
  50. /**
  51. * 开学了,为了教学方便,学校进行了分班,同时要求在创建分班的时候,
  52. * 要求名字相同不分到同一个班级
  53. * @param name
  54. * @param age
  55. * @param height
  56. * @param sex
  57. * @param schoolName
  58. * @param profession
  59. * @param gradeNo
  60. * @throws Exception
  61. */
  62. public Student(String name, int age, int height, int sex,
  63. String schoolName, String profession, int gradeNo) throws Exception {
  64. super();
  65. this.name = name;
  66. this.age = age;
  67. this.height = height;
  68. this.sex = sex;
  69. this.schoolName = schoolName;
  70. this.profession = profession;
  71. this.gradeNo = gradeNo;
  72. if(isValidStudent() == false)
  73. throw new Exception("不合法的学生信息,同名的学生不能分到同一个班级...");
  74. }
  75. /**
  76. * 学生信息合法性校验
  77. * @return
  78. */
  79. public boolean isValidStudent(){
  80. boolean flag = true;
  81. //TODO 进行用户信息合法性校验
  82. return flag;
  83. }
  84. public Student(String name, int age, int height, int sex,
  85. String schoolName, String profession, int gradeNo, String idCard,
  86. String stuNo, String labName, String dormitoryAddress) {
  87. super();
  88. this.name = name;
  89. this.age = age;
  90. this.height = height;
  91. this.sex = sex;
  92. this.schoolName = schoolName;
  93. this.profession = profession;
  94. this.gradeNo = gradeNo;
  95. this.idCard = idCard;
  96. this.stuNo = stuNo;
  97. this.labName = labName;
  98. this.dormitoryAddress = dormitoryAddress;
  99. }
  100. }

当然,以上这个Student类,可以就创建一个构造器,当然这个构造器必须是参数最多的那个。但是这样,编写体检中心信息管

理的程序员不愿意了,它不愿意使用一个需要这么多参数的构造器,因为对他有用的参数就4个。其它模块的程序可能也不大高兴,

因为他们也不愿意使用这样的构造器。同时,如果学校的某个部门突然提出需要其它一些学生信息,比如说学生的4、6级成绩,这

个看似通用的构造器就不适用了,而且修改该构造器代价很大。其它模块的程序员都得配合。 
     也许有人会问,为什么不使用JavaBean使用的Set方法呢?这种方法有一个缺陷,因为构造过程被分配到了几个调用中,在构

造过程中JavaBean可能处于不一致状态。类无法仅仅通过检验构造器参数的有效性来保证一致性。(引用:《Effective Java》)

是啊,我们总不能控制类的使用者按照一定顺利来调用不同参数的Set方法,再在最后一个set方法中做校验吧? 
所以比较满意的方法是根据大家的需要创建不同的构造器。 
    
    这样,当参数不断增多的时候,大家都根据自己的需要创建一个自己的构造器。慢慢的,构造器越来越多,代码变得越来越难

理解。即使有一天,系统的设计者想重新设计这个构造器,也变得异常困难。 
    
    当系统的设计者正在为这种需求苦恼的时候,我们发现了Builder模式,好吧,我们现在就想想怎么用Builder模式来解决我们

的需求难题。 
     试想,哪些信息是必须有的,我们只需要一个基础构造器。其它的信息通过类似JavaBean所使用的Set方法set进去,一样可以

达到我们的目的。具体怎么做?我们先贴出代码吧。

  1. package com.icecode.data;
  2. public class Student {
  3. private final String name;
  4. private final int age;
  5. private final int height;
  6. private final int sex; //0表示男性,1表示女性,其它值非法
  7. private final String schoolName;
  8. private final String profession;
  9. //要求分班的时候,名字相同的同学不能分配到一个班级
  10. private final int gradeNo;//年级编号
  11. //扩展信息
  12. private final  String idCard;//身份证号
  13. private final String stuNo;//学号
  14. private final String labName;//实验室名称
  15. private final String dormitoryAddress;//宿舍地址
  16. private Student(Builder builder) {
  17. this.name = builder.name;
  18. this.age = builder.age;
  19. this.height = builder.height;
  20. this.sex = builder.sex;
  21. this.schoolName = builder.schoolName;
  22. this.profession = builder.profession;
  23. this.gradeNo = builder.gradeNo;
  24. this.idCard = builder.idCard;
  25. this.stuNo = builder.stuNo;
  26. this.labName = builder.labName;
  27. this.dormitoryAddress = builder.dormitoryAddress;
  28. }
  29. public static class Builder{
  30. private String name;
  31. private int age;
  32. private int height;
  33. private int sex; //0表示男性,1表示女性,其它值非法
  34. private String schoolName;
  35. private String profession;
  36. //要求分班的时候,名字相同的同学不能分配到一个班级
  37. private int gradeNo;//年级编号
  38. //扩展信息
  39. private String idCard;//身份证号
  40. private String stuNo;//学号
  41. private String labName;//实验室名称
  42. private String dormitoryAddress;//宿舍地址
  43. public Builder(String name, int age, int height, int sex) {
  44. super();
  45. this.name = name;
  46. this.age = age;
  47. this.height = height;
  48. this.sex = sex;
  49. }
  50. public Builder setSchoolName(String schoolName) {
  51. this.schoolName = schoolName;
  52. return this;
  53. }
  54. public Builder setProfession(String profession) {
  55. this.profession = profession;
  56. return this;
  57. }
  58. public Builder setGradeNo(int gradeNo) {
  59. this.gradeNo = gradeNo;
  60. return this;
  61. }
  62. public Builder setIdCard(String idCard) {
  63. this.idCard = idCard;
  64. return this;
  65. }
  66. public Builder setStuNo(String stuNo) {
  67. this.stuNo = stuNo;
  68. return this;
  69. }
  70. public Builder setLabName(String labName) {
  71. this.labName = labName;
  72. return this;
  73. }
  74. public Builder setDormitoryAddress(String dormitoryAddress) {
  75. this.dormitoryAddress = dormitoryAddress;
  76. return this;
  77. }
  78. //构造器入口
  79. public Student build(){
  80. return new Student(this);
  81. }
  82. }
  83. @Override
  84. public String toString() {
  85. return "Students [name=" + name + ", age=" + age + ", height=" + height
  86. + ", sex=" + sex + ", schoolName=" + schoolName
  87. + ", profession=" + profession + ", gradeNo=" + gradeNo + "]";
  88. }
  89. }

测试代码

  1. public class Test {
  2. public static void main(String[] args){
  3. Student stu = new Student.Builder("icecode", 22, 178, 1)
  4. .setSchoolName("BUPT").setProfession("Computer Science and
  5. Technology").
  6. setGradeNo(20091012)
  7. .build();
  8. System.out.println(stu.toString());
  9. }
  10. }

由上看见,使用Builder模式减少了构造器,提供了通用的入口,便于进行合法性校验。前面系统设计中的问题,也迎刃而解了。 
     当然了,构造器的用途很多,自己只是拿它在多构造器类的重构中的使用来体验。

 

Builder模式 初体验的更多相关文章

  1. rabbitmq镜像模式初体验

    rabbitmq-01: yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm wget ...

  2. 多线程--future模式初体验

    第一次使用多线程,虽然理解的不是很透彻,但是也值得记录下.用的是future模式. 创建个线程池:private ExecutorService cachedThreadPool = Executor ...

  3. Java Builder模式 体验(二)

       在上篇文章中,对Java Builder模式的使用体验主要是从Builder对构造器改造方面的优秀特性来说的,感觉并没有从Java Builder模式本身的功能和作用去写,因此决定再从Build ...

  4. Java8初体验(二)Stream语法详解---符合人的思维模式,数据源--》stream-->干什么事(具体怎么做,就交给Stream)--》聚合

    Function.identity()是什么? // 将Stream转换成容器或Map Stream<String> stream = Stream.of("I", & ...

  5. Android开发学习之路--百度地图之初体验

    手机都有gps和网络,通过gps或者网络可以定位到自己,然后通过百度,腾讯啊之类的地图可以显示我们的地理位置.这里学习下百度地图的使用.首先就是要申请开发者了,这个详细就不多讲了.http://dev ...

  6. flutter初体验

    flutter初体验 和flutter斗争了两个周末,基本弄清楚了这个玩意的布局和一些常用组件了. 在flutter里面,所有东西都是组件Widget.我们像拼接积木一样拼接Widget,拼接的关键词 ...

  7. 痞子衡嵌入式:MCUXpresso Config Tools初体验(Pins, Clocks, Peripherals)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是MCUXpresso Config Tools三大件(Pins, Clocks, Peripherals). 不知道大家有没有这样的感受 ...

  8. .NET平台开源项目速览(15)文档数据库RavenDB-介绍与初体验

    不知不觉,“.NET平台开源项目速览“系列文章已经15篇了,每一篇都非常受欢迎,可能技术水平不高,但足够入门了.虽然工作很忙,但还是会抽空把自己知道的,已经平时遇到的好的开源项目分享出来.今天就给大家 ...

  9. Xamarin+Prism开发详解四:简单Mac OS 虚拟机安装方法与Visual Studio for Mac 初体验

    Mac OS 虚拟机安装方法 最近把自己的电脑升级了一下SSD固态硬盘,总算是有容量安装Mac 虚拟机了!经过心碎的安装探索,尝试了国内外的各种安装方法,最后在youtube上找到了一个好方法. 简单 ...

随机推荐

  1. DC综合流程

    Design Compiler and the Design Flow 步骤 将HDL描述的设计输入到Design Compiler中 Design Compiler使用technology libr ...

  2. Hibernate简单的基础理论

    和Hibernate有关的概念,是掌握Hibernate必须了解的知识.就个人经验来说,可以在了解如何简单开发Hibernate之后,再来学习这些概念,这样可以有个比较清楚的认识.Hibernate是 ...

  3. Linux命令之文件与用户权限

    1.文件管理 在Linux里,任何软件和I/O设备都被视为文件.Linux中的文件名最大支持256个字符,分别可以用A-Z.a-z.0-9等字符来命名. 和Windows不同,Linux中文件是区分大 ...

  4. js精度丢失解决办法

    /** * 加法运算,避免数据相加小数点后产生多位数和计算精度损失. * * @param num1加数1 | num2加数2 */ function numAdd(num1, num2) { var ...

  5. pd的django个人博客教程----1:效果展示等

    开发环境同to do list 1:首页:localhost/pd/ 2:导航栏测试或者生活点入: 测试:localhost/category/?cid=1 3:点击文章后进入文章显示页面 e.g:进 ...

  6. 前端笔试题目总结——应用JavaScript函数递归打印数组到HTML页面上

    数组如下: var item=[{ name:'Tom', age:70, child:[{ name:'Jerry', age:50, child:[{ name:'William', age:20 ...

  7. 你好,C++(19)“老师,我这次四级考试过了没有?”——4.2 条件选择语句

    4.2  条件选择语句 “老师,我这次四级考试过了没有?” 如果老师被问到这个问题,他会如何回答?是的,他会根据不同的条件选择不同的回答: 如果考试成绩大于等于60,那就回答:“恭喜你,你通过了这次考 ...

  8. uva 10922 - 2 the 9s

    題目意思:讀取一數字,此數字最大有1000位.計算該數字是否為九的倍數?如是,再計算其階層數. ※判斷是否為九的倍數:所有位數相加 ÷ 9=0,即為九的倍數. ※計算階層數:所有位數相加後得出的第一個 ...

  9. DHTML【2】--HTML

    通过题目,大家已经明确知道,从这一节开始介绍DHTML中的最基础的部分HTML,对于HTML等概念上一节已经做了概述,这一节不再赘余.在学习HTML之前,先告诉大家一个好消息,HTML不难,比C++. ...

  10. 织梦DEDECMS网站首页如何实现分页翻页

    织梦DEDECMS模板网站首页如何实现首页分页和翻页 方法如下:(三种方法,自己选择一种来实现分页吧) 第一种:调用ajax和参数的(不推荐)1.必须在DEDE首页模板中的<head>&l ...