Command模式与动态语言

来源:互联网 发布:java主方法 编辑:程序博客网 时间:2024/05/01 22:56

在Gof的设计模式中,有一个模式引起的争议比较大,有很多人甚至认为这个模式应该排除在OO模式之外,原因在于它不具有OO的特性。不管怎么说,这个引起争议的模式还是非常特别的,只要我们静下心来分析一下,不难发现它的迷人之处。这个模式就是Command模式。

一、基本的Command模式

最简单的Command模式中,包含一个ICommand接口,接口只有一个方法Execute。不同的Command对象实现这个接口,客户端程序通过接口访问Execute方法的不同实现。


好像也没什么,这个模式太简单了,几分钟就能学会。

模式本身是简单的,但模式中包含的思想就不简单了。有人认为Command模式不够OO的主要原因就是它用OO的思想封装一个方法,将方法当作对象来使用。OO的思想中,所有的名词都是对象,比如说人;对象有自己的属性,比如说身高、体重;对象有自己的方法,比如说人会跑,所以有一个Run()的方法。对象、属性、方法是面向对象的几大基本特征。那这个Command模式在搞什么鬼——它居然将方法当作对象!太不可理解了,世界上根本就不会有Run这个对象。

Command模式的思想就是模糊了方法与对象的界限。上面说的场景其实可以用下面的方式来实现。


其中函数FunctionA、FunctionB、FunctionC分别对应到对象CommandA、CommandB、CommandC。不过采用Command模式比这种方法要更加灵活可变。

二、静态分派与动态分派

分派(Dispatch)可以说是一种定位。不管我们采用什么语言编写程序,在现在的计算机体系结构下,代码最终都会变成函数调用。从代码到具体的函数调用这个过程就是分派。

比如说,在图1中的Client通过ICommand接口调用具体的Command对象Execute方法。这个过程就是一个分派。不过这个分派是在程序运行时才能确定下来,编译的时候不知道Client将会调用A、B、C那个对象的方法,只有在运行时创建了对象后才知道。
在图2中的Client直接调用FunctionA、FunctionB、FunctionC。这个过程也是一个分派。这个分派是编译器就可以明确下来。

从上面的描述来看,分派有两种情况:如果分派过程在编译时就可以确定下来,就叫做静态分派,或者叫早绑定;如果分派过程需要在运行时才能确定下来,就叫做动态分派,或者叫做晚绑定。

在C++、Java、C#、Delphi等语言中overload是静态的分派,而override是动态的分派。

上面介绍的Command模式其实是利用override的特性将静态的分派转为了动态的分派,从而带来更大的灵活性。


三、让静态语言“动”起来

很多设计模式都是因为语言的限制而产生出扩充语言表现力的方法。设计模式会向两个方面转化:一方面转成语言层面,有些设计模式就可能直接成为语言的特性,比如说迭代器模式就是如此;另一方面转化成架构层面,变成架构设计的基本框架,比如说Facade和Adapter模式。

这篇文章中的Command模式目的也是扩充语言的表现力,实现函数调用的动态分派,这样运用设计模式可以让我们使用的语言带有动态语言的一部分特性。本来动态语言中的函数调用就远比常规语言要灵活得多。

在Gof的设计模式中,还有一个模式的关键也在于“分派”,就是Visitor模式,这要比Command模式复杂一些了。大家可以自己看看。等以后有时间我也会写一篇关于Visitor的文章。

动态语言的本质就是“晚绑定”,和这里的“动态分派”有着莫大的关联。我们可以通过设计模式让静态语言动起来,对于原本就动态的语言,有些设计模式可能就没有意义。

这里分析Command模式仅仅介绍了最基本的情况,对于一些复杂的变化也并不是动态语言就可以完全取代的。

四、不能“精通”的语言

精通不管对于什么来说都是非常困难的。“精”是指掌握语言本身的特征,能对语言灵活、精确地使用,“通”指的就是触类旁通,举一反三。

最开始学习编程的时候我们去学C++、Java、C#,这个时候只能学到“精”。等到几年之后,自认为够“精”了,然后去学设计模式,去学企业架构。这是一般人正常的学法。但是这样学却不能“精通”语言。就像上面说的,设计模式又很多会影响到语言,架构模式同样会从语言中的到灵感。

仅仅学习语言是不可能精通的,只有学习分析、设计后再和最基本的相互印证才能逐渐领悟到语言的真谛,达到“精通”吧。 




在Gof的设计模式中,有一个模式引起的争议比较大,有很多人甚至认为这个模式应该排除在OO模式之外,原因在于它不具有OO的特性。不管怎么说,这个引起争议的模式还是非常特别的,只要我们静下心来分析一下,不难发现它的迷人之处。这个模式就是Command模式。

一、基本的Command模式

最简单的Command模式中,包含一个ICommand接口,接口只有一个方法Execute。不同的Command对象实现这个接口,客户端程序通过接口访问Execute方法的不同实现。


好像也没什么,这个模式太简单了,几分钟就能学会。

模式本身是简单的,但模式中包含的思想就不简单了。有人认为Command模式不够OO的主要原因就是它用OO的思想封装一个方法,将方法当作对象来使用。OO的思想中,所有的名词都是对象,比如说人;对象有自己的属性,比如说身高、体重;对象有自己的方法,比如说人会跑,所以有一个Run()的方法。对象、属性、方法是面向对象的几大基本特征。那这个Command模式在搞什么鬼——它居然将方法当作对象!太不可理解了,世界上根本就不会有Run这个对象。

Command模式的思想就是模糊了方法与对象的界限。上面说的场景其实可以用下面的方式来实现。


其中函数FunctionA、FunctionB、FunctionC分别对应到对象CommandA、CommandB、CommandC。不过采用Command模式比这种方法要更加灵活可变。

二、静态分派与动态分派

分派(Dispatch)可以说是一种定位。不管我们采用什么语言编写程序,在现在的计算机体系结构下,代码最终都会变成函数调用。从代码到具体的函数调用这个过程就是分派。

比如说,在图1中的Client通过ICommand接口调用具体的Command对象Execute方法。这个过程就是一个分派。不过这个分派是在程序运行时才能确定下来,编译的时候不知道Client将会调用A、B、C那个对象的方法,只有在运行时创建了对象后才知道。
在图2中的Client直接调用FunctionA、FunctionB、FunctionC。这个过程也是一个分派。这个分派是编译器就可以明确下来。

从上面的描述来看,分派有两种情况:如果分派过程在编译时就可以确定下来,就叫做静态分派,或者叫早绑定;如果分派过程需要在运行时才能确定下来,就叫做动态分派,或者叫做晚绑定。

在C++、Java、C#、Delphi等语言中overload是静态的分派,而override是动态的分派。

上面介绍的Command模式其实是利用override的特性将静态的分派转为了动态的分派,从而带来更大的灵活性。


三、让静态语言“动”起来

很多设计模式都是因为语言的限制而产生出扩充语言表现力的方法。设计模式会向两个方面转化:一方面转成语言层面,有些设计模式就可能直接成为语言的特性,比如说迭代器模式就是如此;另一方面转化成架构层面,变成架构设计的基本框架,比如说Facade和Adapter模式。

这篇文章中的Command模式目的也是扩充语言的表现力,实现函数调用的动态分派,这样运用设计模式可以让我们使用的语言带有动态语言的一部分特性。本来动态语言中的函数调用就远比常规语言要灵活得多。

在Gof的设计模式中,还有一个模式的关键也在于“分派”,就是Visitor模式,这要比Command模式复杂一些了。大家可以自己看看。等以后有时间我也会写一篇关于Visitor的文章。

动态语言的本质就是“晚绑定”,和这里的“动态分派”有着莫大的关联。我们可以通过设计模式让静态语言动起来,对于原本就动态的语言,有些设计模式可能就没有意义。

这里分析Command模式仅仅介绍了最基本的情况,对于一些复杂的变化也并不是动态语言就可以完全取代的。

四、不能“精通”的语言

精通不管对于什么来说都是非常困难的。“精”是指掌握语言本身的特征,能对语言灵活、精确地使用,“通”指的就是触类旁通,举一反三。

最开始学习编程的时候我们去学C++、Java、C#,这个时候只能学到“精”。等到几年之后,自认为够“精”了,然后去学设计模式,去学企业架构。这是一般人正常的学法。但是这样学却不能“精通”语言。就像上面说的,设计模式又很多会影响到语言,架构模式同样会从语言中的到灵感。

仅仅学习语言是不可能精通的,只有学习分析、设计后再和最基本的相互印证才能逐渐领悟到语言的真谛,达到“精通”吧。 




原创粉丝点击