`
java-xb
  • 浏览: 125165 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

代码重构之第二章 从基础开始

阅读更多
第二章 从基础开始
上一章定义了一个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. 用关键子staticfinal来声明类常量,类常量是成员变量。提醒一下,关键子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;

这样更富有表现力










分享到:
评论

相关推荐

    Android开发案例驱动教程 配套代码

    注: 由于第12,13,14章代码太大,无法上传到一个包中。 这三节代码会放到其他压缩包中。 作者:关东升,赵志荣 Java或C++程序员转变成为Android程序员 采用案例驱动模式展开讲解知识点,即介绍案例-&gt;案例涉及...

    Eclipse in Action

    第二章:怎样获得并安装Eclipse,怎样使用他调试java程序,及一下重要的选项,属性 第三章:用eclipse进行开发,包括单元测试,调试,日志 第四章:使用一个例子应用程序,向你展示如何组织你的项目,及重构 第五...

    Table_map_log_event内容详解.pdf

    本书的主要内容如下: Java 8实战目录第一部分 基础知识 第1章 为什么要关心Java 8 2 第2章 通过行为参数化传递代码 20 第3章 Lambda表达式 34 第二部分 函数式数据处理 第4章 引入流 68 第5章 使用流 82 ...

    python有限元分析框架-《有限元分析基础教程》(曾攀)笔记一-二维杆单元有限元程序(基 .pdf

    曾攀⽼师的《有限元分析基础教程》第三章有⼆维杆单元的推导,并结合⼀个例题进⾏了解析解和基于Matlab的程序求解。但是我感觉书 中的MATLAB代码有点罗嗦,⽽且⼀些实现⽅法也⽐较⿇烦,⽐如已经知道了杆单元的起点...

    Android移动应用开发(第3版)卷Ⅰ基础篇 (Shane Conder, Lauren Darcey) PDF扫描版

    第二部分 Android应用程序设计基础 第5章 剖析Android应用程序  第6章 使用Android Manifest文件定义应用程序  第7章 管理应用程序资源  第三部分 Android用户界面设计精髓 第8章 探索用户界面屏幕元素  ...

    CSS网站布局实录 (第二版)PDF版

    第2章 XHTML与CSS基础 2.1 XHTML基础 2.2 选择合适的DTD 2.3 选择合适的标签 2.4 给CSS留下接口 2.5 良好的XHTML编写习惯 2.6 CSS语法结构 2.6.1 CSS属性与选择符 2.6.2 类型选择符 2.6.3 群组选择符 2.6.4 包含选择...

    Ext JS 权威指南

    第二,授人以渔,宏观上对ext js的整体架构进行了分析,微观上则通过源代码深刻揭示了ext js的工作机制与原理,对于想了解ext js工作原理和在开发中碰到疑难问题的读者尤为有帮助。全书一共22章:第1章简要介绍了...

    Reversing:逆向工程揭密

    第二类是从没有源代码的程序出发,生成对应的源程序、系统结构以及相关设计原理和算法思想的文档等,亦即本书重点讨论的二进制逆向工程。 本书共有13章和三个附录,涵盖了逆向工程的基础知识、应用、开发和拓展的...

    领域驱动设计与模式实战

    5.1.3 第二个任务:OrderRepository+OrderNumber 5.1.4 重建持久化的实体:如何从外部设置值 5.1.5 获取订单列表 5.1.6 该到讨论实体的时候了 5.1.7 再次回到流程上来 5.1.8 总览图 5.1.9 建立OrderRepository的伪...

    iphone3开发基础教程

    4.3.5 设置第二个文本字段的属性 50 4.3.6 连接输出口 50 4.4 构建和运行 51 4.4.1 完成输入后关闭键盘 51 4.4.2 通过触摸背景关闭键盘 52 4.5 实现滑块和标签 54 4.5.1 确定输出口 54 4.5.2 确定操作 54 4.5.3 添加...

    asp.net知识库

    ASP.NET 2.0使用Web Part创建应用程序之二(共二) 体验 .net2.0 的优雅(2) -- ASP.net 主题和皮肤 NET2.0系列介绍(一).NET 2.0 中Web 应用程序主题的切换 ASP.NET 2.0 中Web 应用程序主题的切换 2.0正式版中...

    《.NET实践之旅 C#篇》黄凯波著

    第二部分为辅线,介绍c#以及.net framework的基础和特性,采用结合实际工程的方式来引入这些重要的知识点,说明为什么用它们以及怎么使用,并且阐述这些技术的限制,以帮助读者形成自己的技术判断能力,这些知识也是...

    张峥、小白谈GPT与人工智能:可能是好事,也可能不是

    张峥:GPT的基础是大语言模型,这些大模型本质上在训练的时候是在做接龙游戏——把下一页书给写出来——但它们有两点是远超人类的,第一是海量阅读,第二是其中有百分之十的数据是非常结构化的代码(以及代码周围的...

    《iOS6开发指南》精彩书摘

     第二部分网络篇,介绍了iOS网络开发相关知识 第12章“访问Web Service”。了解数据交换格式,其中XML和JSON是主要的方式。重点介绍Web Service的访问以及ASIHTTPRequest框架。 第13章“定位服务与地图应用开发”。...

Global site tag (gtag.js) - Google Analytics