从封装到协议扩展

假设我们要在Swift中定义一个简单的服务类,如果某些输入为正,则只输出一些输出。 (哇:要求跨度少于2行!)

对象封装

简单地说-容易完成吗? 是的,如果我们不在乎客户端的可扩展性:

使用这种方法,客户端类可以简单地实例化服务,并将doSomething工作委托给它。 非常简单(这很好),但是非常令人讨厌的是,当服务实例本身正在执行工作时,客户端无法干预要执行的输入数据和输出操作。

继承-不错的尝试!

不,继承并不总是我们的敌人。 它确实有(两个?)有效的用例。 但是直言,这不是我们最好的朋友(即使代码确实更短!):

通过仅覆盖需要的内容,客户端可以将实现注入所需的位置。 每当定义时,服务将调用客户端替代而不是其自身的实现。 而且一切都会很顺利,例如,客户端现在不能是自定义的NSView (或UIView ),因为在这种情况下,有必要从所需的Cocoa基类而不是我们的服务中继承它……

功能编程

哦! 我们正在变得现代化,是吗? 尽管如此,对于Swift而言,我也不认为这也是服务开发人员应该遵循的最佳方法-仅仅是因为这将(可能)需要在客户端开发人员级别上过多的基础设施意识。

确实,我们服务的用户需要执行一些“技巧”(例如,如果要在该处使用客户端状态,则捕获弱者无主的 自我 ),以确保当他们将自定义闭包传递给我们时,不会在应用程序中引入内存泄漏:

代表和协议扩展

现在我们在说话! 我们最终将有一个真正的解决方案。 不需要继承,也不需要客户端开发人员的ARC知识!

我们只需要:

  • 具有可选扩展名的服务委托协议,以提供我们要使用纯Swift公开的默认实现(即,没有@objc可选成员);
  • 在服务中托管此类委托对象的实例或无主实例(尽管要求客户端类型为类,但无需我们的客户端开发人员处理内存管理问题);
  • 并在适用时最终调用委托的(属性和)方法:

一体

最后,让我们看一看适用于我们所有类型客户的服务解决方案:如果喜欢继承,则接受; 否则,人们可以使用函数式编程并传递(设计良好)闭包; 或者,他们可以仅仅依靠(弱)聚集的代表来完成工作;或者 当然,所有这些都是为了防止默认情况下首先出现以下问题:

现在轮到你了。 您不需要上面的(我承认,很丑)多合一解决方案,但是至少您现在可以根据自己项目的需要对其进行调整。 无论如何,我想补充一点,我通常发现它足以支持继承和具有(部分或全部)默认实现的委托,但是有时功能样式也可以很好地工作(当您不希望客户需要在转义它们将通过的闭包)。