// 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程序的重构的更多相关文章

  1. java程序性能优化

    一.避免在循环条件中使用复杂表达式 在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快. 例子: import java.util ...

  2. 回答阿里社招面试如何准备,顺便谈谈对于Java程序猿学习当中各个阶段的建议

    引言 其实本来真的没打算写这篇文章,主要是LZ得记忆力不是很好,不像一些记忆力强的人,面试完以后,几乎能把自己和面试官的对话都给记下来.LZ自己当初面试完以后,除了记住一些聊过的知识点以外,具体的内容 ...

  3. Java程序员学习之路

    1. Java语言基础 谈到Java语 言基础学习的书籍,大家肯定会推荐Bruce Eckel的<Thinking in Java>.它是一本写的相当深刻的技术书籍,Java语言基础部分基 ...

  4. 【转】java架构师之路:JAVA程序员必看的15本书的电子版下载地址

    作为Java程序员来说,最痛苦的事情莫过于可以选择的范围太广,可以读的书太多,往往容易无所适从.我想就我自己读过的技术书籍中挑选出来一些,按照学习的先后顺序,推荐给大家,特别是那些想不断提高自己技术水 ...

  5. 如何准备阿里社招面试,顺谈 Java 程序员学习中各阶段的建议

    引言 其实本来真的没打算写这篇文章,主要是LZ得记忆力不是很好,不像一些记忆力强的人,面试完以后,几乎能把自己和面试官的对话都给记下来.LZ自己当初面试完以后,除了记住一些聊过的知识点以外,具体的内容 ...

  6. 阿里面试回来,想和Java程序员谈一谈(转载)

    引言 其实本来真的没打算写这篇文章,主要是LZ得记忆力不是很好,不像一些记忆力强的人,面试完以后,几乎能把自己和面试官的对话都给记下来.LZ自己当初面试完以后,除了记住一些聊过的知识点以外,具体的内容 ...

  7. Java程序中调用Python脚本的方法

    在程序开发中,有时候需要Java程序中调用相关Python脚本,以下内容记录了先关步骤和可能出现问题的解决办法. 1.在Eclipse中新建Maven工程: 2.pom.xml文件中添加如下依赖包之后 ...

  8. [JAVA] java程序性能优化

    一.避免在循环条件中使用复杂表达式 在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快. 例子: import java.util ...

  9. Java程序员必备的 15框开发工具

    15款Java程序员必备的开发工具 如果你是一名Web开发人员,那么用膝盖想也知道你的职业生涯大部分将使用Java而度过.这是一款商业级的编程语言,我们没有办法不接触它. 对于Java,有两种截然不同 ...

随机推荐

  1. HDOJ(HDU) 2103 Family planning(需要注意范围)

    Problem Description As far as we known,there are so many people in this world,expecially in china.Bu ...

  2. uboot启动后在内存中运行裸机程序hello

    如题,实现过程中发现3额问题,先写下来,待解答: 1.uboot启动后再dnw上打印许多信息,我想改变其中的打印信息或加上自己的打印信息以证明程序运行到何处.修改完后重新编译uboot.bin. 在D ...

  3. Unity3D基础学习 NGUI Example 7-Scroll View(Panel)制作固定包裹栏,点击传递参数显示物体

    最终效果如下: 实现ScrollView主要是NGUI的三个脚本"UIDraggable Panel","UIGrid","UIDrag Panel ...

  4. Android ArrayAdapter MultiAutoCompleteTextView

    MultiAutoCompleteTextView 继承自AutoCompleteTextView,它和AutoCompleteTextView不同的就是能处理多个输入字段,如发送短信界面的联系人列表 ...

  5. 第二节,CCSpriteBatchNode CCSpriteFrameCache

    1,CCSpriteBatchNode 精灵集合类 其中Batch的英文含义是一批,一群的意思.他的对象常常包含了许多的精灵对象,这些精灵对象有一个共同的特点,那就是使用同一张文理图片.虽然是同一个纹 ...

  6. 使用MFC读写Excel

    _Application m_ExlApp;   //组件服务器的各个classes     _Workbook m_ExlBook;     Workbooks m_ExlBooks;     _W ...

  7. STL之deque双向队列

    deque双向队列是一种双向开口的连续线性空间,可以高效的在头尾两端插入和删除元素,提供随机访问,deque在接口上和vector非常相似,下面列出deque的常用成员函数: Table 6.9. C ...

  8. C语言原码反码补码与位运算.

      目录:     一.机器数和真值     二.原码,反码和补码的基础概念     三.为什么要使用原码,反码和补码     四.原码,补码,反码再深入     五.数据溢出测试     六.位运算 ...

  9. UWP APP 开发日记

    最近需要使用C#开发UWP应用,以前学习过C,这回就是快速看了一下C#的一些特别之处,然后就进入到了实战练习当中. 1.按照MSDN的教程自己搭建了一个简单的“Hello, world”应用.是使用C ...

  10. mysql limit性能问题

    offset大的时候的比较 1. SELECT * FROM persons LIMIT 200000,10; 耗时0.109s 2. SELECT *FROM persons WHERE id> ...