今天的问题有点意思:我们有停车场(ParkingLot),还有停车小弟(Attendant)。一个停车小弟要管理多个停车场,然后帮客人把车子泊到有空位的停车场去。然后老板说了,要有不同的策略来选择停车场:有时候要选到空位最多的,有时候要选到车子最少的,大老板的车要停到最贵的,熟客的车要停到最便宜的……
熟悉面向对象的程序员第一印象会想到Strategy模式。不过我不是,因为目前不是熟悉面向对象的程序员,熟悉函数要更多一些……(寒一下)。第一印象想起的是,停车小弟知道的多个停车场,其实就是一个list;给定一个条件从list里头挑出一个东西来,其实就是accumulate。所以,第一个想到的做法就是,先实现一个Accumulator,然后用一个binary functor来走accumulate,走完结果就出来了。Strategy是第二个念头冒出来……
问题在于这只是一个感觉,可是光凭感觉编程是不够的。感觉有可能会错,也有可能YAGNI(前面我已经overkill过一次了)。而且就像Jane说的,我们是consultant,是要把知识share给别人的。Strategy模式倒也罢了,若是一步跨上来就是一个accumulate,估计大半人都得晕菜了事——这个不是危言耸听,上次在项目里写了一个map和filter,连Andy都几乎晕菜,事后说是“clever code”,clever这就不是什么好词。fancy design不是毛病,但得有理由,而且得让客户也明白这个理由,不然客户就得说我们TWer拿着他们的钱在这边玩编码游戏。
所以今天很认真地跟着老师的步伐走……老实说不是很认真,不过大致是差不多的。于是一次一次地闻到了bad smell。先是logic switch,抓住它,把变化的和不变的分开,抽取出来,得到Strategy模式;然后是遍历列表的操作,抓住它,变化的部分抽取出来就是“两个停车场之间的比较”,于是用IComparer来实现比较算法,用ArrayList提供的Sort()方法一排序,取出第一个元素就OK。果然,最初的想法虽说大致不差,还是overkill了:这个需求底下,binary functor可以用IComparer来表达,accumulate也不用自己写的。
重构还没有做完,明天先把上面说的最后部分搞定,然后把Strategy删掉,就得到了符合我第一审美印象并且更加清晰和简单的代码。今天大概是TWU以来学得第二多的一天……学得最多的是业务流程建模和story那天,都语无伦次了。
今天另一个发现是Prefactoring:这是一本好书。仍然以今天的课来说,如果没有老师的引导,那么就要靠第一审美印象来引导了。当然smell也是引导,但big picture同样是很重要的。而且就像refactoring可以训练一样,big picture同样是可以训练的。恰好现在大好时机,很久没有时间和心情来看这种“基础”的书,真是享受。