今天在总结最近一个项目的时候,突然灵感一现,理解了一些以前困惑的问题,和自己一直以来的设计上的问题,这里来分享下。
抽象与封装,是我们在做设计和写程序的时候经常用到的,然而很多时候抽象封装的不对则会造成很乱、很遭的设计。在我最近的项目里就很有体会。场景是这样的,有一个新闻表单,用户填写然后提交,程序要做的就是检查数据(包括是否合法,是否为空等),如果没有错误就向数据库中插入一条数据,如果验证不通过则通过弹窗的方式提示用户,然用户继续输入。然后对于实现就是下面这样的:
{
// 验证数据
$bean -> validate()
}
catch (BeanException $e )
{
// 通过弹窗的方式提示用户
halt_js( $e -> getMessage();
}
// 获取验证后的数据
$post = $bean -> get_array();
// 插入一条数据
$db -> insert( $table , $post );
但是发现除了这个表单,其他的表单都是这样的,发现这是重复代码,老是需要复制粘贴,于是就想把它用一个类,或者函数给封装起来,这样每次调用就方便了。就产生了下面的代码:
然后在insert中就做了上面的验证并提示的功能,但是后来有这么一个需求,我需要一份bean验证后的数据,这个时候问题就来了,因为在这个新的封装类中就没办法获取到了;后来又来了一个需求提示方式要换了,因为是ajax的方式来提交的,这个时候也没办法了,马上就感觉头大起来了,而且,对于这么一堆乱代码,自己头也很晕,不知道这个封装到底是什么意义,就发生了厌恶之感,不太愿意去写了。
出现这种结果的原因在于错乱的抽象与封装,对于封装还仅仅停留在代码的层次上,看到重复的代码就用一个函数包装起来,这样维护起来就很痛苦了,因为第一,当需求变化影响到这个封装的时候由于事先考虑的东西很少,只是因为这段重复的代码就封装了,很难应对需求的变化,而且加上这个封装没有在概念上形成一种意义的话,对你理解代码没有帮助,于是维护问题就出来了。
所以我认为在做任何抽象和封装的时候,我们都应该是先从概念上来考虑,从概念的层次进行抽象,封装。比如像刚刚那个问题,首先考虑为什么这段代码是重复的,从概念上讲,它们都做了这几个动作,第一就是验证数据,第二就是出错用一种方式进行提示,成功就将验证后得到的数据插入。而之前的需求都是这样的,所以不会有什么问题,一旦我的步骤不是这样的时候就会出问题了,比如,我成功后不是立马将验证数据插入,先留下来一份我要用,然后这个时候再插入,就会没办法满足了。当我们从概念上理解这段代码后,我们就要进行抽象和封装,我们要封装的是这个做事的流程,抽象出来的就是这么一段流程,$beanDB就需要验证部分,需要提示部分,需要插入数据部分,而这每个部分都是可以随时更换的,这样当需求变化的时候我们就可以很方便的应对了,这个时候我们想到设计模式中,对于流程的封装就是模板方法,然后对于想更换显示方式,就想到策略方式了,用这两种设计模式就可以解决这个问题了。
在项目中还有个很严重的问题,在一个插入数据方法里放了太多的东西,以至于我都不敢再去调用它了。因为做项目的时候根本就没考虑清楚就开始写了,开始的时候就想这是一个向数据库插入数据的方法,但是当插入数据要做的事情多起来的时候,我就不断的给它加入新的代码,破坏了封装和抽象,同样是犯了上面说到的问题,没有从概念上考虑它到底是什么,应该负有什么责任,就随便的给它加代码,破坏了概念上的封装。于是就会遇到和上面一样头疼的维护问题。
所以总结了一下后发现,在做设计的时候,我们都应该是针对概念进行抽象和封装,把概念弄清楚了,程序就很好写了,而且当变化来的时候,由于你之前考虑过这个概念,不要去动这个概念,那么不会发生严重的问题,头也不会很晕,不知道这个东西到底是什么了。而且如果是抽象出的概念,它的复用性也会更强,会加大系统的复用,提高可维护性。