【问题标题】:How to reference a class that follows a protocol in return type of function?如何在函数的返回类型中引用遵循协议的类?
【发布时间】:2015-06-07 07:14:58
【问题描述】:

我有一个名为 Social Service 的协议,声明如下:

protocol SocialService: class {
    class func testFunc()
}

遵循协议的类可能如下所示:

class Twitter: SocialService {
    class func testFunc() {

    }
}

我想要一个方法返回一个遵循这个协议的类,所以调用它看起来像这样:

let socialService = socialServiceForServiceType(serviceType: String)

我不确定我需要把什么作为这个函数的返回值类型。例如,这个:

func socialServiceForServiceType(serviceType: String) -> SocialService.Type

这里没有给出错误,但是尝试像上面那样调用它,给出了一个错误:

访问协议类型值“SocialService.Type”的成员是 未实现

编辑:我不想要那种类型的实例,我想要那种类型的类。所以我想要一个 Twitter 类,这样我就可以在上面调用 SocialService 协议中的类方法。

【问题讨论】:

标签: ios class swift protocols


【解决方案1】:

简单使用

func socialServiceForServiceType(serviceType: String) -> SocialService

协议可以是函数的返回类型。

【讨论】:

  • 就像返回 String 表示“字符串的实例”一样,返回 SocialService 表示“SocialService 的实例”。我想要一个类,我可以简单地调用类方法。
【解决方案2】:

使用工厂模式来实现同样的目的。

class SocialFactory : NSObject
{
  class func socialServiceForServiceType(serviceType: String) -> SocialService?
  {
    switch serviceType
    {
      case "Twitter":
         return Twitter();
      case "Facebook":
         return Facebook()
      default:
         return nil;
    }
  }
}

【讨论】:

  • 我建议你使用工厂模式来实现松散耦合的设计。而且在接口中使用静态方法也不是一个好主意。当您想避免直接耦合到具体类时,可以使用接口。
【解决方案3】:

正如错误所说,此功能未实现。不过……

我不想要那种类型的实例,我想要那种类型的类。所以我想要一个 Twitter 类,这样我就可以在上面调用 SocialService 协议中的类方法。

我不确定您认为避免此类情况会得到什么。请记住,类不需要有成员变量,没有它们本质上只是函数指针的集合——这正是您所寻找的。​​p>

如果您实现了一个没有属性且符合协议的 Twitter 类,那么在该协议上调用方法将动态分派到该实例的实现:

protocol SocialService: class {
    func testFunc()
}

class Twitter: SocialService {
    func testFunc() {
        println("Testing Twitter!")
    }
}

func socialServiceForServiceType(serviceType: String) -> SocialService {
    return Twitter()
}

let service = socialServiceForServiceType("blah")

// prints "Testing Twitter!"
service.testFunc()

如果您希望将成员变量放在 Twitter 类中,但又不想为某些功能带来开销,那么这可能表明您希望将此功能分解为两个不同的类。或者,如果您想要一个单例实例(例如处理连接),那么还有其他模式可以处理这个问题。

【讨论】:

    【解决方案4】:

    完全同意 Airspeed Velocity,但我想扩展他的观点之一:

    我不确定您认为避免此类情况会得到什么。请记住,类不需要有成员变量,没有它们本质上只是函数指针的集合——这正是您所寻找的。​​p>

    我假设你正在尝试做这样的事情:

    func socialServiceForServiceType(serviceType: String) -> SocialService.Type
    ...
    let cls = socialServiceForServiceType("twitter")
    let conn = cls.connect(user)
    

    或者类似的东西。你不需要类来实现这一点。你可以只返回函数。

    typealias Connect = User -> Connection
    func connectorForServiceType(serviceType: String) -> Connect {
         switch serviceType {
             case "twitter": return Twitter.Connect
             ...
         }
    }
    
    let connect = connectorForServiceType("twitter")
    let conn = connect(user)
    

    如果您想将一整套函数打包在一起,只需使用结构即可。

    struct ServiceHandlers {
        let connect : User -> Connection
        let ping : () -> Bool
        let name: () -> String
    }
    
    func standardPinger(host: String) -> () -> Bool {
        return { host in 
            // perform an ICMP ping and return Bool 
        }
    }
    
    func handlersForServiceType(serviceType: String) -> ServiceHandlers {
         switch serviceType {
             case "twitter":
                 return ServiceHandlers(connect: Twitter.connect,
                                        ping: standardPinger("www.twitter.com"), 
                                        name: { "Twitter" })
             ...
         }
    }
    
    let service = handlersForServiceType("twitter")
    let conn = service.connect(user)
    

    在某些方面,这与类方法是重复的,但是 (a) 类方法所需的功能没有实现,并且 (b) 这更加灵活。你可以返回任何你想要的函数集合;它们不必都是类方法。拥有默认行为更容易(当你使用继承时,这在 Swift 中很难)。它更容易扩展,因为您不必扩展所有类(请参阅我对standardPinger 的使用,这是我编写的返回另一个函数的函数;它不必是类方法) .

    摆脱类/继承思维,只传递函数可能是 Swift 的一大优势。有时结构比协议更好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多