单个数组元素的延迟初始化

Lazy initialisation of individual array elements

在 Swift 中,lazy properties 允许我们仅在请求时初始化 class 成员,而不是直接在运行时初始化 - 对于计算量大的操作很有用。

我在 Swift 4 中有一个 class 负责从一组编译时(开发人员硬编码)提供的 StrategyProtocol 对象中初始化一个 strategy .它看起来像这样:

class StrategyFactory {
    private var availableStrategies: [StrategyProtocol] = [
        OneClassThatImplementsStrategyProtocol(),
        AnotherThatImplementsStrategyProtocol() // etc
    ]

    public func createStrategy(): StrategyProtocol {
        // Depending on some runtime-calculated operation
        // How do I do this nicely here?
    }
}

但是,根据我的理解,将 () 放在每个策略的末尾会初始化对象(?),而我可能只想根据某些运行时条件创建一个对象。

无论哪种方式,是否可以将 lazy 放置在 Array class 成员值周围的某处,以便仅在我请求时实例化我想要的值?还是我必须通过闭包或其他替代方案来解决这个问题?


当前尝试

这是在按照我的想法行事吗?直到我得到数组的第一个元素并执行它,它才会真正实例化策略?

private var availableStrategies: [() -> (StrategyProtocol)] = [
    { OneClassThatImplementsStrategyProtocol() }
]

ANYCLASS, META TYPE AND .SELF may answer your question. (I am not expert on Swift, but use of metaclasses is likely what you want and Swift, as I expected, appears to support them.) You can look through this Stack Overflow search.

编辑:如果不清楚,我们的想法是让策略数组包含协议的元classes 而不是实例化。虽然这取决于您是否需要为 class 和惰性 属性 的每个实例化一个新的策略对象,或者策略是否是有效的全局策略和创建的缓存策略。如果是后者,那么保存它们的惰性数组方法可能会更好。

你的 "Current attempt" 做你想做的事。你有一个数组 闭包,并且策略仅在闭包被初始化时被初始化 已执行。

一个可能的替代方案:存储一个 types 的数组而不是 实例或闭包(如 )。

为了按需创建实例,一个 init() 要求必须添加到协议中(然后必须 被 required init() 满足,除非 class 是 final, 比较 ).

一个可能的优势是您可以查询静态属性 以便找到合适的策略。

这是一个独立的小例子,其中 createStrategy() 创建并 returns 第一个 "fantastic" 策略:

protocol StrategyProtocol {
    init()
    static var isFantastic: Bool { get }
}

class OneClassThatImplementsStrategyProtocol : StrategyProtocol {
    required init() { }
    static var isFantastic: Bool { return false }
}

final class AnotherThatImplementsStrategyProtocol : StrategyProtocol {
    init() { }
    static var isFantastic: Bool { return true }
}

class StrategyFactory {
    private var availableStrategies: [StrategyProtocol.Type] = [
        OneClassThatImplementsStrategyProtocol.self,
        AnotherThatImplementsStrategyProtocol.self // etc
    ]

    public func createStrategy() -> StrategyProtocol? {
        for strategy in availableStrategies {
            if strategy.isFantastic {
                return strategy.init()
            }
        }
        return nil
    }
}