四個程序員的一天 【轉載】

你,一個DotNet程序員,剛剛加入一個新項目組。除了你之外,其他的成員包括:Ceer,一直從事C項目的程序員,他剛剛轉入C#不到一個月; Jally,整天抱着本Design Pattern(沒錯,就是GoF的那本)在啃的前Java程序員;以及Semon,你對他完全不瞭解,只是聽PM介紹說他是搞Scheme的(傳說中的第二古老的語言LISP的方言之一)。不過你也沒在意,畢竟計算機這玩意,老東西是不吃香的。

週一,剛打開電腦,老闆就跑到你們組的辦公座面前:“好吧,夥計們,現在有個function需要你們來搞定。具體是這樣的:用戶輸入2個數,並輸入一個操作符。你根據輸入的情況來得出相應的運算結果。“


[plain] view plaincopy
01.Example: Foo(+, 1, 2) = 3; Foo(*, 3, 6) = 18; Foo(/, 2, 4) = 0.5    


Ceer最先作出反應:簡單嘛,判斷一下輸入的操作符就好了。說着,他很快在白板上寫出如下代碼: 

public class CStyle_Calculator    
02.{    
03. static public double Foo(char op, double x, double y)    
04. {    
05.  switch(op)    
06.   case ’+’: return x + y; break;    
07.   case ’-’: return x - y; break;    
08.   case ’*’: return x * y; break;    
09.   case ’/’: return x / y; break;    
10.   default: throw new Exception(”What the Hell you have input?");    
11. }    
12.}   


Jally只看了一遍,就捂着鼻子連連搖頭:好一股的代碼臭味。還不如看我用OO的方法來解決:

public interface I操作符 //誰說代碼不能寫中文的?恩恩    
02.{    
03. double 運算(double x, double y);    
04.}    
05.public class OO_Calculator    
06.{    
07. private I操作符 m_op;    
08. public OO_Calculator(I操作符 op)    
09. {    
10.  this.m_op = op; //依賴注入【注2】    
11. }    
12.    
13. public double Foo(double x, double y)    
14. {    
15.  return this.m_op.運算(x, y);    
16. }    
17.}    
18.    
19.public class 加法:I操作符    
20.{    
21. public double 運算(double x, double y)    
22. {    
23.  return x + y;    
24. }    
25.}    
26.    
27.public class 減法:I操作符    
28.{    
29. public double 運算(double x, double y)    
30. {    
31.  return x - y;    
32. }    
33.}    
34.    
35.public class 乘法:I操作符    
36.{    
37. public double 運算(double x, double y)    
38. {    
39.  return x * y;    
40. }    
41.}    
42.    
43.public class 除法:I操作符    
44.{    
45. public double 運算(double x, double y)    
46. {    
47.  return x / y;    
48. }    
49.}    
50.    
51.public class TheMainClass    
52.{    
53. static public void Main()    
54. {    
55.  I操作符 我的加法 = new 加法();    
56.  OO_Calculator 我的加法器 = new OO_Calculator(我的加法);    
57.  double sum = 我的加法器.Foo(3, 4);    
58.  System.Console.WriteLine(sum);    
59.  //sum = 7    
60.    
61.  //其他3個我就不廢話了    
62. }    
63.}  

你看着Jally把白板寫得密密麻麻之後,聳聳肩,暗歎,你們這些用java的廢柴,就一個運算器還搞出Interface這些東西,煩不煩啊。 讓你們見識見識DotNet的強大吧. 那個運算符我直接用delegate傳進去不就好了麼.

public delegate double TheOperator(double x, double y);    
02.    
03.public class Operators    
04.{    
05. static public double Add(double x, double y)    
06. {    
07.  return x + y;    
08. }    
09.    
10. static public double Sub(double x, double y)    
11. {    
12.  return x - y;    
13. }    
14.    
15. //乘,除法 我也懶得廢話了    
16.}    
17.    
18.public class DotNet_Calculator    
19.{    
20. public double Foo(TheOperator op, double x, double y)    
21. {    
22.  return op(x, y);    
23. }    
24.}    
25.    
26.public class TheMainClass    
27.{    
28. static public void Main()    
29. {    
30.  TheOperator myAdd = new TheOperator(Operators.Add);    
31.  TheOperator mySub = new TheOperator(Operators.Sub);    
32.    
33.  DotNet_Calculator dc = new DotNet_Calculator();    
34.  double sum = dc.Foo(myAdd, 2, 4); //sum = 6    
35.  System.Console.WriteLine(sum);    
36.  double sub = dc.Foo(mySub, 3, 7); //sub = -4    
37.  System.Console.WriteLine(sub);    
38. }    
39.}    

//dot net 下面還可以用CodeDom動態構造C#代碼,然後在內存編譯運行。

//如果覺得專門寫個Operators很煩的話,可以試試C#2.0的匿名方法 

很好,當你寫完代碼之後,挑釁的看着Jally,Ceer卻開始抱怨起來:”這不就是C裏面的函數指針麼,我也會...“

“然則DotNet下面的Delegate是類型安全滴...”你繼續洋洋得意./

而Semon,看了看你們3位華麗的代碼,啥也沒說,只是在鍵盤上敲下了2行代碼

(define (Foo op x y)    
02.(op x y))  

然後就下班了...

【注: scheme的代碼稍微解釋下:(+ 1 2) = 3, (* 3 4) = 12.】

至於Semon的解法:

[plain] view plaincopy
01.(define (Foo op x y)    
02.(op x y))    

看明白了麼,上面的代碼只有一個作用:第一行是函數頭,定義了一個叫Foo的函數。該函數接受3個參數op, x, y。

第二行定義了函數的行爲:把第一個參數op當作運算符,計算後面2個參數。

所以:(Foo + 1 2) = 3. (Foo / 12 6) = 2.

好了好了,不編故事了。

我只是想簡單的讓大家在繁忙的工作之餘,也瞅瞅Function Programming(函數編程)世界的美妙。函數編程,最大的特點是它是將函數作爲語言裏1st class的元素來對待的。一個函數可以接受另一個函數作爲參數,也可以把一個函數作爲結果來返回。這樣的函數我們稱爲Higher-order function。

那麼,Function Programming和我們傳統的面向對象有啥區別捏? 恩,這個嘛,扯得遠可以扯到圖靈機和馮·諾以曼這2種體系的差異...@_@不過那個太學術性,俺就不說了,有時間在『代碼之謎』系列文章裏面科普吧。不過有句話可以較好的概括FP和OO的區別(好吧,這個也是抄“紫皮書”上面的):

“Pascal是爲了建造金字塔...Lisp是爲了建造有機體...”“作爲Lisp的內在數據結構,表對於這種可用性起着重要的提升作用...”“採用100函數在一個數據結構上操作,遠遠優於採用10個操作在十個數據結構上工作”“金字塔矗立在那裏千年不變,而有機體則必須演化,否則就會消亡”。

而另一個總結得比較好的話是:(同樣是抄來的)

一個對象:一組相同的運算上面,外加不同的數據。(想想你的object,是不是這樣的?)

一個Closure:一組相同的數據,外加不同的操作。(Delegate就是這樣的思想,有興趣的話也可以去看看Ruby)

基本上,恩,沒啥說的了。 如果你感興趣的話,可以去看MIT SICP的課程(有在線版的,MIT也作爲Open Course開設了的) 


原文鏈接: 點擊打開鏈接



發佈了30 篇原創文章 · 獲贊 9 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章