设计模式沉思录

来源:互联网 发布:林书豪纪录片 知乎 编辑:程序博客网 时间:2024/05/04 13:34

最近在读一本超高分的编程语言书《Fluent Python》,网评的高分绝对实至名归。这本书引起了两方面的反思:其一是语言学习方面,Fluent用得非常恰当,流利二字反映出我们在学习任何一门新语言时(不管是编程语言还是自然语言),都试图用旧的(母语的)思维去“扭曲”它而没有做到真正的地道和流利,关于这一方面会单独写一篇关于Python学习的文章;其二就是关于设计模式方面的反思,为什么会有设计模式,设计模式是万能的吗,这些也就是本文关注的重点。


1.抽象(Abstraction)

从软件开发的角度来讲,《Code Complete》对什么是抽象有不错的解释。所谓抽象就是:概念的聚合(Aggregate),可以很安全地忽略细节去使用一个概念,在不同的层次处理不同的细节。现实世界中很多东西已经是某种程度上的抽象了,举个例子:当你开门时,你直接去操纵门把手就行了,你不会去操心门具体用的什么木质材料、甚至分子层面,否则每天你开门时都将寸步难行。当你没能正确地抽象时,你的系统就像一扇过度复杂而无法打开的门,而好的开发者则会从门把手、门、房子等(对应软件开发中的方法、类、包等层次)各个层面创造出正确的抽象来降低复杂度。

《Code Complete》说过,软件开发的首要任务就是处理复杂度,而降低复杂度的武器就是抽象。所以说抽象隐藏了背后的细节,让你拿来即用,一层一层地构造更加复杂的抽象概念。从这一点上来说,抽象就像软件模块一样,从硬件到操作系统到编译器到编程语言,从ISO模型的物理层到链路层到网络层到应用层等,每一层抽象都各司其职,对外隐藏细节,内部处理复杂。那么设计模式是不是一种抽象呢?答案就在下文。


2.模式:失败的抽象

在这篇Is there an applied mathematics equivalent to the software engineering idea of design patterns?的Quora问答中,最高票回答说得非常精彩,在此摘录并作简单的翻译:

A design pattern is a commonality found in different pieces of code. An abstraction is also a commonality between pieces of code, but it’s typically a commonality that has been factored out, for example, into a library function that can be reused. A design pattern is a failed abstraction. It’s a commonality that for some reason couldn’t be factored out. Instead it gets described in English (or other natural language) and if you want to use it you read the English and use that as a guide to writing code. It’s a lot easier to use an abstraction because then you can just call it from your code instead of rewriting it. What can be abstracted depends to some extent on your programming language. For example in Java you might use the visitor pattern. But in ocaml or Haskell you just write a recursive function. The ability to visit each element of a tree structure is already built right into functional languages obviating the need for a pattern.

Mathematics notation is very flexible. If it doesn’t already do what you want you can invent new structures and notation. This means that if you see common structure in two separate proofs then you have a good chance of extracting out the common structure and making that a reusable theorem. For example there are counting arguments that work for both the set of integers and the set of Rubik cube moves. Both these sets form groups and the common structure can be abstracted out into a theorem of group theory.

But sometimes the structure shared between two theorems is too difficult to factor out. Maybe it’s a bit vague, or the similarity isn’t an exact correspondence. Then you have a design pattern. I think these things correspond to what mathematicians might call an “argument” or a “trick”. For example there’s the Proof by infinite descent. I don’t think there’s a single theorem that encompasses all descent arguments. So it’s a pattern rather than a single abstraction. Or maybe Terry Tao’s amplification trick. Again, I don’t think there’s one theorem at work here. It’s more of an approach to solving a class of problem so again it’s a pattern. Another example from Tao might be finitization (Page on York).

设计模式是失败的抽象,它是由于某种原因而无法提取出来的共性。它通常用英语或其他自然语言来描述,当你想使用它时就去读这份“指南”去指导你写代码。相反地,抽象更容易使用,因为你直接“调用”它,拿来即用而非重写它。在数学中也如此,当你看到两处证明中有类似的结构时,把它提取出来作为一个可重用的定理。但有时这种共通的结构非常难以提取出,这时你就有了一个设计模式。

3.你的模式,我的语言特性

在《Fluent Python》一书中第六章的开篇提到,Peter Norvig说GoF(《设计模式》书的四位作者)的23种设计模式中,有16种在动态语言中都更简洁甚至不见了。一个令人震惊的类比是:对于过程语言来说,它的设计模式就是继承、封装和多态。在函数为“一等公民”的语言中,Norvig建议我们重新思考Strategy、Command、Template method和Visitor模式。

以最明显的Python对Strategy的原生支持为例,看一看动态语言(Python是动态强类型)对传统设计模式的颠覆。经典的Decorator装饰器模式,在Python中信手拈来,一个简单的返回匿名函数的函数,就可以当作一个装饰器来用。装饰器或者说面向方面编程(AOP)在Python中变得格外简单。

import timedef timeit(func):    def inner(num):        start = time.time()        ret = func(num)        print 'Cost time: {} (s)'.format(time.time()-start)        return ret    return inner@timeitdef do_sth_slow(num):    time.sleep(1)    return num * numprint 'Result: {}'.format(do_sth_slow(5))"""Cost time: 1.00513315201 (s)Result: 25"""

这一个例子只是抛砖引玉,还有更多的模式值得深入思考。GoF的《Design Pattern》作为历经时间考验的经典,其地位是否受到了挑战,也需要花时间去重读来重新定位和评价。更多内容,待之后编写专门的Python学习系列文章以及设计模式重读文章再做整理。

原创粉丝点击