浏览 1321 次
锁定老帖子 主题:代码重构之第二章 从基础开始
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2010-03-06
最后修改:2010-03-06
第二章 从基础开始
上一章定义了一个Student类。在学校里,学生都有课程安排,所以需要一个CourseSession类表示课程安排,它存储上课时间和教师信息,同时保存一份这门课程的学生。 class CourseSession{ private String department; //课程名称 private String number; //编号 CourseSession(String department,String number){ this.department = department; this.number = number; } } CourseSession 需要存储学生,所以需要一个集合来存储学习,大家立刻会想到用ArrayList private ArrayList<Student> students = new ArrayList<Student>(); 注意用import包把java.util.ArrayList包含进来,包提供了一种将相关的类进行分组的机制。 包有几个用途: 首先,将一组类打成包,给开发者提供了相当的便利,避免开发者必须同一时刻在成十,成百,甚至上千的类中查找。 第二,类被打成包也有发布地目的,可以方便地重用模块或者子系统。 第三,包在java中提供了命名空间。包提供了赋予类一个唯一名字的机制,从而最小化类命名冲突。比如您的类有全称 com.mycompany.studentinfosystem.Student ,第三方API也许会用 com.thirdpartyco.expensivepackages.Student. 习惯:默认的包对于例子或者非商业程序是允许的。但是,对于任何真正的软件开发,所有的类都应该某些包而不是默认包。事实上如果您把类放在 默认包,那么您不可能从其他包使用这些类。 您地开发团队应该就包的命名达成一致。多数公司把他们的域名倒过来,作为包名的开始。例如,一个名叫Minderbinder Enterprise的公司或许用 com.minderbinder作为包名的开始 声明类参数化类型的一个好处是:限制Java.util.ArrayList只能包含Student对象,从而避免不小心把其他类型的对象添加进去。 重构代码 隐藏CourseSession不必要暴露的细节。您封装了student集合,只可以用get、add、size方法来处理该集合。 例如 // 暴露了CourseSession的细节 ArrayList<Student> getAllStudents(){ return students; } //用get方法根据索引得到student Student get(int index){ return students.get(index); } 封装提供了两个优点:首先,目前在ArrayList中保存student列表。ArrayList是有着特定用法和性能指标地一种数据结构。如果您将该列表直接暴露给客户代码,客户代码将依赖于用ArrayList存储student的事实。这样依赖意味着您无法轻易地改变students的存储形式。第二,暴露完整的集合意味着其他类可以操作该集合——加入新的student对象,删除student对象,诸如此类——而且CourseSession类无法意识到这些改变。CourseSession对象的完整性将遭到破坏。 关键点: 1. 用关键子static和final来声明类常量,类常量是成员变量。提醒一下,关键子final表明该成员变量的引用不能改变,即指向不同的值。关键字static意味着在没有创建类的实例的情况下就可以使用该成员变量。 例子: class ChessBoard{ static final int SQUARES_PER_SIDE = 9; } 使用方法:int numberOfSquares = ChessBoard.SQUARES_PER_SIDE; 按照约定,用大写字母定义类常量。当所有的字母都是大写,用“驼峰模式”来标记就不可能,所以标准方法是采用下划线来分割单词。 ********************************************** 课程安排需要开始时间和结束时间。用来标记第一天和最后一天,课程一般都是16周(15周课程,在第7周后会用一周的休息时间) 在CourseSession类中定义一个变量startDate; private Date startDate; //课程安排需要开始时间 然后重载(不是修改原来的构造函数,而是多写一个构造函数)构造函数 CourseSession(String department,String number,Date startDate){ this.department = department; this.number = number; this.startDate = startDate; } Date getEndDate(){ GregorianCalendar calendar = new GregorianCalendar(); calendar.setTime(startDate); int numberOfDays = 16*7-3; calendar.add(Calendar.DAY_OF_YEAR, numberOfDays); Date endDate = calendar.getTime(); return endDate; } 增加对工厂方法的理解 如果方法足够短,我们就容易提供有意义的、简短的名字命名方法。如果发现为方法命名很困难,请考虑将其拆为几个更小的方法,每个方法只做一个简单的、可以命名的事件。 int year = 103; int month = 0; int date = 6; Date startDate = new Date(year,month,date); 像上面的代码让人看着糊涂——因为要相对1900年份来指定年份,月份必须指定在0到11,而不是1到12直接。可以通过增加一个生产Date实例的方法来创建时间 Date createDate(int year,int month,int date){ return new Date(year-1900, month-1, date); }用这个方法好比一个工厂生产时间实例,给我年月日,就给你个日期实例,相当简单。这样创建date实例有助于封装对局部变量的理解。 消除所有的警告。 忽略编译警告就像牙虫的危害---迟早您会为其付出代价,而且为您长期的忽视付出昂贵的代价。 用Calender创建日前而不是用Date创建日期。消除警告(想必大多数人用Date都有警告)。 Date createDate(int year,int month,int date){ GregorianCalendar calendar = new GregorianCalendar(); calendar.clear(); calendar.set(Calendar.YEAR, year-1900); calendar.set(Calendar.MONTH, month-1); calendar.set(Calendar.DAY_OF_MONTH, date); return calendar.getTime(); } int numberOfDays = 16*7-3; 这样的地方容易让人难以理解。可以通过增加注释的方法帮助理解, 例如 weeks * days per week -3days, 但是错误或容易引起误解的注释是声名狼藉的。上面的注释是无效注释的经典例子 一个好的解决方案是: final int sessionLength = 16 ; final int daysInWeek = 7; final int daysFromFridayToMonday = 3; int numberOfday = sessionLength * daysInWeek - daysFromFridayToMonday; 这样更富有表现力 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |