【问题标题】:Redefine protocol functions using constraints without having to expose method使用约束重新定义协议函数,而不必暴露方法
【发布时间】:2017-11-09 15:46:00
【问题描述】:

丑1

protocol Persisting {
    func persist()
}

extension Persisting {
    func persist() { print("persisting") }
}

protocol Service {
    func get()
    func persistIfAble() // If I remove this, "Not able to persist" gets printed twice
}

extension Service {
    func get() {
        persistIfAble()
    }
}

extension Service {
    func persistIfAble() {
        print("Not able to persist")
    }
}

extension Service where Self: Persisting {
    func persistIfAble() {
        persist()
    }
}

struct OnlyService: Service {}
struct Both: Service, Persisting {}

let both = Both()
both.get()

let onlyService = OnlyService()
onlyService.get()
print("Can now directly call `persistIfAble` which is not wanted")
onlyService.persistIfAble() // DONT WANT THIS TO BE POSSIBLE

如果我可以从协议声明中删除func persistIfAble(),这个解决方案会很优雅。因为我不想让它暴露。 然而,真正有趣的是,如果我删除它,行为就会改变,然后extension Service where Self: Persisting 内部的实现永远不会被调用。

丑2

protocol Persisting {
    func persist()
}

extension Persisting {
    func persist() { print("persisting") }
}

protocol Service {
    func get()
}

extension Service {
    func get() {
        // Ugly solution, I do not want to cast, `Service` should not have to know about `Persisting`
        if let persisting = self as? Persisting {
            persisting.persist()
        } else {
            print("not able to persist")
        }
    }
}

extension Service where Self: Persisting {
    func persistIfAble() {
        persist()
    }
}

struct OnlyService: Service {}
struct Both: Service, Persisting {}

let both = Both()
both.get()

let onlyService = OnlyService()
onlyService.get()

这两个丑陋的解决方案中的代码当然是我实际场景的一个极其简化的版本,我真的不想执行强制转换,因为它使代码更难阅读。即使我将if let 更改为guard let

丑3(最丑?)

protocol Persisting {
    func persist()
}

extension Persisting {
    func persist() { print("persisting") }
}

protocol Service {
    func get()
    func persistIfAble(allowed: Bool)
}

extension Service {
    func get() {
        persistIfAble(allowed: true)
    }
}

extension Service {
    func persistIfAble(allowed: Bool = false) {
        guard allowed else { print("KILL APP"); return }
        print("Not able to persist")
    }
}

extension Service where Self: Persisting {
    func persistIfAble(allowed: Bool = false) {
        guard allowed else { print("BREAKING RULES"); return }
        persist()
    }
}

struct OnlyService: Service {}
struct Both: Service, Persisting {}

let both = Both()
both.get()

let onlyService = OnlyService()
onlyService.get()
print("Can now directly call `persistIfAble` which is not wanted")
// DONT WANT THIS TO BE POSSIBLE
onlyService.persistIfAble() // prints: "KILL APP"

我错过了什么?

漂亮的解决方案在哪里?

【问题讨论】:

    标签: ios swift swift4 swift-protocols


    【解决方案1】:

    我想知道您是否真正想要的是使用实际对象的组合,而不仅仅是接口(和一些默认实现)。考虑一下:PersistingService 正如您所定义的那样,它们确实需要在具体的类或结构中实现,以便它们可以包含有关它们在何处访问数据的上下文。所以我想你可以跳过协议扩展,把真正的“胆量”留给这些协议的具体实现,然后像你的Both 这样的东西会像这样实现:

    struct Both: Persisting, Service {
        let persisting: Persisting
        let service: Service
        // a default init lets you pass in concrete implementations of both of those things
    
        func persist() {
            persisting.persist()
        }
    
        func get() {
            service.get()
            persist()
    }
    

    这显然不会为您提供看起来您正在尝试实现的自动“混入”效果,但 OTOH 很容易理解。

    【讨论】:

      【解决方案2】:

      删除一层间接性(即“persistIfAble”)怎么样?

      protocol Persisting {
          func persist()
      }
      
      extension Persisting {
          func persist() {
              print("persisting")
          }
      }
      
      protocol Service {
          func get()
      }
      
      extension Service where Self: Persisting {
          func get() {
              persist()
          }
      }
      
      extension Service {
          func get() {
              print("Not able to persist")
          }
      }
      

      【讨论】:

      • 对我没有太大帮助,因为 get 方法是我想共享所有代码的方法,我当然可以尝试在其他函数中包装尽可能多的代码,但我真的会希望能够避免代码重复。
      猜你喜欢
      • 1970-01-01
      • 2016-08-09
      • 1970-01-01
      • 2012-01-26
      • 1970-01-01
      • 2020-11-19
      • 1970-01-01
      • 2018-08-08
      • 1970-01-01
      相关资源
      最近更新 更多