Swift中的通用flyweight模式

时间:2019-07-18 00:00:34

标签: swift flyweight-pattern

我正在尝试在Swift中实现通用的flyweight模式。在我的代码中,我使用的是弱引用字典。基本协议(Node)仅具有位置。更改位置会创建一个新的Node

当不再有对给定重量的引用时,我在网上看到的实现方式不会尝试清理问题。

符合Node的类可以选择使用Factory进行flyweighting,它维护现有对象的字典。

  • 释放值后,哈希函数将更改(请参见Weak<T>.hash(into:))。这会破坏一切吗?
  • 最好不拥有这些值,并以某种方式从deinit的工厂中删除这些值?我能以一般方式做到吗?
  • 身份运算符===不能用于协议类型。我可以通过测试以某种方式解决这个问题吗?
  • 有更简单的方法吗?

完整的游乐场代码

import Foundation

protocol Node {
    // Immutable: changing the position returns a new node
    func position(_ p:CGPoint) -> Node
    func printAddress()
}

protocol HashableNode : class, Hashable, Node { }

struct Weak<T : HashableNode> : Hashable {
    static func == (lhs: Weak<T>, rhs: Weak<T>) -> Bool {
        return lhs.value == rhs.value
    }

    weak var value : T?

    func hash(into hasher: inout Hasher) {
        value?.hash(into: &hasher)
    }
}

class Factory<T:HashableNode> {
    var values = [Weak<T> : Weak<T>]()

    func make(_ proto: T) -> T {
        let w = Weak<T>(value: proto)
        if let v = values[w] {
            if let r = v.value {
                return r
            }
        }
        values[w] = w
        return proto
    }
}

class TestNode : HashableNode {

    deinit {
        print("TestNode deinit")
    }

    // Can I define equality and hash automatically?
    static func == (lhs: TestNode, rhs: TestNode) -> Bool {
        return lhs.p == rhs.p
    }

    func hash(into hasher: inout Hasher) {
        hasher.combine(p.x)
        hasher.combine(p.y)
    }


    let p:CGPoint

    init(p: CGPoint) {
        print("TestNode init")
        self.p = p
    }

    func position(_ p: CGPoint) -> Node {
        return testNodeFactory.make(TestNode(p: p))
    }

    func printAddress() {
        print(Unmanaged.passUnretained(self).toOpaque())
    }

}

let testNodeFactory = Factory<TestNode>()

func runTest() {

    let n0 = testNodeFactory.make(TestNode(p: CGPoint.zero))
    let n1 = testNodeFactory.make(TestNode(p: CGPoint.zero))

    assert(n0 === n1)

    n0.printAddress()
    n1.printAddress()

    let n2 = n0.position(CGPoint(x: 1, y: 1))

    n2.printAddress()

    // Doesn't compile:
    // Binary operator '!==' cannot be applied to operands of type 'Node' and 'TestNode'
    // assert(n2 !== n0)

}

runTest()
print("done!")

1 个答案:

答案 0 :(得分:2)

此行:

from itertools import islice

def qud(x,p):
    x_sqr = x**2
    x_qud = x**3
    while True:
        p = x_sqr*p                        # update p
        yield x_sqr ,x_qud,p               # yield instead of return

my_iterator = qud(2,1/2)                   # create an iterator based on itial values

for values in islice(my_iterator, 0, 4):   # loop over an islice 
    print(values)

此处调用的position方法将返回let n2 = n0.position(CGPoint(x: 1, y: 1)) ,而不是您为NodeTestNode明确创建的n1。编译器不知道如何比较这两种类型。

您可以为TestNode <-> Node实现n2或将cast n2键入为TestNode