浅谈我对框架的理解
原文链接:http://www.felix021.com/blog/read.php?1793
有少量修改,如有疑问,请访问原作者...
Def:
一个完美的框架,应该是一个实现了对修改关闭,对扩展开放的框架。需要修改,意味这这个框架仍然存在瑕疵;不适合扩展,那就没有被称为框架所需的内涵。当然,完美的框架是不存在的,也没有一个框架能够满足所有的情况,所以需要根据具体的情况来做出选择。
Range:我觉得做出这个选择的最重要标准是系统的规模。
对于一个小型系统,也许是一次性的(没有多少扩展需求),或者代码比较少(修改起来比较容易),那么框架的存在就不一定是必要的了。不论是自己设计一个框架,抑或是学习并采用一个现有的框架,都需要耗费比较多的时间精力,对于一个小型系统而言,很可能得不偿失。当然,不需要框架并不意味着可以随意开发(随意开发的过程是痛苦的,越往后越明显,felix深有感受...),高内聚低耦合等基本的设计原则还是必须遵从的,这样能够使开发过程更简单。更严格一点说,一个良好的设计本身就带有一些框架的性质。
对于一个中型系统,如果规模虽然稍大,但是仍然可以在少数几个人的掌握之下,那么一个强大的框架对开发是有相当助益的。在这种情况下,学习框架的开销是可以接受的,一次投入多次产出:在掌握了框架以后,每当需要增加新的功能的时候,只需要按照框架的规则写一个模块并插入到系统中,多余的事情都由框架来完成,非常轻松。
对于一个大型系统,其规模已经大到不是几个人可以掌握的了,那么在开发之初对框架的选择是至关重要的。因为当系统大到一定规模再更换框架,在很多情况下是不现实的,所以在开发之前就必须有足够的考虑。一个强大的框架是必须的,但我觉得这还不是全部:这个框架还必须简单。俗话说计划赶不上变化,当初设计得再好的功能,逐渐也可能会不适应后来的需求(PM一句话,RD两行泪=.=),以至于成为整个系统的累赘。所以框架还必须要简单(无为而治)——这个简单不是说框架需要提供少的功能。引用讲述Unix设计哲学的一段话:
Strategy:策略与机制分离 这些是非常理想化的选择,但是实际中又存在许多难以避免的问题。
其一,温水煮青蛙
这个寓言大家都耳熟能详了,虽然其真实性有待验证,但是其寓意还是很有警示意义的。一个系统的规模并不一定是刚开始的时候就可以知道的。比如创业的小公司,刚开始可能只是设计一个小型或者中型的系统,直到某一天发现系统负载或者是其扩展性已经或者将在可见的未来无法满足要求。这时候为了发展只能进行底层的重构。
其二,机制和策略的矛盾
Unix哲学考虑得很好,程序应该分成机制和策略两块,但是将这二者完全划分清楚未必是好的,甚至是不可能的。如果框架完全不干涉策略的实现,那么意味着每一个模块的开发都会有更多的工作量。如果框架过多地干涉策略,那么意味着框架过于复杂,掌握框架的代价更高。所以这里存在需要权衡的地方,而权衡的标准,还是的得考虑系统的规模和复杂性。于是又回到上一个问题了。
其三,...
需求的不确定、某个语言的局限这样一些具体的问题,也许不应该放在这里,但是在实际的开发和维护过程中,他们又的确会困扰开发者。甚至让人头疼。
Conclusion:----
说了这么多,感觉有点虚,因为没有什么特别具体的例子。公司里的项目不适合拿来讨论,但是正好前几天跟同事聊到一个例子,觉得比较适合放在这里说说。
这个例子就是C++,和C。最近一段时间我对C++有一些排斥,所以很难保证我下面将要说的内容的中立性,有任何问题欢迎探讨。
我觉得C++本质上就是C的一个框架。C++包装了C语言,提供了一些方便开发的特性,比如对面向对象的支持,比如对泛型的支持。根据上面提到的命名方式,我们可以认为这些特性就是这个"C框架"提供的机制,而C++程序员开发相应的程序,就是使用这些机制来完成其特定的策略。另一方面,C++不仅提供了机制,还在一定程度上影响了策略的实现。
比如说,在C++中,类的成员函数是否具有virtual属性,决定了这个类(的这个成员函数)是否可以实现多态。当然,这可以看作是一种机制的实现,但是它不可避免地影响了具体的策略。更特别的是,如果一个被继承的类的析构函数不具有virtual属性的话,可能程序在运行过程中会出现内存泄漏。
比如说,当你编写一个inline函数的时候,你可能期望它总是被inline,但是可能由于某些你不知道的限制,实际上inline属性并没有生效,它还是作为一个函数被反复调用。
再比如说,当你使用一个模板的时候,你可能不会考虑到这些模板对内存的占用。但实际上,模板的每一次特例化,都会使得几乎相同的函数在内存中存在两份拷贝(也许这个例子有些牵强)。另一个模板的例子是在特例化的时候没有特别注意类型,比如说make_pair(1, 2.0)实际上创建了一个pair<int, float>,而不是pair<float, float>。
这些是多少都可以算做是这个C框架不仅提供机制,还影响策略的例子。我相信还有很多类似的例子是我不知道的,但是糟糕的是,要掌握这个C框架的代价太大。这也就是我近来对C++产生排斥感的主要原因(另一个原因是我担心C++用多了,以后写代码会越来越懒~~~)。
说了这些不是想说C++是多么不堪、不能使用,去年暑假有很长一段时间我在仔细学习STL,其中有很多很伟大的设计。从这个角度来说,对C++我是心存敬畏的。从框架的角度来看,C++实际上是一个很强大的C框架,很适合快速开发,比如写一个acm程序,我肯定用C++,好好用上STL。做一个小型的系统,我也许也会选用C++。我只是觉得,这个强大的框架做得不够简单,如果要考虑大型系统的开发,务必要仔细权衡。
---
最后,使用一个很著名的设计原则来结束这篇日志:
KISS: Keep It Simple, Stupid.
--
转载请注明出自 http://www.felix021.com/blog/read.php?1793 ,如是转载文则注明原出处,谢谢:)
RSS订阅地址: http://www.felix021.com/blog/feed.php 。
后记:关于对库和框架的选择问题:
从本质上说C++是C的一个语法扩展库,只是纳入了语言标准;正如boost是C++的预备役库,假以时日 boost 有可能成为标准库,即C的C++ 框架的一部分;
其中boost库的构建使用了标准框架,而这个库又构成C++扩展框架的一部分;
而对于程序构建,一个现成框架 只能构建一个模式的 系列软件;而库的使用 可以有任意发挥的空间,即必须自行设计框架。
最后:程序员的时间比机器的时间宝贵的多...这就是为什么选择C++的原因....