Builder模式 初体验

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

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

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

Java代码  

  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进去,一样可以

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

Java代码  

  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. }

测试代码

Java代码  

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

 

时间: 2024-08-05 14:21:51

Builder模式 初体验的相关文章

Java Builder模式 体验(二)

在上篇文章中,对Java Builder模式的使用体验主要是从Builder对构造器改造方面的优秀特性来说的,感觉并没有从Java Builder模式本身的功能和作用去写,因此决定再从Builder模式的作用以及在项目开发中的使用来体验下.     Builder 模式,即建造者模式,顾名思义,这个模式可能更多的使用在产品的组装中使用,具体说就是在软件产品的组件或模块组装的时候使用.     感觉网络上比较好的解释有:     建造者模式(Builder):将一个复杂对象的构建与它的表示分离,使

【Spark深入学习 -15】Spark Streaming前奏-Kafka初体验

----本节内容------- 1.Kafka基础概念 1.1 出世背景 1.2 基本原理 1.2.1.前置知识 1.2.2.架构和原理 1.2.3.基本概念 1.2.4.kafka特点 2.Kafka初体验 2.1 环境准备 2.2 Kafka小试牛刀 2.2.1单个broker初体验 2.2.2 多个broker初体验 2.3 Kafka分布式集群构建 2.3.1 Kafka分布式集群构建 2.3.2 Kafka主题创建 2.3.3 生产者生产数据 2.3.4消费者消费数据 2.3.5消息的

Android Studio初体验之启动AVD模拟器异常:cannot set up guest memory 'pc.ram'

启动AVD模拟器异常:Cannot set up guest memory 'pc.ram' 错误信息: HAX is working and emulator runs in fast virt mode Cannot set up guest memory 'pc.ram': Invalid argument Error accepting connect 分析 各种查资料,没有发现网上有同样问题的,在一篇相关文章中找到类似的解决方法. 从语意看,应该是hax安装后没有启动.(不懂hax是什

Flume 实战(1) -- 初体验

前言: Flume-ng是数据收集/聚合/传输的组件, Flume-ng抛弃了Flume OG原本繁重的zookeeper和Master, Collector, 其整体的架构更加的简洁和明了. 其基础组件就Agent进程, 内部又可以细分为Source, Channel, Sink三个组件, Source是数据的输入源, channel作为消息的管道, 而sink是作为数据流的输出, Source可以配置多个channel, sink和channel一一对应. *) 初体验Flume-ng 以C

Cocos2dx-Android初体验

windows下android平台cocos2dx. 首先得自己具备如下eclipse(adt.cdt).cygwin.android-ndk .android-sdk,自己下载安装,不做详细解释. 一.下载cocos2dx. http://www.cocos2d-x.org/download 我的cocos2dx目录为D:\2013\cocos2dx\cocos2d-x-2.1.4\cocos2d-x-2.1.4 二.首先进行android版配置,需要修改几个地方. 1.进入目录,修改crea

WCF之初体验

什么是WCF? WCF的全称是:Windows通信基础(WindowsCommunication Foundation),本质来讲,他是一套软件开发包. WCF和WebService的区别 Webservice:严格来说是行业标准,不是一种技术,使用XML扩展标记语言来表示数据(这个是跨语言和平台的关键.) WCF其实一定程度上就是ASP.NET WebService,因为它支持Web Service的行业标准和核心协议,因此ASP.NET Web Service和WSE能做的事情,它几乎都能胜

树莓派2代B model 上手初体验,不用显示器,Python GPIO 点亮一颗LED

开题:[好东西,值得研究!] 标题:树莓派2代B model 上手初体验,不用显示器,Python GPIO 点亮一颗LED [知识普及] 1,树莓派各版本对比: 2,树莓派2代BModel 主板,图样 树莓派2 代B GPIO 图 [所需硬件] 一张TF卡,8G或者8G以上,我的是 [三星TF卡16g class10 EVO] 一根网线,让树莓派与路由器连接 一个5V 500MA 的普通USB电源,为树莓派供电 ,我试过了,5V 500ma没问题 一个树莓派2代B 一个普通路由器[如果你连路由

Xamarin.iOS开发初体验

Xamarin是一个跨平台开发框架,这一框架的特点是支持用C#开发IOS.Android.Windows Phone和Mac应用,这套框架底层是用Mono实现的. Mono是一款基于.NET框架的开源工程,包含C#语言编译器.CLR运行时和一组类库,能运行于Windows.Linux.Unix.Mac OS和Solaris.对于.NET程序员来说,Xamarin是走向安卓.iOS.Mac跨平台开发的神器,不仅能用熟悉的C#来开发,还能使用Visual Studio作为IDE.本文内容是Xamar

KVM之初体验——手动及自动化安装KVM脚本

一,什么是KVM KVM包括很多部件:首先,它是一个Linux内核模块(现在包括在主线中)用于转换处理器到一种新的用户 (guset) 模式.用户模式有自己的ring状态集合,但是特权ring0的指令会陷入到管理器(hypervisor)的代码.由于这是一个新的处理器执行模型,代 码不需要任何的改动.   除了处理器状态转换,这个内核模块同样处理很小一部分低层次的模拟,比如MMU注册(用于管理VM)和一部分PCI模拟的硬件. 在可预见的未来,Qemu团队专注于硬件模拟和可移植性,同时KVM团队专