fangzhzh
2013-06-07 23:47:22 +08:00
我是OO software engineer, 所以例子难免使用很多oo的概念.
设计模式,面向对象, 都是一种手段,不是目的.
# 几个大原则:
* 先想框架, 再想细节.
* 代码要分层, 划分好边界.
* 把最容易变化的部分抽象并隔离出来.
* 一个比较虚的, 简单->复杂. 考虑的足够复杂, 实现就可能很简单.
* 解耦合. 分配好职责,一个类只做并做好一件事情, 通知机制尽量不要使用依赖过强的方式.
## 先框架, 再细节
上来就写代码不是一种好习惯.
写代码前, 技术选型以后, 先不要想代码上怎么实现. 要不要多线程, 是不是要使用stl, boost, 是不要要使用一些第三方库, 是不是要自己实现链表, 字典等等. 这个功能是不是适合一个排序.先不要从这些地方想.
先想一想, 要做什么,逻辑上可以分成几个部分, 每个部分的关系, 之间的联系. 然后再想每个部分是什么, 需要具体做哪些工作, 实现哪些功能. 最后再考虑这些功能需要使用什么技术.
## 分层
### 大方面:
一般是MVC, M数据层, V层肯定是要分开的. 控制层简单了和UI混在一起,有时候单拎.
### 小方面:
一般的小功能一个工作类就可以搞定了. 稍微大一些的,举个异步的列子. 实现上一般有一个 manager管理所有的请求, 或并行, 或队列串行, 把请求分发给正确的工作类. 工作类结束了, 把结果交给manager , manager负责把结构返回给请求者.
层次上, 工作类和管理类分开, 客户只看到了管理类的统一接口, 接口类不变, 工作类可以有无限增加, 并且可以透明替换. 那么client不再依赖工作类, 边界划分的很清楚.
一个项目改动最多的就是工作类--即业务逻辑处理类. 分好层+边界, 多次的修改也不会对框架, 层次破坏, 也就不会乱了.
## 把最容易变化的部分抽象并隔离出来
四人帮的设计模式你如果看过的话, 应该看到过这句话很多次. 把最容易变化的部分抽象出來, 就可以打到添加,修改需求时, 改动不影响以前代码最小.
抽象不是为了重用, 而是为了被重用. 接口是抽象的一种实现方式. 如果设计的足够精良, 那么你的设计就会对修改封闭, 对添加开放.
举个烂大街例子: 你设计个一个类叫animal, 你需要实现叫声这个方法, 你可以使用
if( 汪星人)
汪汪
else if( 喵星人 )
喵喵
….
于是每增加一个动物,你的代码就要加上一行 else if, 修改原来代码.
如果把此接口抽象出来, 每个动物尽管实现自己的doBark好了, 那么 代码简单到
ani.doBark();
具体doBark, 由自己确定, 以后增加了类, 只需要这个类实现了doBark接口, 就可以不修改以前代码的基础上, 直接被以前的代码使用.
这个例子太简单, 太肤浅, 其实根本说明不了什么. 但是这种想法是要牢记的, 把*最容易变化*的部分抽象出来.
## 一个比较虚的, 简单->复杂. 考虑的足够复杂, 实现就可能很简单.
这个本来就很虚, 说起来就更虚的. 最好不说了.
## 解耦合. 通知机制尽量不要使用依赖过强的方式.
我说一个实际的问题吧. c++的数据库类D. 负责接受请求, 查询数据库, 将数据发送回去. 最显然的解决方案是: 客户类A像数据库类D发送请求, D分析请求, 是全部查询, 还是部分查询, 是不是可以查询, 还要考虑多个A之间的互斥.
如果可以查询, 那么D查询数据库, 打包取回来的数据, 返回给A. 如果不能查询, 那么本次的请求就丢掉了.
一种解耦合的方式, 队列+变量.
A的请求, 请求时更新 最近一次的请求时间, 把具体请求入队列, 然后A就可以返回.
D 根据自己的状态, 看是否有足够资源执行此次请求, 不行,就队列中等待. 直到有足够资源执行此次请求.
打包结果, 放入结果队列. A可抵达, 使用回调函数, 通知A 返回的结果. 如果A此时不可用, 同样后台等待下次发送结果.
这样保证了,请求不会丢, 结果不会丢, A不用无限等待D的执行过程. 解耦了A的请求与数据库查询操作.
# 上边是战略,下边讲一下战术
* 改代码尽量不影响以前的逻辑
* 复杂的程序逻辑,先用一些条件去掉不可能的情况
* 编写完代码的选择
## 改代码尽量不影响以前的逻辑
这个很容易理解,不容易做到. 这个在修改已有的代码的是很重要的.
千万不要*随便修改*已有的经过检验的业务逻辑, 哪怕你一百万的确定,你可以改对. 不要那么做.
需要需要修改以前代码的情况,大多数是新增了需求, 那么找到合适的位置, 把以前没有过滤的情况,过滤掉. 不要直接修改以前的代码.
## 复杂的程序逻辑,先用一些条件去掉不可能的情况, 每一个顺序下去的条件,都是互斥的
我以前写代码习惯这样
if(可行)
{
if( 条件1)
bla;
else if(条件2.1 && 条件2.2 )
{
if(条件4)
}
}
这种代码写下去,很恐怖.
后来学会了,
if(不可行)
return;
if(条件1)
bla;
if(!条件1 && (条件2.1 && 条件2 )) // !条件1, 这个保证了和上边的互斥, 在特别复杂的逻辑时,要容易理解的多
bla;
## 编写完代码的选择
一般人编完代码,就Run and Pray. 但是这是事倍功半的.
一种实践证明的方法是自己code review. 自己的代码刚写完是很难发现错误的, 所以我有一些 checklist
* 数据切片
关键数据, 用搜索功能, 遍历他出现的地方, 是不是出现了不该出现的地方, 是不是在该出现的地方没有出现,这种办法可以杜绝很多的低级的 typo错误. 而这种错误是最难找的.
* 控制切片
遍历所有的if else, 是不是覆盖了你想要的所有情况, 多否定自己的想法, 如果还有其他情况呢, 如果不是专业昂呢. 脑海中做几个边界测试, for, while的上下边界, if的典型数据.
太多了, 码字辛苦.
虽然码字有这么多,我认为对楼主的帮助仍然不会很大. 可能会让楼主觉得, 哇哦,好牛逼啊. 但是实际操作上, 楼主仍然觉得是没有操作性.
所以,我真正的建议, 找一个好的leader,或者伙伴,表现你的诚意,和可以栽培的潜力, 一个好leader ,可以让你的成长速度加倍, 有些东西是实践中来的,必须是你做了烂的设计, 别人做出不一样的设计; 或者你写了烂代码, 别人给出不一样的代码, 让你对比,你才会有切身的体会, 深刻的体会.
纸上得来终觉浅,绝知此事要躬行.