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

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

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

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

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

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

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

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

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

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


    测试代码 
    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.   
    6. Technology").  
    7.                             setGradeNo(20091012)  
    8.                             .build();  
    9.         System.out.println(stu.toString());  
    10.     }  
    11. }  


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

     

  • 相关阅读:
    Atitit java支持php运行环境 Quercus jar 1.1. Quercus 1 1.2. Web.xml 增加php servlet拦截 1 1.3. Phpinfo。php测试 1
    EXTJS学习系列提高篇:第十一篇(转载)作者殷良胜,制作树形菜单之五
    EXTJS学习系列基础篇:第八篇(转载)作者殷良胜,Ext组件系列之textfield组件的基本用法
    基础篇:第五篇,Ext.util.Format类是Ext对数据进行格式化操作的一个类(转载)作者殷良胜
    EXTJS学习系列基础篇:第七篇(转载)作者殷良胜,Ext组件系列之label组件的基本用法
    EXTJS学习系列提高篇:第二篇(转载)作者殷良胜,结合EXT2.2+C#.net实现将数据导入Excel的功能
    EXTJS学习系列基础篇:第九篇(转载)作者殷良胜,Ext组件系列之field组件的基本用法
    EXTJS学习系列基础篇:第二篇(转载)作者殷良胜
    Ext 智能 在VS2008中让Intellisense提供对ExtJS的支持 (转载)作者殷良胜
    EXTJS学习系列提高篇:第十篇(转载)作者殷良胜,制作树形菜单之四
  • 原文地址:https://www.cnblogs.com/lvdongjie/p/4478012.html
Copyright © 2011-2022 走看看