0

在协议中,我想从函数创建单个实例,因此我使用容器来存储静态实例,如下所示:

protocol MyProtocol {
    func networkService() -> NetworkService
}

extension MyProtocol {

    func networkService() -> NetworkService {
        if Singletons.networkService == nil {
            Singletons.networkService = NetworkService(abc: 123)
        }

        return Singletons.networkService!
    }
}

private enum Singletons {
    static var networkService: NetworkService?
}

稍后,一个类型可以符合它并替换默认实现,但也需要一个实例:

struct MyType: MyProtocol {
    private static var networkService: NetworkService?

    func networkService() -> NetworkService {
        if Self.networkService == nil {
            Self.networkService = NetworkService(abc: 555)
        }

        return Self.networkService!
    }
}

我希望通过使用属性包装器来封装这个创建单例的仪式,但是在类型上。我想做这样的事情:

protocol MyProtocol {
    func networkService() -> NetworkService
}

extension MyProtocol {

    func networkService() -> NetworkService {
        @Singleton
        NetworkService(abc: 123)
    }
}

////

struct MyType: MyProtocol {

    func networkService() -> NetworkService {
        @Singleton
        NetworkService(abc: 555)
    }
}

有没有办法实现这个或类似的东西?

4

1 回答 1

0

这是我的第一次尝试:

struct Single {
    private static var instances = [String: Any]()

    static func make<T>(_ instance: () -> T) -> T {
        let key = String(describing: type(of: T.self))

        guard let value = instances[key] as? T else {
            let resolved = instance()
            instances[key] = resolved
            return resolved
        }

        return value
    }
}

protocol NetworkService {}
struct NetworkDefaultService: NetworkService {
    let id = UUID().uuidString

    init() {
        print("Network Default: \(id)")
    }
}

struct NetworkMockService: NetworkService {
    let id = UUID().uuidString

    init() {
        print("Network Mock: \(id)")
    }
}

protocol LocationService {}
class LocationDefaultService: LocationService {
    let id = UUID().uuidString

    init() {
        print("Location Default: \(id)")
    }
}

protocol NonSingleService {}
struct NonSingleDefaultService: NonSingleService {
    let id = UUID().uuidString

    init() {
        print("Non-Single Default: \(id)")
    }
}

protocol Context {
    func networkService() -> NetworkService
    func locationService() -> LocationService
    func nonSingleService() -> NonSingleService
}

extension Context {

    func networkService() -> NetworkService {
        Single.make {
            NetworkDefaultService()
        }
    }

    func locationService() -> LocationService {
        Single.make {
            LocationDefaultService()
        }
    }
}

struct AppContext: Context {

    func networkService() -> NetworkService {
        Single.make {
            NetworkMockService()
        }
    }

    func nonSingleService() -> NonSingleService {
        NonSingleDefaultService()
    }
}

let context = AppContext()
context.networkService()
context.networkService()
context.locationService()
context.locationService()
context.nonSingleService()
context.nonSingleService()

这打印:

Network Mock: 48CBDE3A-26D2-4767-A6AA-F846F8863A52
Location Default: 4846953B-93F6-4025-A970-DA5B47470652
Non-Single Default: 957979D8-9F3E-428E-BD87-B9F45D56B755
Non-Single Default: 816D2886-D606-4558-A842-295C833AE4C8
于 2021-02-05T13:59:15.617 回答