`
zhanche2011
  • 浏览: 97320 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java Builder模式 初体验

阅读更多
    看来Java构造器模式,决定动手体验下。构造器模式是什么?干什么用的?推荐大家看下ITEYE的一篇文章
    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模式减少了构造器,提供了通用的入口,便于进行合法性校验。前面系统设计中的问题,也迎刃而解了。
     当然了,构造器的用途很多,自己只是拿它在多构造器类的重构中的使用来体验。
3
1
分享到:
评论
3 楼 Richard2018 2014-08-13  
哎,还是没明白builder模式交之直接用set 的好处
2 楼 水围山流山为水守 2013-01-22  
恰好我也是在effective java上看到那个builder了,他也是那样用的,但是我在eclipse里面敲的代码那样写就不行啊
1 楼 水围山流山为水守 2013-01-22  
您好,我有个疑问哦,
    private final String name; 
    private final int age; 
    private final int height; 
    private final int sex; //0表示男性,1表示女性,其它值非法 
这些变量被定义为final了,也就是常量了,但是此处没有初始化值,不会报错吗

相关推荐

    java 面试题 总结

    JAVA相关基础知识 1、面向对象的特征有哪些方面 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用...

    二十三种设计模式【PDF版】

    设计模式之 Template(模板方法) 实际上向你介绍了为什么要使用 Java 抽象类,该模式原理简单,使用很普遍. 设计模式之 Strategy(策略) 不同算法各自封装,用户端可随意挑选需要的算法. 设计模式之 Chain of ...

    超级有影响力霸气的Java面试题大全文档

    超级有影响力的Java面试题大全文档 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节。...

    oh-my-design-patterns::artist_palette:记录我在学习设计模式时编写的文章和代码

    :grinning_face:点击查看电子书,体验更好 :backhand_index_pointing_right: 创建型 (Creational)Java Kotlin结构型(Structural)适配器模式(Adapter Class/Object Pattern) Java桥接模式(Bridge Pattern) ...

    lyadmin_jfinal是零云官方推出的java版本.zip

    ,lyadmin全称零云lyadmin是一套轻量级通用后台,采用JFinal+Vue+Element制作,内置系统设置、上传管理、权限管理、模块管理、插件管理等功能,独有的Builder页面自动生成技术节省50%开发成本 微信小程序是腾讯公司...

    asp.net知识库

    2分法-通用存储过程分页(top max模式)版本(性能相对之前的not in版本极大提高) 分页存储过程:排序反转分页法 优化后的通用分页存储过程 sql语句 一些Select检索高级用法 SQL server 2005中新增的排序函数及应用 ...

    PHP学习手册(PHP知识大全)

    目录页 下一页 ... 虽然 PHP5 还没有正式发布(开发版本已经提供下载),但我们现在就可以开始体验一下新的版本将要带给我们的惊喜。...这三大特点为:  * 新的对象模式 (New ...Power by Softscape HTML Builder 3

    Autofac.Annotation:Autofac extras library for component registration via attributes 用注解来load autofac 摆脱代码或者xml配置和java的spring的注解注入一样的体验

    // 注册autofac打标签模式builder.RegisterModule(new AutofacAnnotationModule(typeof(AnotationTest).Assembly));//如果需要开启支持循环注入//builder.RegisterModule(new AutofacAnnotationModule(typeof(Ano

    VSB 网站综合管理平台

    Visual SiteBuilder网站综合管理平台(简称VSB)是基于JAVA技术开发的网站管理软件。该系统融合先进的网站建设周期管理思想,集成网站可视化设计,内容管理,虚拟主机,用户管理,审核管理等经典应用,全面覆盖了...

    工程硕士学位论文 基于Android+HTML5的移动Web项目高效开发探究

    综上所述,“认我测”在线认证检测系统,率先填补了认证检测领域移动端的空缺,提供了Web浏览器+移动端的双端访问模式,给用户提供了多种访问途径,真正实现了用户和检测机构的随时随地在线下单检测。 关键词:...

    Grid++Report5.6报表开发工具

    5、报表数据来源丰富:支持绑定(报表数据拉模式)与非绑定(报表数据推模式),一切数据库数据与其它数据都可以作为报表数据源。 6、提供图表功能,包括:饼图、叠加饼图、柱状图、气泡图、折线图、曲线图、散列点图等...

    锐浪报表Grid++Report5.3

    5、报表数据来源丰富:支持绑定(报表数据拉模式)与非绑定(报表数据推模式),一切数据库数据与其它数据都可以作为报表数据源。 6、提供图表功能,包括:饼图、叠加饼图、柱状图、气泡图、折线图、曲线图、散列点图等...

    Grid++Report5.5报表工具

    5、报表数据来源丰富:支持绑定(报表数据拉模式)与非绑定(报表数据推模式),一切数据库数据与其它数据都可以作为报表数据源。 6、提供图表功能,包括:饼图、叠加饼图、柱状图、气泡图、折线图、曲线图、散列点图等...

    Grid++Report6 报表开发者安装包

    5、报表数据来源丰富:支持绑定(报表数据拉模式)与非绑定(报表数据推模式),一切数据库数据与其它数据都可以作为报表数据源。 6、提供图表功能,包括:饼图、叠加饼图、柱状图、气泡图、折线图、曲线图、散列点图等...

    Grid++Report5报表工具 版本5.5.0.8

    5、报表数据来源丰富:支持绑定(报表数据拉模式)与非绑定(报表数据推模式),一切数据库数据与其它数据都可以作为报表数据源。 6、提供图表功能,包括:饼图、叠加饼图、柱状图、气泡图、折线图、曲线图、散列点图等...

    一款简单的 page 切换布局

    Builder 模式来创建,使用方式就和 Android 里面的AlertDialog一样,通过 Builder 去构建一个 PageLayout。最后的样子是长这样的:方法注释showLoading()显示 loadingshowError()显示错误布局showEmpty()显示空布局...

    精通ANDROID 3(中文版)1/2

    25.4.4 Gestures Builder应用程序  25.5 参考资料  25.6 小结  第26章 传感器  26.1 什么是传感器  26.1.1 检测传感器  26.1.2 可以了解的传感器信息  26.2 获取传感器事件  26.3 解释传感器数据 ...

    精通Android 3 (中文版)2/2

    25.4.4 Gestures Builder应用程序  25.5 参考资料  25.6 小结  第26章 传感器  26.1 什么是传感器  26.1.1 检测传感器  26.1.2 可以了解的传感器信息  26.2 获取传感器事件  26.3 解释传感器数据 ...

    cuteEditor6.0

    Support auto resize images. 具有特殊的对话框 <br/>With Style builder dialog box you can apply CSS style attributes directly to any HTML elements on your Web page.<br/> <br/> 支持内容...

Global site tag (gtag.js) - Google Analytics