协议是否可以拥有静态工厂方法的默认实现?

7

Consider a protocol that have a factory method:

public protocol Frobnicator {

  func frobnicate()

  static func makeRightFrobnicator() -> Frobnicator
}

private class SomeFrobnicatorImplementation: Frobnicator { ... }
private class AnotherFrobnicatorImplementation: Frobnicator { ... }

public extension Frobnicator {

  static func makeRightFrobnicator() -> Frobnicator {
    if something {
      return SomeFrobnicatorImplementation()
    } else {
      return AnotherFrobnicatorImplementation()
    }
  }
}

我希望能够在不同的时间构建不同的实现。这些实现本身对模块是私有的,而协议则对客户端代码是公开的。

当我尝试类似上面的代码时,我会得到“静态成员makeRightFrobnicator不能在协议元类型Frobnicator.Protocol上使用”的错误信息。

是否有任何方法可以解决这个问题,或者我应该只使用一个自由函数?


这就是工厂模式的用途。 - Dai
@Dai,是的,尽管问题是关于是否可以使用协议静态方法的默认实现。 - Zomagk
问题是关于我是否可以使用协议静态方法的默认实现。那么为什么你不在问题中说呢?这与协议是否具有静态方法无关。这是关于协议扩展提供静态方法的实现。 - matt
@matt,确实;对于混淆感到抱歉。 - Zomagk
1个回答

5
静态函数的实现是合法的:
protocol P {
    static func f() -> P
    init()
}

extension P {
    static func f() -> P {return self.init()}
}

但是您会注意到,为了使其编译通过,我必须向编译器保证我手头有一种合法的方法来创建一个P,以便能够返回一个P。
在您的代码中存在问题,即尝试返回协议的特定实现,如SomeFrobnicatorImplementation。协议对采用者不关心。换句话说,您不能在协议定义中保证SomeFrobnicatorImplementation实际上将成为此协议的采用者。因此,您代码的这部分是非法的。

我没有给你点踩。我很欣赏你的努力,只是想补充一下return self.init()可以编译通过,而return X()却不能。 https://repl.it/Ecm0/1 https://repl.it/Ecm0/0 - Zomagk
1
只有编译器知道return X.init()是合法的时候,才能这样使用。对于一个协议来说,它怎么可能知道谁是它的遵循者呢?因此,不能指定一个特定的P adopter。 - matt
以上代码可以编译通过,但是当我尝试使用 P.f() 时,会出现错误信息 "error: static member 'f' cannot be used on protocol metatype 'P.Protocol'"。即使我将代码更改为以下形式:protocol P { static func f() -> P init() } extension P { static func f() -> P {return S.init()} } struct S: P { } P.f()仍然无法解决问题。 - kareman
由于某些原因,使用四个空格缩进代码无法正常工作。 - kareman
@kareman “但是在尝试使用P.f()时” 当然,你不能给一个协议发送消息!你必须发送消息给协议的_采用者_。采用者是一个对象;协议只是一个协议(字面上是一组规则)。 - matt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接