1

假設我有一個班級來模擬一個城市。它的特徵如下:MVC是否打破封裝?

  • 它只有兩個屬性「name」和「population」,都是私有的,它們在構造函數中設置。
  • 它有這些屬性的getters,但不是setter。

我不希望這個類的任何用戶設置屬性,我希望他們使用公共的.edit()方法。

這種方法需要打開一個表格輸入城市和人口的新名稱,即:一個視圖。然後,如果我有一個視圖,我想實現MVC模式,所以想法是控制器接收.edit()調用,呈現視圖,檢索數據並將其發送到視圖,以便它改變了它的狀態。

但是,如果我這樣做,我必須將城市模型的屬性從私有變爲公共。所以,如果任何用戶實例化我的課程,她/他可以直接更改屬性。

所以,哲學問題:是不是打破封裝?

編輯只是爲了使其更加明確:

city_instance.edit()方法應該是變異對象的唯一途徑。

此外,我看到我的部分問題來自於對模型是對象的誤解(您可以在php mvc框架中閱讀它),實際上它是一種不同的抽象,它是一個將業務邏輯(域對象+我想更多的東西)

+2

您是否看到http://programmers.stackexchange.com/questions/168316/isnt-mvc-anti-oop? – 2013-03-14 16:37:02

+0

控制器不應該從視圖中接收到2個值,然後將它們放在.edit()方法中作爲參數嗎? – JeffO 2013-03-14 20:39:32

回答

3

免責聲明:我不明白你在哪裏提出.edit()方法來實施,所以這將有助於如果你能澄清一點。

這裏要考慮的第一件事情是,在你的問題的項目符號列表,你似乎暗示着一個City實例就像一個不可變對象:它需要它的實例變量在構造函數中,不允許任何人在外面改變他們。但是,您稍後聲明您確實想要創建一種可視化編輯City實例的方式。這兩個要求顯然會產生一些緊張局勢,因爲它們有些相反。

如果你去MVC方法,通過從模型分離的觀點,你有兩個主要選擇:

  • 對待你City對象作爲不可變的,而不是編輯例如當值的改變形式,丟棄原始對象並創建一個新對象。
  • 提供變異現有City實例的方法。

如果您實際上將City視爲不可變對象,則第一種方法可使模型保持完好。對於第二個有很多不同的方法去:

  • 最標準的方法是在City類提供一個增變。對於每個屬性或常見消息(我認爲這是您提到的.edit()方法),它可以具有獨立設置器的形狀,以便通過採用數組來同時更改多個屬性。請注意,在這裏你不需要將表單對象作爲參數,因爲模型不應該意識到視圖。如果您希望視圖注意模型中的內部更改,請使用Observer模式。
  • 對控制器使用「朋友」類。有些語言允許朋友類訪問對象的內部。在這種情況下,您可以創建一個控制器,它是您的模型的一個好友類,可以在模型和視圖之間建立連接,而無需爲模型添加增變器。
  • 使用反射來完成類似於朋友類的東西。

這三種方法中的第一種是唯一的語言不可知選擇。是否打破封裝是一種很難說的,因爲需求本身會是衝突的(這基本上意味着希望有一個模型與用戶可以改變的視圖分離,但這不允許模型本身改變爲外部)。然而,我會同意,如果你想要可變的實例,從模型中分離模型會促進顯式的變異機制。

HTH

+0

我的想法並不是讓'City'不可變,而是隻通過調用其'.edit()'方法來允許更改。而這種方法應該呈現一個表單(它返回新的屬性值)並將這些新值賦給私有屬性。不從外部獲取數組/值。儘管如此,我的一部分混亂來自錯誤的想法,即模型是一個對象,而不是一層商業邏輯。感謝您的有用答案。 – bgusach 2013-03-14 21:20:21

+0

@ ikaros45好的,我明白了。在這種情況下,問題在於你實際上正在打破MVC,因爲域對象(模型)實際上知道視圖。 MVC以相反的方式展示事物(這個視圖知道模型,模型不知道視圖的任何內容)。這很好,因爲您不會使用視圖驅動代碼污染您的域邏輯,並且您可以通過同一對象(例如,桌面和Web視圖)獲得儘可能多的視圖。 – 2013-03-14 21:59:39

1

注:我指的是MVC,因爲它適用於Web應用程序。 MVC可以應用於多種應用程序,並且以多種方式實現,所以很難說MVC確實或沒有做任何特定的事情,除非您嚴格地談論由模式定義的某些內容,而不是特定的實現。

我認爲你對「封裝」是什麼有一個非常具體的看法,並且該視圖不符合封裝的教科書定義,也不符合它的常見用法。沒有「封裝」的定義,我可以發現,要求不存在setter。實際上,由於Setters本身就是用來「編輯」對象的方法,所以這是一個愚蠢的論點。

從維基百科條目(注意它說:「像getter和setter」):

一般來說,封裝是OOP(面向對象編程)的四個基本原則之一。封裝是爲了隱藏類中的變量或某些東西,防止未經授權的方使用。所以像getter和setter這樣的公共方法訪問它,其他類調用這些訪問方法。

http://en.wikipedia.org/wiki/Encapsulation_(object-oriented_programming)

現在,這並不是說MVC不破壞封裝,我只是說你的封裝是什麼想法是非常具體的,不是特別規範。

當然,使用Getters和Setter會導致一些問題,例如返回列表,然後您可以直接在對象本身之外進行更改。你必須小心(如果你在乎)保持你的數據隱藏。你也可以用另一個集合替換一個集合,這可能不是你想要的。

得墨忒耳的法則在這裏比其他任何東西都更有意義。

但是,無論如何,這一切實際上只是一個紅鯡魚。 MVC只是關於GUI,GUI應該儘可能簡單。它在視圖或控制器中應該幾乎沒有邏輯。您應該使用簡單的視圖模型將表單數據反序列化爲一個簡單的結構,該結構可用於您喜歡的任何業務體系結構(如果您不想使用setter,則使用不包含對象的業務層使用setter和使用mutattors。)。

在UI層幾乎不需要複雜的體系結構。 UI層更像是一個邊界和網關,它將HTTP的平面形式和命令性質轉換爲您選擇的任何業務對象模型。因此,它不會在UI層面上成爲純粹的OO,因爲HTTP不是。

這被稱爲阻抗不匹配,它通常與ORM相關聯,因爲對象模型不容易映射到關係模型。 HTTP到Business對象也是如此。在這方面,您可以將MVC視爲ORM的必然結果。

+0

我想指出的是,MVC模式(或者讓我們更具體一些,因爲MVC是一個混淆的術語:關注點的分離),這意味着對象必須從外部可變,因爲視圖(從我想要的位置檢索數據)不應包含在其中。順便說一下,MVC在web開發中尤其被誤解。你所描述的沒有邏輯的觀點與PAC模式更接近。真正的MVC是從模型中提取數據的視圖。看看這個http://www.garfieldtech.com/blog/mvc-vs-pac – bgusach 2013-03-14 21:30:54

+0

@ ikaros45 - 我認爲你沒有很好的解釋你的觀點。當然,MVC要求對象從外部可變。他們還會發生什麼變異?它們只能被另一個做* something *的對象突變,以便從外部進行變異。 – 2013-03-14 22:11:25