一次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,有两种截然不同 ...
随机推荐
- app开发历程——android手机显示服务器端图片思路
以前自己都不知道怎么去显示服务器端的图片,还好在apkbus论坛上找到一个特别简单的例子.虽然一天天忙忙碌碌,但是自己内心其实有一种想逃的心里,说不定哪天就会冒出来. 1.首先服务器端图片 这里的Im ...
- UVAlive4287 Proving Equivalences(scc)
题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=10294 [思路] 强连通分量. 求出bcc后,缩点形成DAG,设D ...
- Python自动化之Django的CSRF
什么CSRF? CSRF, Cross Site Request Forgery, 跨站点伪造请求.举例来讲,某个恶意的网站上有一个指向你的网站的链接,如果 某个用户已经登录到你的网站上了,那么当这个 ...
- Java并发编程:Future接口、FutureTask类
在前面的文章中我们讲述了创建线程的2种方式,一种是直接继承Thread,另外一种就是实现Runnable接口. 这2种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果. 如果需要获取执行结果,就 ...
- jQuery.isEmptyObject()函数用于判断指定参数是否是一个空对象。
jquery中有一个函数isEmptyObject()用来判断制定参数是否是一个空对象. 示例如下: function isEmptyObject(e) { var t; for (t in e) r ...
- 1629 - Cake slicing(DP)
花了近2个小时终于AC,好爽.. 一道类似于最优矩阵链乘的题目,受<切木棍>那道题的启示,该题的原理也是一样的,仅仅只是变成了且面积.那么对应的也要添加维度 . 显然要完整的表示状态,最少 ...
- C++11 tuple
tuple元组定义了一个有固定数目元素的容器,其中的每个元素类型都可以不相同,这与其他容器有着本质的区别.是对pair的泛化. 首先来介绍元组的创建和元组元素的访问.通过make_tuple()创建元 ...
- sql循环遍历
<sql id="Example_Where_Clause" > <!-- WARNING - @mbggenerated This element is aut ...
- maven部署命令
参考文档:http://blog.csdn.net/woshixuye/article/details/8133050 http://www.blogjava.net/itvincent/archiv ...
- 使用Canvas实现下雪功能
示例代码: <html> <head> <meta http-equiv="Content-Type" content="text/html ...