閱讀726 返回首頁    go 阿裏雲 go 技術社區[雲棲]


Cocoa教學:Windows OOP與Cocoa MVC之對比

封裝不封裝,這是個問題。

今天我在看Cocoa開發者郵件列表的時候,看到一個帖子,求助如何在兩個View之間互相通信的問題。做Windows程序員的時間長的我都不好意思說了,我意識到,這個問題在我剛剛接觸到Mac上的Objective-C時也遇到過。

我現在可以提出這個問題的簡化版:“我有一個對話框,獲取了一些用戶輸入的數據。我現在需要從我那個對話框中把這個數據提取出來以供主窗口使用。如何才能從主窗口獲取到對話框裏的數據呢?”


在Windows裏,尤其是C# .NET,你可以通過添加一個Form對象來創建新的窗口,而且還可以簡單地在設計窗口中添加一些不同的“控件”。這些操作是非常容易的。不過一旦窗口創 建好之後,你需要在主窗口的代碼中建立剛才新建的窗口的實例,然後提供公共變量在兩個窗口之間設置或者獲取數據。窗口類是由Windows Form模板寫好直接交給你使用的,這當然可以使代碼看起來清晰幹淨,但是它打破了MVC的慣例,所以大部分Windows的程序員會花費不少時間提升他 們思考的方式也就不足為奇了。

我用VS2008做了一個demo程序,截圖大概是這樣的:


看一下主窗口的代碼:

  1. public partial class Form1 : Form
  2. {
  3.     Panel p;
  4. ?
  5.     public Form1()
  6.     {
  7.         InitializeComponent();
  8.         p = new Panel();
  9.         p.Show();
  10.     }
  11. ?
  12.     private void btnChangeText_Click(object sender, EventArgs e)
  13.     {
  14.         p.OutputText = this.tbInputText.Text;
  15.     }
  16. }

 

注意看我聲明了一個Panel的對象,這是我們需要在上麵設置文字的第二個窗口(view)。下麵是Panel類的代碼:

 

  1. public partial class Panel : Form
  2. {
  3.     public Panel()
  4.     {
  5.         InitializeComponent();
  6.     }
  7. ?
  8.     public string OutputText
  9.     {
  10.         set
  11.         {
  12.             this.tbOutputText.Text = value;
  13.         }
  14.     }
  15. }

 

好,代碼很容易理解,但是從這裏就可以看出我的觀點:MVC模型已經被破壞了。雖然這個例子裏麵並沒有任何編程邏輯,不過很清楚的是這樣的設計導致你隻需要把代碼放到按鈕的事件處理裏麵就可以了,而不是去將邏輯抽象到controller對象中。

 

你也許會問,我在C#中如何做MVC呢?呃……這是一個關於Objective-C、Cocoa編程的網站,對於讀者們來說這是個作業了……不過坦 白講,我可不知道。我知道那是一件可能的事情,不過C#語言的內部就沒有把開發者向這個方向去引導。我也看過一些講這方麵事情的文章,不過那些也都是基本 上困難到沒法實踐的。有幾篇號稱是MVC不過根本不算,所以如果你真想在C#上麵實現MVC,自己想辦法弄吧……^o^ 我想說的其實就是要想在C#上麵實現MVC,那算你狠。

 

Objective-C/Cocoa的方式

 

在Objective-C裏,你必須明確地創建一個controller用來處理model和view之間的變化。其實MVC應該被稱做MCV,因 為controller是在model和view之間的一個協調員。如果你的model發生了改變,你的controller會通知view。如果用戶在 view中做出了某種改變,controller就會通知model。所以我建議初學者可以叫它MCV,會更加形象一點。有點跑題了。

在Objective-C/Cocoa的世界裏,我們建立的controller通常是指應用程序(Application)的托管 (Delegate),或者可以簡單稱做app delegate。很多Windows程序員都會在這裏迷惑不解的事情是,我們通常學習到的麵向對象開發就是你應該去做的事情,而並不會關注為什麼你會去 做,或者你為什麼不去做。我並不是說你別用OOP的思想,而正相反我建議去用。問題是如果把一切都抽象化,那就有點太傻叉了……我們應該有很好的理由去寫 這些代碼,而不要用諸如“我從大學裏麵學的……”或是“我一直就這麼幹……”這種理由。

當你在Objective-C裏麵建立一個app delegate的時候,這個delegate可以做為你所有model和view的controller,或者你也可以為不同的model和view分 別創建controller。想怎麼幹就怎麼幹吧。不過有一個比較重要的事情是要記住的,如果你把所有的代碼都扔到同一個app delegate類裏頭,那你就有了一個超大的app delegate文件,很難看清楚。

一些例子程序

為了幫助那個提出問題的朋友,還有另外一些想從Windows開發轉變到Cocoa開發的朋友們,我也寫了點簡單例子來幫助把這個問題變簡單。如果 你想讓兩個View,或者兩個窗口可以互相之間通信,隻要在他們之間傳遞消息就可以了。雖然把你的view們封裝到它們自己的類中並不是壞事,不過通常來 說真的沒必要。在任何一種語言和任何一種平台上,都有實現這個功能的方法,所以就別管我沒提到的事情了,我也沒說這是唯一的方法不是……我說的方法是簡單 直接的方法,可以幫你更快的理解。

我同樣建了一個簡單的demo程序來演示上麵說的,這裏是截圖:

你可以在這裏下載例子。

這裏是我提到的代碼,隻需要在app delegate的頭文件中將你的view聲明為outlet:

 

  1. @interface AppDelegate : NSObject {
  2.     IBOutlet NSTextField *inputText;
  3.     IBOutlet NSTextField *outputText;
  4. }

然後聲明這樣一個方法,在按下按鈕之後會執行:

  1. - (IBAction)updateText:(id)sender;

 

最好要做的事情就是在IB裏麵把action和outlet連到AppDelegate對象上,任務完成。就這麼簡單。

 

為什麼Windows的方法爛,Mac的方法讚

 

好吧,這個小標題僅僅是個玩笑,Windows專家們千萬表噴俺。不過我的確認為C#設計用戶界麵的方式會把人們的代碼搞得賊亂,而且明顯不是MVC模式。

當然,又來了,怎麼做還是看你自己,不過.NET的用戶界麵設計工具非常鼓勵用戶去破壞MVC模式。當你在設計器裏麵把一個按鈕拽到窗口裏,然後雙 擊那個按鈕的時候,它就自動地給你指到按鈕點擊事件代碼裏,大部分程序員就自然而然地在那裏寫代碼了。當你在設計過程的時候,倒也沒什麼,不過它根本沒有 做什麼來支持你將邏輯和表現分開。

在Objective-C裏,想破壞MVC設計模式倒是很困難的事情。基本上你都必須遵循這個模式。甚至當你使用Interface Builder在app delegate和action及outlet中間建立連接的時候,都會帶有一個可視的MVC表現。要連接app delegate類(你的controller)到outlet的時候(比如輸入框),你按住ctrl之後從AppDelegate拖拽一根線放到 outlet上。當你想告訴AppDelegate執行一些動作,你要從觸發動作的對象中拽到AppDelegate對象上。反過來是不行的。養成這樣的 習慣其實很好,隻不過Windows的鐵杆程序員會相當不習慣。

結論

從Windows程序員轉到Mac程序員是有一點挑戰的,不過你越早拋掉從前的開發的概念,就越容易接受Mac開發的概念。想想令狐衝吧……Mac的開發的確是不太一樣的。要習慣這種開發思路,而不要試圖沿用從前的習慣來進行Mac開發。

承認這一點吧兄弟們,工程師們都是很傲慢的,而且當學習一門新的語言、技術或是平台的時候,通常會認為他們已經很清楚了。最後這句的英文真的很棒, 我不知道怎麼翻譯才能完美的表達這句話,和大家共勉:Goto is not inherently evil, you know? Until next time.

轉自iOS分享網--https://iosshare.cn


最後更新:2017-04-02 15:14:44

  上一篇:go 微軟瓦解Nitol僵屍網絡
  下一篇:go 為什麼應該放棄或減少使用MD5