Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
swift中可测试代码与静态方法调度的结合_Swift_Function_Dispatch_Testability - Fatal编程技术网

swift中可测试代码与静态方法调度的结合

swift中可测试代码与静态方法调度的结合,swift,function,dispatch,testability,Swift,Function,Dispatch,Testability,最近我读了很多关于Swift运行时的书,并且对使用静态方法分派优化我的代码越来越感兴趣。这通过以下方法实现: 结构方法 最终类方法,即用final关键字声明为private或在最终类中 在协议扩展中定义的协议方法,而不在协议本身中声明 问题是,这些情况中并没有一种使我能够编写可测试的代码,至少不像我现在这样做:注入在单元测试中被mock取代的协议实体 那么,在不放弃静态方法分派的情况下编写可测试代码是可能的吗?如果是这样的话,该如何进行呢 谢谢 泛型是您需要的。您可以通过协议进行抽象,但编译

最近我读了很多关于Swift运行时的书,并且对使用静态方法分派优化我的代码越来越感兴趣。这通过以下方法实现:

  • 结构方法
  • 最终类方法,即用final关键字声明为private或在最终类中
  • 在协议扩展中定义的协议方法,而不在协议本身中声明
问题是,这些情况中并没有一种使我能够编写可测试的代码,至少不像我现在这样做:注入在单元测试中被mock取代的协议实体

那么,在不放弃静态方法分派的情况下编写可测试代码是可能的吗?如果是这样的话,该如何进行呢


谢谢

泛型是您需要的。您可以通过协议进行抽象,但编译器仍然知道您使用的确切类型,因此不需要动态调度

protocol Dependency {
  func doSomething()
}

struct RealDependency: Dependency {
  func doSomething() {
    print("I'm doing real work")
  }
}

struct MockDependency: Dependency {
  func doSomething() {
    print("I'm the mock, so I do nothing")
  }
}

struct MyApp<D: Dependency> {
  let dependency: D

  func doSomething() {
    dependency.doSomething()
  }
}

let myAppReal = MyApp(dependency: RealDependency())
let myAppMock = MyApp(dependency: MockDependency())

myAppReal.doSomething() // Prints "I'm doing real work"
myAppMock.doSomething() // Prints "I'm the mock, so I do nothing"
协议依赖性{
func doSomething()
}
结构RealDependency:Dependency{
func doSomething(){
打印(“我正在做真正的工作”)
}
}
struct MockDependency:Dependency{
func doSomething(){
打印(“我是冒牌货,所以我什么都不做”)
}
}
结构MyApp{
让依赖项:D
func doSomething(){
dependency.doSomething()
}
}
让myAppReal=MyApp(依赖项:RealDependency())
让myAppMock=MyApp(依赖项:MockDependency())
myAppReal.doSomething()//打印“我正在做真正的工作”
myAppMock.doSomething()//打印“我是模拟对象,所以我什么都不做”

然而,请注意,在Swift中,仿制药的单晶化是不保证的。因此,无论如何,您可能会以某种形式的动态调度结束。请参见

您需要的是泛型。您可以通过协议进行抽象,但编译器仍然知道您使用的确切类型,因此不需要动态调度

protocol Dependency {
  func doSomething()
}

struct RealDependency: Dependency {
  func doSomething() {
    print("I'm doing real work")
  }
}

struct MockDependency: Dependency {
  func doSomething() {
    print("I'm the mock, so I do nothing")
  }
}

struct MyApp<D: Dependency> {
  let dependency: D

  func doSomething() {
    dependency.doSomething()
  }
}

let myAppReal = MyApp(dependency: RealDependency())
let myAppMock = MyApp(dependency: MockDependency())

myAppReal.doSomething() // Prints "I'm doing real work"
myAppMock.doSomething() // Prints "I'm the mock, so I do nothing"
协议依赖性{
func doSomething()
}
结构RealDependency:Dependency{
func doSomething(){
打印(“我正在做真正的工作”)
}
}
struct MockDependency:Dependency{
func doSomething(){
打印(“我是冒牌货,所以我什么都不做”)
}
}
结构MyApp{
让依赖项:D
func doSomething(){
dependency.doSomething()
}
}
让myAppReal=MyApp(依赖项:RealDependency())
让myAppMock=MyApp(依赖项:MockDependency())
myAppReal.doSomething()//打印“我正在做真正的工作”
myAppMock.doSomething()//打印“我是模拟对象,所以我什么都不做”

然而,请注意,在Swift中,仿制药的单晶化是不保证的。因此,无论如何,您可能会以某种形式的动态调度结束。请参见

记住,静态分派是一种编译器优化,而且往往非常脆弱。虽然它是一个加速紧密循环的强大工具,但调整编程风格以在整个程序中保持不变需要做大量的工作,回报很小。对于大量(压倒性的)方法调用,它提供了最小的性能改进,如果您简单明了地编写Swift,编译器将为您提供非常好的工作。如果您发现系统中需要许多模拟,那么您可能有一个过度耦合的系统,应该将重点放在这一点上,而不是静态调度。这里的基本要点是,试图猜测编译器以强制静态调度可能会适得其反,并导致更差的性能。专注于减少模拟的数量可能会比追求大量模拟的广泛静态分派带来更好的收益。这非常有趣,同时也有点令人失望,因为您可以将两者结合起来。请记住,静态分派是一种编译器优化,而且往往非常脆弱。虽然它是一个加速紧密循环的强大工具,但调整编程风格以在整个程序中保持不变需要做大量的工作,回报很小。对于大量(压倒性的)方法调用,它提供了最小的性能改进,如果您简单明了地编写Swift,编译器将为您提供非常好的工作。如果您发现系统中需要许多模拟,那么您可能有一个过度耦合的系统,应该将重点放在这一点上,而不是静态调度。这里的基本要点是,试图猜测编译器以强制静态调度可能会适得其反,并导致更差的性能。专注于减少模拟的数量可能会比追求大量模拟的广泛静态调度带来更好的收益。这非常有趣,同时也有点令人失望,你可以将两者结合起来。这是一个非常好的答案,最后一点非常重要。与使用类的更简单的动态调度解决方案相比,这可能有更好的性能,也可能没有更好的性能。(在某些情况下,大型结构的传递速度比大型类慢,这压倒了静态分派的任何好处。另一方面,结构可以比类快。没有简单的“始终这样做”规则。)这是一个非常好的答案,最后一点非常重要。与使用类的更简单的动态调度解决方案相比,这可能有更好的性能,也可能没有更好的性能。(在某些情况下,大型结构的传递速度比大型类慢,这压倒了静态分派的任何好处。另一方面,结构可以比类快。没有简单的“始终这样做”规则。)