一次java程序的重构
// com口操作类
package xyz.game;
class ComOpera {
public void openPort() throws Exception {...} // 打开com
public void closeProt() {...} // 关闭com
private String readMsg() {...} // 读取com消息
private void writeMsg(String msg) {...} // 写com消息
public boolean getComStatus() {...}
private String unicode2gb(String hexString) {...}
public boolean writeMsgWithResultOK(String cmd)
public String writeMsgWithResult(String cmd) {...} public String getSmsCode() {...} //短信操作接口通过上述com接口实现
public boolean deleteMsg() {...}
public void sendsms(String sms, String receivers) {...}
}; // 业务逻辑模块
package xyz.game;
class GameCatch{
public void catch(ComOpera comOpera){
comOpera.openPort(); //打开com端口
comOpera.getSmsCode()
}
} // 程序入口
package xyz.game;
class GameMain{
public ComOpera comOpera = new ComOpera();
public void run(){
GameCatch gameCatch = new GameCatch()
gameCatch.catch(comOpera); //传递给其他对象 // other code
} public static void main(String[] args) {
GameMain game = new GameMain();
game.run();
game.comOpera.closePort(); //关闭com端口
}
}
这是简化后的代码,我初次读到这些代码的时候发现问题有二:一个类里可以有多达27个属性;代码长度可以平均达到每个文件400+行,那么我第一反应是这个程序在一个类里放入多个功能,从而导致类的臃肿。
再读下去,发现印证了我的猜测,仅仅在原有项目里并不算最复杂的ComOpera类里就有多个功能放入一个类的情况,原设计将短信操作和COM操作放到同一个类里去实现了,原因是短信是通过com口实现通信的,但是我很明显的感觉到SMS操作和COM操作明显是不同的功能模块,理由有二:发送短信未必只能采用COM口,而COM口也未必只能发送短信。独立开来这两个模块会有更好的复用性,清晰性。
但是这样做也勉强可以接受:就是当需求未清楚时,可以采用最简单的设计方案,毕竟研发成本也是有限的,例如在这个项目中,假如就只需要COM口收发送短信,如果提前解耦那么成本就会增加,用不到的话就是浪费。而且增加接口也会增加理解的难度
然而需求变更还是出现了:短信的通信方式从COM口变更成为从数据库进行读写,那么朋友打算怎么干:
1) 写一个读写数据库的类
2) 在GameCatch里替换ComOpera;
3) aObjectOfOtherClass.method里传入一个新对象
这完全是打补丁的方案!!!敏捷设计之所以可以不做任何设计即可进入开发,是因为敏捷设计在需求变更之际。会不断的提炼接口,抽象操作,按照敏捷的理论,需求变更不是让程序越改越烂,而是越改越好。也就是说好的程序员和烂的程序员在开始的时候可以写出差不多的代码,但是随着项目的发展,需求的变更,好的程序员可以把代码越改越好而烂的程序员只能让代码越来越烂(忏悔下,俺原来就是传说中的烂程序员啊)当然,话是这么说,需求变更对于程序员的考验还是很严峻的,有追求的人还是应该直面压力和挑战
好。下面是我的解决方案:
// 短信接口
package xyz.game;
public class SmsCodeMgr {
public String getSmsCode() {
return "";
}
} // 短信接口的数据库实现
package xyz.game;
public class SmsCodeByDb extends SmsCodeMgr {
public String getSmsCode() {
// todo
}
} // 短信接口的COM实现
package xyz.game;
public class SmsCodeByCom extends SmsCodeMgr {
private ComOperNew comOper;
public SmsCodeByCom(){
comOper = new ComOperNew()
comOper.openPort();
} public String getSmsCode() {
// todo
} protected void finalize() { // 对象消亡时需要关闭com口
comOper.closeProt();
}
} // COM接口 为一切需要COM通信的对象服务
package xyz.game;
public class ComOperNew {
public void openPort() throws Exception {...} // 打开com
public void closeProt() {...} // 关闭com
public String readMsg() {...} // 读取com消息
public void writeMsg(String msg) {...} // 写com消息
public boolean getComStatus() {...}
public String unicode2gb(String hexString) {...}
public boolean writeMsgWithResultOK(String cmd)
public String writeMsgWithResult(String cmd) {...}
} // 业务逻辑模块
package xyz.game;
class GameCatch{
public void catch(SmsCodeMgr smsmgr){
smsmgr.getSmsCode()
}
} // 程序入口
package xyz.game;
class GameMain{
public SmsCodeMgr smsmgr = new SmsCodeMgr();
public void run(){
GameCatch gameCatch = new GameCatch()
gameCatch.catch(smsmgr); //传递给其他对象 // other code
} public static void main(String[] args) {
GameMain game = new GameMain();
game.run();
}
}
其实整个方案里最可不控制的是什么呢?就是原来ComOpera类里读写COM的接口被暴露出去,原来的设计是Com只为短信服务,结果main和其他模块还是知道了短信是需要com的,而且需要为这个事实进行服务,现在通过DB来实现,这些打开关闭COM端口的服务就不在需要了,但是这个时候外界已经知道这件事情了,所以需要在整个系统里去掉openPort,closePort这样的语句,其实这就是设计的僵化
软件预构说的好:软件开发有两个极端:一是瀑布模型二是敏捷,瀑布模型是极端的分析设计,敏捷是极端的不设计,其实现实生活里的软件项目处于这两个极端中的某个位置,如何把握度是个艺术
一次java程序的重构的更多相关文章
- java程序性能优化
一.避免在循环条件中使用复杂表达式 在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快. 例子: import java.util ...
- 回答阿里社招面试如何准备,顺便谈谈对于Java程序猿学习当中各个阶段的建议
引言 其实本来真的没打算写这篇文章,主要是LZ得记忆力不是很好,不像一些记忆力强的人,面试完以后,几乎能把自己和面试官的对话都给记下来.LZ自己当初面试完以后,除了记住一些聊过的知识点以外,具体的内容 ...
- Java程序员学习之路
1. Java语言基础 谈到Java语 言基础学习的书籍,大家肯定会推荐Bruce Eckel的<Thinking in Java>.它是一本写的相当深刻的技术书籍,Java语言基础部分基 ...
- 【转】java架构师之路:JAVA程序员必看的15本书的电子版下载地址
作为Java程序员来说,最痛苦的事情莫过于可以选择的范围太广,可以读的书太多,往往容易无所适从.我想就我自己读过的技术书籍中挑选出来一些,按照学习的先后顺序,推荐给大家,特别是那些想不断提高自己技术水 ...
- 如何准备阿里社招面试,顺谈 Java 程序员学习中各阶段的建议
引言 其实本来真的没打算写这篇文章,主要是LZ得记忆力不是很好,不像一些记忆力强的人,面试完以后,几乎能把自己和面试官的对话都给记下来.LZ自己当初面试完以后,除了记住一些聊过的知识点以外,具体的内容 ...
- 阿里面试回来,想和Java程序员谈一谈(转载)
引言 其实本来真的没打算写这篇文章,主要是LZ得记忆力不是很好,不像一些记忆力强的人,面试完以后,几乎能把自己和面试官的对话都给记下来.LZ自己当初面试完以后,除了记住一些聊过的知识点以外,具体的内容 ...
- Java程序中调用Python脚本的方法
在程序开发中,有时候需要Java程序中调用相关Python脚本,以下内容记录了先关步骤和可能出现问题的解决办法. 1.在Eclipse中新建Maven工程: 2.pom.xml文件中添加如下依赖包之后 ...
- [JAVA] java程序性能优化
一.避免在循环条件中使用复杂表达式 在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快. 例子: import java.util ...
- Java程序员必备的 15框开发工具
15款Java程序员必备的开发工具 如果你是一名Web开发人员,那么用膝盖想也知道你的职业生涯大部分将使用Java而度过.这是一款商业级的编程语言,我们没有办法不接触它. 对于Java,有两种截然不同 ...
随机推荐
- SWOT分析法
SWOT(Strengths Weakness Opportunity Threats)分析法,又称为态势分析法或优劣势分析法,用来确定企业自身的竞争优势(strength).竞争劣势(weaknes ...
- windows 编程 —— 子窗口 与 子窗口控件
目录: 子窗口与主窗口的交互 子窗口控件 按钮类别 button 滚动条类别 scrollbar 静态类别 static 编辑框类别 edit 清单方块 listbox 子窗口与主窗口的交互 创建窗 ...
- javascript 如何避免属性访问错误
var book = {subtitle: "Bible"}; var bookName = book.name.length // 这时候会出错, 因为试图查询这个不存在的对象 ...
- CTime,Systemtime的比较还有转换成日期格式。
vc为我们提供了两种日期型的变量. 一种是CTime.他的缺点就是年份只支持到2038年,以后的日期就不支持啦,如果你的项目有20-30年的寿命,你就选择使用SYSTEMTIME.这个时间函数来进行比 ...
- Pascal's Triangle II
Given an index k, return the kth row of the Pascal's triangle. For example, given k = 3, Return [1,3 ...
- jQuery 對table的基本操作
一.鼠标移动到行更换背景色: css样式: .hover{ background-color: #cccc00; } Js脚本: $(document).ready(function () { //鼠 ...
- Win7系统安装MySQL5.5.21图解教程
转自:http://www.jb51.net/article/37310.htm 这篇文章主要介绍了如何在win7中安装mysql,所以加上了MySQL的下载过程,希望对需要的人有所帮助 大家都知道M ...
- Gradle 用法总结
用过android studio的对gradle应该都不陌生了,gradle文件的基本配置大同小异,略做了解使用应该是没什么问题了.但是深入细致的了解一下对于理解项目还是很有帮助的,尤其是遇到一些配置 ...
- 将用户信息保存到Cookie中
/** * 把用户保存到Cookie * * @param request * @param response * @param member */ private void rememberPwdA ...
- C# Byte[]数组读取和写入文件
这个项目我用的是asp.net构建的,代码如下 protected void ByteToString_Click(object sender, EventArgs e) { string conte ...