ios - Swift 中对于具有多个方面的模型的良好设计?

标签 ios swift design-patterns

我想问一个关于如何在 swift 中定义具有多个方面的模型的好例子,特别是当项目变得越来越大并且一个模型具有多个方面时。问题很长,但我只是想知道人们如何在大项目中设计模型。任何评论或想法将不胜感激。

假设有一个名为“Book”的模型,其定义如下:

class Book {
    var id: String
    var title: String
    var author: String
    init?(json: [String: AnyObject]) {
        // parse the model from JSON
    }
}

Book 有一个可失败的初始化程序,用于解析服务器发送的 JSON 中的属性。 在 View Controller A上,它描述了关于模式Book的更详细的信息,因此在 View Controller R A上使用时,会在模型中添加一些属性:

class Book {
    var id: String
    var title: String
    var author: String

    // required on View Controller A
    var price: Int
    var seriersName: String
    var reviewNumber: Int
    var detailedDescription: String

    init?(json: [String: AnyObject]) {
        // parse the model from JSON
    }
}

在另一个 View Controller B 上,我们想要显示图书购买的历史记录。因此该模型需要如下附加属性:

class Book {
    var id: String
    var title: String
    var author: String

    // required on View Controller A
    var price: Int
    var seriersName: String
    var reviewNumber: Int
    var detailedDescription: String

    // required on View Controller B (Not required on VC A)
    var purchasedDate: NSDate
    var expireDate: NSDate

    init?(json: [String: AnyObject]) {
        // parse the model from JSON
    }
}

Book 的这个定义缺乏灵 active ,因为传递给故障标签初始化程序的 JSON 必须具有所有属性,即使在仅使用部分属性的 VC 上也是如此。

解决方案A:
我认为最简单的解决方案就是将这些附加属性声明为可选,但我个人认为这不太酷,因为每当使用这些可选属性时,都需要检查它们是否不为零。

if let seriesName = book.seriesName {
    self.seriesNameLable.title = seriesName
}

这种可选绑定(bind)代码将会溢出到我假设的所有代码中。隐式可选绑定(bind)也许可以使用,但使用起来并不安全。

解决方案B:
另一种解决方案可能是定义继承 Book 的不同模型,例如 BookA 和 BookB。但是如果我们需要一个同时具有 BookA 和 BookB 方面的模型怎么办?

我想这类问题没有单一的解决方案,但我想知道其他人如何在大项目中定义模型。 (我想知道是否有人会使用一些“快速特定”功能(例如协议(protocol)及其扩展)提供一个很酷的解决方案:)。我将不胜感激任何意见...谢谢。

最佳答案

免责声明:我不是 Swift 程序员,这是我根据具有相同功能的其他语言进行的推断,我的 Swift 语法可能不是 100% 准确

使用protocols我会做类似的事情:

class EBook: Book, HasOnlineSource {
  ...
} 

class OtherKindOfBook: Book, WithCollectorEditions, HasBleh, WithFoo {...} 

但你必须问自己:

我需要进行动态更改吗?

如果是这种情况,您需要通过组合来进行委派。

应用程序的不同部分使用核心模型的方式是否不同?

或者换句话说,这些模型的不同用户是否需要不同的行为?在这种情况下,扩展非常有用,因为允许根据上下文公开同一模型的不同行为。例如,报告模块可以发送消息numberOfReaders,而销售模块可以请求promotionalCodes。两者都使用相同的模型,但与不同的协议(protocol)进行交互。就您而言,您有不同的 Controller 想要不同的东西,因此这可能适用。

使用委托(delegate)

这遵循组合优于继承原则,但在回顾了如何delegates work in Swift之后,我知道它们不是 native 实现,但仍然是一种设计模式(您可能会说是功能请求),委托(delegate)是手工进行的。

其他语言允许您使用 BookProtocol 创建 JSSONSerializedBook,但您可以设置委托(delegate),而不是实现 BookProtocol 上所需的内容初始化后将实现此类协议(protocol)。该委托(delegate)将是 JSSONSerializedBook 的内部协作者,并且 JSSONSerializedBook 接收到的属于 BookProtocol 一部分的所有消息都将委托(delegate)给它。 或者换句话说,消息传递是自动处理的(如果您想检查其他语言如何实现它,这里是Kotlin documentatin on delegates)。

如果您想在 Swift 上执行相同的操作,则必须显式将消息传递给您的委托(delegate)。 这种设计有几个优点,但由于没有对消息传递的 native 支持,因此实现起来变得非常冗长。

如需进一步引用,您可以查看 mixins 上的论文和 traits深入了解此功能背后的设计决策。

关于ios - Swift 中对于具有多个方面的模型的良好设计?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35238605/

相关文章:

ios - presentViewController 改变 Controller 的方向

ios - 我们可以在 Swift Playground 中添加过渡动画吗?

c# - 优化 : How should i Optimize the Linq Concat of Collections? C#

java - Scala 等价于 Java 构建器模式是什么?

java - 设计模式: multiple swing interfaces listen for thread variable

ios - 类中的 extern NSString *const。

ios - 增加所有文本字段上的文本大小

ios - iOS 版 Crosswalk 无法与 iOS SDK 10.1.1 配合使用

xcode - 背景音乐不起作用,但没有错误?

ios - 在 iOS swift 中处理表格中的选定行时出错