使用约束重新定义协议函数,而无需公开方法



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

我错过了什么?

美丽的解决方案在哪里?

我想知道您是否真正想要的是使用实际对象的组合,而不仅仅是接口(和一些默认实现)。请考虑一下:您定义的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很清楚理解。

删除一个间接级别(即"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")
    }
}

最新更新