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

代码重构之字符串与包的讨论

阅读更多
接着前两章的学生信息系统继续,学生信息系统的用户需要一个报表,列出课程的清单。
在CourseSession中增加两个变量页眉和页脚
private static String ROSTER_REPORT_HEADER = "页眉,学生信息报表";
private static String ROSTER_REPORT_FOOTER = "页脚,学生信息报表";

然后增加方法getRosterReport返回报表信息。
String getRosterReport(){
	StringBuilder buffer = new StringBuilder();
	buffer.append(ROSTER_REPORT_HEADER);
	Student student = students.get(0);
	buffer.append(student.getName());
	buffer.append('\n');
		
	student = students.get(1);
	buffer.append(student.getName());
	buffer.append('\n');
		
	buffer.append(ROSTER_REPORT_FOOTER+students.size()+'\n');
		
	return buffer.toString();
		
}
在很多地方使用了'\n'表示缓换行,这样做不仅有冗余,而且难以移植----不同平台使用不同的特殊字符序列表示换行。类java.lang.System中包含一个方法getProperty,此方法以一个系统属性的键值作为参数,并返回与该键值相关的系统属性。其中一个属性是line.separator。参考java API文档,在unix中该属性的值为'\n',然而在windows中,值为'\r\n'。应该使用getProperty(line.separator)弥合不同平台直接的差异。
在CourseSession类中定义一个换行常量
static final String NEWLINE = System.getProperty("line.separator");

然后代码相应变为
private static String ROSTER_REPORT_HEADER = "Student"+NEWLINE+"-----"+NEWLINE;
private static String ROSTER_REPORT_FOOTER = NEWLINE + "#Student";
String getRosterReport(){
	StringBuilder buffer = new StringBuilder();
	buffer.append(ROSTER_REPORT_HEADER);
	Student student = students.get(0);
	buffer.append(student.getName());
	buffer.append(NEWLINE );
		
	student = students.get(1);
	buffer.append(student.getName());
	buffer.append(NEWLINE);
		
	buffer.append(ROSTER_REPORT_FOOTER+students.size()+'\n');
		
	return buffer.toString();
		
}
单职责原则:
学生信息系统不断需要新的报表,可以预见,因为增加报表,需要不断地改变类CourseSession。面向对象有一个基本的设计原则:一个类只做好一件事,由于只做一件事,所以应该只有一个动机。这就是单职责原则
生成报表,如报名表,是改变类CourseSession 的另一个动机,违背了单职责原则。
创建一个新类RosterReporter 来生成报表。
public class RosterReporter {
	
	static final String NEWLINE = System.getProperty("line.separator"); //换行常量
	private static String ROSTER_REPORT_HEADER = "Student"+NEWLINE+"------"+NEWLINE;
	private static String ROSTER_REPORT_FOOTER = NEWLINE + "#Student";
	
	private CourseSession session;
	
	public RosterReporter(CourseSession session) {
		super();
		this.session = session;
	}
	
	String getRosterReport(){
		StringBuilder buffer = new StringBuilder();
		buffer.append(ROSTER_REPORT_HEADER);
		for(Student student:session.getAllStudents()){
			buffer.append(student.getName());
			buffer.append(NEWLINE);
		}
		
		buffer.append(ROSTER_REPORT_FOOTER+session.getAllStudents().size()+NEWLINE);
		
		return buffer.toString();
		
	}
	
	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();
	}

}
在CourseSession类和RosterReporter中都需要createDate工具方法。这个很明显是一个小重复,如果您不进行重构,您就打开了大规模的重复的大门,很快您的系统中就会出现代价高昂的重复。在一个大型系统中,或许会有很多创建日期的方法,每个方法都有类似的代码。

可以创建一个日期工具类 DateUtil来统一日期的创建和维护。
public class DateUtil {
	
	/**
	 * 
	 * @param year 年
	 * @param month 月份
	 * @param date  月中的天数
	 * @return 返回一个根据参数year,month,date组成的日期实例
	 */
	//可以写成静态方法。
	public static 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();
	}
}

包结构的一些约定
迄今为止,您编写的类都在包studentinfo包中,典型的组织包的方法是:分离用户接口类和表示业务逻辑的底层类。用户接口负责与最终用户的交互。

如下面的包结构是根据j2ee的mvc模式来划分的,cn.com.common包中放工具类:如日期生产类等,接口(cn.com.dao/cn.com.service)和实现类(cn.com.daoimpl/cn.com.serviceimpl)放在不同的包中,且包的分类都是根据模块来分类的。



类的访问权限
为了更安全的编程,推荐的顺序是:首先是最受限的访问,然后需要时打开相应的访问权限。暴露太多的类给客户,会导致客户对系统的细节产生不必要的依赖。如果您改变了某些细节,客户的代码就可能无法继续工作,而且,打开太多的访问权限,会使您的代码逐渐被破坏。


  • 大小: 28.3 KB
分享到:
评论

相关推荐

    随机字符串/密码生成器

    1. 代码重构:简化和优化代码逻辑,减少不必要的计算和内存占用。 2. 依赖管理:只引入必要的库和组件,避免冗余。 3. 压缩和资源优化:对资源文件进行压缩,减少体积。 4. 构建配置:在发布时选择最小化部署,去除...

    将字符串重构为特定类型

    标题“将字符串重构为特定类型”提示我们要讨论如何从通用的字符串类型转换到更适合特定场景的数据类型。这通常涉及到类型转换、数据验证以及异常处理,以确保数据的准确性和安全性。 字符串类型在处理用户输入、...

    PHP 杂谈《重构-改善既有代码的设计》之三 重新组织数据

    例如,从简单的字符串到具有特定功能的对象,如电话号码类。这样做可以将行为与数据紧密结合,使得代码更易于理解和扩展。 Encapsulate Field是面向对象设计的一个基本原则,即将public字段声明为private并提供...

    看大师如何重构代码(java程序员必看).doc

    在讨论重构之前,我们注意到代码中存在一些可以改进的地方。例如,`DBConnect`方法中的异常处理过于简单,只打印错误消息但没有进一步处理。此外,`LoadProp`方法的异常处理也是类似的。这些异常处理应该更健壮,以...

    35丨 实战一(下):手把手带你将ID生成器代码从“能用”重构为“好用”1

    这个ID生成器主要用于生成包含主机名、时间戳和随机字符的唯一标识字符串。课程分为四轮重构,每轮专注于解决特定的问题。 第一轮重构的重点在于提高代码的可读性。在原始代码中,`IdGenerator`类包含了一个静态...

    java实验十.docx

    根据提供的文件信息,本次讨论将围绕两个主要的Java实验任务展开:一是利用`StringBuffer`类来判断一个字符串是否为对称字符串;二是利用`StringBuilder`类实现对一段文本中的单词进行统计、查找、替换及删除操作。...

    正则表达式实现将MM/DD/YYYY格式的日期转换为YYYY-MM-DD格式

    4. 字符串的解析和重构,将解析得到的日期组成部分重新组织成新的格式。 5. 代码实现的具体实例,以及对错误情况的处理,例如输入不符合预期格式的日期时的反馈。 这些知识点不仅适用于本例的日期格式转换,还可以...

    C语言中函数的结构比较.pdf

    综上所述,文档中探讨了C语言中函数结构比较的方法,提出了函数结构字符串的表示方法,并通过计算两个函数结构字符串的公共字符串来定义函数的结构相似度,这对于程序分析、代码重构和维护具有重要的意义。...

    代码坏味道整理

    4. **硬编码值**:直接在代码中使用固定的数值或字符串,而不是通过常量或配置文件,会使得代码难以理解和测试。应使用常量或变量来代替硬编码值。 5. **魔法数字**:魔法数字是代码中的未定义数值,它们的含义只有...

    优化VB代码.rar

    3. **避免大量字符串连接**:使用StringBuilder类代替加号(+)进行字符串拼接,减少内存分配和垃圾回收。 4. **使用With语句**:通过With...End With块简化代码,减少对象引用的重复。 5. **适当使用ByRef参数**:...

    驯服烂代码

    首先讲解了用提取接口的办法编写Stub来进行单元测试,以及用子类化并覆写方法的办法编写Mock来进行单元测试,然后讲解了如何将被测类与文件系统之间的这种不适用于单元测试的耦合,转化为被测类与字符串之间这种适合...

    21-06-23_Nop4.4(018_添加NopConfig类定义,重构整个程序实现).rar

    1. **NopConfig 类的定义**:`NopConfig` 类通常用于集中管理应用程序的配置信息,如数据库连接字符串、API 密钥、电子邮件设置等。这样的设计使得配置更容易管理和测试,因为所有的配置信息都在一个地方。 2. **...

    HTML代码过滤技术

    5. 输出重构:在应用所有过滤规则后,将修改后的解析树转换回HTML字符串,供服务器发送给客户端。 除了基本的过滤操作,还有一些高级策略可以提高过滤效果: - 使用白名单策略:只允许特定的HTML标签和属性存在,...

    代码大全(第二版)较清晰目录很全

    11. **文档编写**:鼓励编写清晰的文档,包括类和函数的文档字符串、用户手册和API参考,以帮助其他开发者理解和使用你的代码。 12. **软件工程实践**:探讨了项目管理、需求分析、软件架构设计等软件工程领域的...

    如何阅读源代码

    这时,可以使用如DeMorgan法则这样的数学原理来简化逻辑表达式,也可以用字符串消息或关键词搜索代码的方式来快速定位到功能实现的部分。 总之,阅读源代码是一个系统性的工程,需要我们不断地学习和实践。通过积累...

    代码大全2 清晰版

    1. **变量与数据类型**:了解不同编程语言中的基本数据类型(如整型、浮点型、字符串等)及其使用方法。 2. **控制结构**:掌握条件语句(if...else)、循环语句(for、while)等,学会如何通过这些结构来控制程序...

    base64编码和解码c++代码

    以下将详细讨论Base64编码的原理、C++实现Base64编码和解码的步骤,以及如何从live555源码中移植和修改代码。 Base64编码原理: 1. 将每3个字节(24位)分为4个6位组。 2. 每个6位组转换为一个0-63的数字,然后用...

    深入python3

    - **字符串处理**:Python3中的所有字符串默认都是Unicode编码的,这意味着开发者无需像在Python2中那样区分普通字符串与Unicode字符串。同时引入了新的`bytes`类型来处理字节序列,从而避免了Python2中常见的字符串...

Global site tag (gtag.js) - Google Analytics