25

假设我们有以下类:

看法

@interface ArticleView : UIView
@property IBOutlet UILabel *titleLabel;
@property IBOutlet UILabel *bodyLabel;
@end

模型

@interface Article : NSObject
@property NSString *title;
@property NSString *body;
@end

控制器

@interface ArticleViewController : UIViewController
@property Article *myArticle;
@property ArticleView *myArticleView;
- (void)displayArticle;
@end

@implementation
- (void)displayArticle {
    // OPTION 1
    myArticleView.titleLabel.text = myArticle.title;
    myArticleView.bodyLabel.text = myArticle.body;    

    // ... or ...

    // OPTION 2
    myArticleView.article = myArticle;
}
@end

选项1

  • PRO:视图和模型都没有相互耦合。
  • CON:控制器需要知道模型和视图的细节。

选项 2

  • PRO:控制器代码轻巧灵活(如果视图或模型更改,控制器代码保持不变。
  • CON:视图和模型是耦合的,因此可重用性较低。

在选项 2 中,必须更改 ArticleView 以保存对模型的引用:

@interface ArticleView : UIView
@property IBOutlet UILabel *titleLabel;
@property IBOutlet UILabel *bodyLabel;
@property Article *article;
@end

然后可以覆盖文章设置器以相应地更新视图,如下所示:

- (void)setArticle:(Article *)newArticle {
    _article = newArticle;
    self.titleLabel.text = _article.title;
    self.bodyLabel.text = _article.body;
}

所以我的问题是,就 OO 和 iOS/MVC 最佳实践而言,这两个选项中的哪一个是最好的?

我当然看到两者都在使用。我见过在 UITableViewCell 子类中常用的 OPTION 2。

我还读到视图和模型应该被设计成可重用的,而不依赖于任何东西,而视图控制器是最不可重用的。

我的直觉是使用 OPTION 1 仅仅是因为我宁愿视图控制器完成将模型绑定到视图的肮脏工作,并让模型和视图保持独立并且彼此不知道。但是由于某些视图被设计为只做一件事,因此将它们直接绑定到特定模型可能还不错。

我很想听听你对此的看法。

4

6 回答 6

31

这并不总是一个非此即彼的决定。您的第一个选项更典型的是 Apple 的 MVC 版本;在 iOS 中,模型和视图通常不会直接相互通信,而控制器负责它们之间的大部分协调。但是,拥有一个了解较大模型中特定类的自定义视图并不是不合理的。您可能有一个 ArticleView,它知道如何处理 Article,但 ArticleView 仍应接收它从控制器显示的任何文章,而不是直接从较大的模型中获取它。

MVC 的目标之一是使模型和视图类更可重用。如果你让你的 ArticleView 非常简单,以至于控制器必须完成所有解释文章的工作,那么你实际上可能会失去可重用性——每次你想用一个新的视图控制器重用 ArticleView 时,你都必须重现为 ArticleView 解释文章的所有代码。或者,您总是使用相同的视图控制器类来管理 ArticleView。这些都不是真正“可重复使用的”。

同时,您必须承认,ArticleView 与 ArticleView 之间存在一些自然耦合,因为 ArticleView 旨在显示文章的所有相关细节,无论是直接从文章中获取它们还是设置它们由视图控制器。如果 Article 发生更改,ArticleView 很可能必须更改,无论它是否知道 Article。

因此,即使 Article 可能是一个模型类,拥有一个知道它的视图也是可以的。您不想要的是一个了解较大模型并尝试从模型本身获取文章的 ArticleView。这将您可以在 ArticleView 中显示的文章限制为只能在 ArticleView 中找到的文章——它会阻止您显示来自其他来源的文章。

于 2013-05-13T07:24:52.787 回答
3

是的,您已经证明了对该主题的理解。

OPTION 1 是 MVC 的经典结构,我推荐它作为您提供的两者的默认路由。

仅仅因为 OPTION 1 是一个更纯粹的定义,并不意味着它需要在任何可能的地方应用。

我最常犯的偏差是,当实现非常具体且未重用时,引入专用控制器类型只会导致在实现很小、非常专业、不可重用且不会大幅增长时编写和维护更多代码。如果该程序很适合将 V 和 C 折叠成一个单独的实现并适合一些小的东西(例如数十行代码),我不担心使用 OPTION 2。

现实比这更复杂,但要点是:不要觉得你需要坚持#1,尽管在你编写和维护一些中等规模的程序之前,你可能不会理解使用#2 会如何引入维护问题在几年里。从一个移动到另一个可能会在已发布的程序中引入许多更改——这是可以避免的。

使用选项 2 应该是少数。如有疑问,请使用选项 1。

无论哪种方式,我相信模型不应该知道视图或控制器。

对我来说,在编写可重用组件时,严格遵守更为重要。

于 2013-05-13T07:38:26.747 回答
1

坦率地说,有时我自己会做选项 2。但选项 1 是“出书”。

于 2013-05-13T07:25:13.723 回答
0

正如其他人所说,选项 1 是更纯粹的方法。控制器应该是视图和模型之间的“接线盒”。

然而,这种方法的许多实现(例如 Microsoft 称为 MVC 的框架)对于选项 2 来说非常丰富。当然,在 Microsoft 的情况下,视图和模型相互了解这一事实允许 IDE 创建大量样板代码,为您免去“烦恼”。这样做的好处是您将时间花在编写“功能”代码而不是“接线”代码上。因此,无论是否纯正,您都可以了解它们的来源。

正如在软件开发中经常发生的那样,选项 1 和选项 2 之间的选择归结为纯粹与实用主义。

于 2013-05-13T07:41:58.107 回答
0

根据 Apple 对此主题的官方指南,Objective-C 编程中的概念文档的MVC 作为复合设计模式部分讨论了这两种方法,但清楚地表达了 Apple 对选项 1 的偏好,而不是选项 2。事实上,Cocoa Core能力仅列出选项 1。

我从不后悔实施选项 1 方法,但是当我偷工减料并尝试让模型和视图直接交互时,当我不得不在以后返回并修改系统时,我经常后悔。

于 2013-05-13T14:45:40.620 回答
-1

选项 1 是 MVC。选项2不是。

OO 实际上处于不同的级别,您拥有模型、视图和控制器的对象,因此您不能做更多的事情来成为 OO。

这两个选项当然都可以,但是 MVC 的存在是有原因的(我相信你已经完成了一些像这样的一般性阅读),如果你遵循这些原则,你会发现你的代码更容易阅读、理解和重用MVC 的。

于 2013-05-13T07:18:04.580 回答