swift方法应该返回协议类型还是具体类型?

时间:2016-10-09 12:41:30

标签: swift unit-testing module protocols

在当前项目中,我们尝试使用协议而不是具体定义来定义类型,以便它们可以在主应用程序中使用,并且可以使用协议双精度进行单元测试。 e.g。

protocol UserProtocol {
    var firstName: String { get }
    var lastName: String { get }
    var userName: String { get }
    // ... plenty of other properties as the app has grown
}

然后我们为app创建了单独的模块,这些模块与每个模块中的这些属性的子集有关。例如,假设的网络管理器和用户设置管理器将关注在不同协议中定义的不同属性子集,以帮助进行本地推理并为此模块创建更简单的测试双精度。

// For User settings
protocol UserSettingType {
    var firstName: String { get }
    var lastName: String { get }
    var notificationTypes: [String] { get }
    var userName: String { get } // Common to both
}

// For the Network manager
protocol NetworkUserType {
    var userName: String { get } // Common to both
    var userUUID: String { get 
    var password: String { get }
    var deviceToken: String? { get }
}

我希望尽可能地将用户设置和网络管理器与应用程序的其余部分分开,以便可以使用更多插件类型的体系结构来抽象它们。因此,我希望能够将这些较小的协议追溯应用于UserProtocol,但Swift不允许这样做。 e.g ..

extension UserProtocol: UserSettingType { } // Extension of protocol 'UserProtocol' cannot have an inheritance clause.

但是通过实现符合UserProtocol的具体类型的具体类型。

struct User: UserProtocol {
    ...
} 
extension User: UserSettingType { } // works fine

我最初的反应是,这是Swift不必要的限制,最好是能够提供这种灵活性,但后来我更多地考虑了用例。

  1. 我无法传递实际UserProtocol个实例,而是始终是UserProtocol的特定实例,例如classstructenum
  2. 它们只来自一个初始化者或一个永远是特定类型的方法的返回类型。它可能恰好符合UserProtocol,但会有更多关于类型的具体信息,例如它是引用还是值类型。因此,这里没有实际的灵活性,只有信息的丢失。
  3. 我唯一想要灵活地替换符合协议而不是具体类型的实例的地方是作为方法的输入参数(主要用于单元测试)。
  4. 考虑到这一点,我得出一个结论,我应该输入方法作为测试实例创建灵活性的协议和方法作为具体类型的返回实例。

    func retrieveAUser() -> User { //concrete return type
        ...
    }
    
    func userSettingsSampleFunction(user: UserSettingType) { // Protocol as input
        ...
    }
    

    我得到的反馈是,我们应该使用输入和输出协议来实现灵活性,但我看不出这样做的好处。 我会对这里有一些关于哪种方式最好的想法感兴趣。 如果输入参数和返回类型是协议类型,我应该返回具体类型还是有更好的替代方案?

    请注意我没有提到泛型,因为用例主要是关于实现方便测试,但是如果有人有任何想法可能值得关注。

    非常感谢

0 个答案:

没有答案