一次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,有两种截然不同 ...
随机推荐
- SharePoint Server 2010安装图解
SharePoint Server 2010作为MOSS 2007的升级版本,自从2009年底发布Beta版本以来就备受关注,网络上已经出现了很多相关的文章,其中也不乏中文的信息. 最近SharePo ...
- Unity绘制GUI连连看(尚未完善效果和重置)
OneImage.cs public class OneImage : MonoBehaviour { public int row, col; public Rect rect; public Te ...
- Exception in thread "main" com.sun.xml.internal.ws.streaming.XMLStreamReaderException: unexpected XML tag.
webservice 抛异常,原因: public class HeaderHandler implements SOAPHandler<SOAPMessageContext>{ @Ove ...
- Android开发系列(十八):自己定义控件样式在drawable目录下的XML实现
在Android开发的过程中,我们常常须要对控件的样式做一下改变,能够通过用添加背景图片的方式进行改变,可是背景图片放多了肯定会使得APK文件变的非常大. 我们能够用自己定义属性shape来实现. s ...
- HDU1247 Hat’s Words 【trie树】
Hat's Words Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Tota ...
- monkeyrunner 详细介绍
MonkeyRunner: monkeyrunner工具提供了一个API,使用此API写出的程序可以在Android代码之外控制Android设备和模拟器.通过monkeyrunner,您可以写出一个 ...
- Zend框架2入门(二) (转)
Zend框架2使用一个模块系统,和你组织内每个你的主应用程序特定代码模块.骨架提供的应用程序模块是用于提供引导,错误和路由配置到整个应用程序.它通常是用来提供应用水平控制器,比如说,应用程序的主页,但 ...
- 使用正则表达式给网址添加a标签
在内容中存在链接地址的时候,我们在前台显示时一定想自动的将地址添加上a标签,方便用户进入链接.使用正则表达式就能轻松实现. Jsvascript正则替换 //javascript 正则替换 var s ...
- Mounting File Systems
1.Mounting File Systems Just creating a partition and putting a file system on it is not enough to s ...
- C:应用于字符串处理函数
出于对C的不够熟悉,在读代码的过程中,平凡出现的字符串处理函数,成为了一个理解代码的大问题. 为了更方便的读取和理解代码,特意将接触到的字符串处理函数列出,方便查询: 1.strstr(str1,st ...