ios - 使用约束重新定义协议(protocol)功能,而无需公开方法

标签 ios swift swift4 swift-protocols

丑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

如果我可以从协议(protocol)声明中删除 func persistIfAble(),这个解决方案会很优雅。因为不想暴露。 但是,真正有趣的是,如果我删除它,行为就会改变,然后扩展服务内的实现,其中 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

Ugly 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"

我错过了什么?

漂亮的解决方案在哪里?

最佳答案

我想知道您是否真正想要的是使用实际对象的组合,而不仅仅是接口(interface)(和一些默认实现)。考虑一下:您定义的 PersistingService 确实需要在具体的类或结构中实现,以便它们可以包含有关访问它们的位置的上下文数据。所以我想你可以跳过协议(protocol)扩展,把真正的“胆量”留给这些协议(protocol)的具体实现,然后像你的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 理解起来非常清楚。

关于ios - 使用约束重新定义协议(protocol)功能,而无需公开方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47206037/

相关文章:

ios - 获取从 UITableViewController 中选择的行

ios - Swift 中的函数式图形

swift - Playground 未在右侧栏上显示结果

swift - 可滚动 NSTextView 与自定义 NSTextStorage 进行格式化

ios - 任意结构的 Swift 4 JSONDecoder 实用函数

ios - 如何在 Google MapView iOS Swift 4 上呈现来自 Web Api 的地址数组

ios - 使用不同的变量异步多次运行某些代码

iOS:将旋转的 UIImage 作为 alpha 蒙版应用于另一个 UIImageView

ios - 在 ios 中以横向模式显示 iPad 的侧边栏,如 facebook

ios - Firebase:将用户 UID 链接到数据库