使用 swift 代理模式,如何修改私有变量?

Using the swift proxy pattern, how do you modify a private variable?

我正在 Swift 游乐场试验基本代理模式;我不是 100% 熟悉它;但有些视频很有用。

在我的实验中,主体 C 通过代理调用来执行上述操作

即:

A - Proxy - C

然而,在我的实验中我发现我可以直接调用 C 本身,甚至不需要代理;所以我想知道既然我可以直接调用 C 为什么还要使用代理呢?

所以我决定将 C 中的变量设为私有;但是现在我无法调用它们,也无法进行修改,我不知道如何解决。

我还尝试了我在 Whosebug 上找到的 "decorator" 模式来尝试操纵 Cs 变量,但它仍然标记为私有,所以这是不可能的。

此外,我发现的装饰器模式使用 static 个变量。这让我觉得很好,为什么不直接写一个在内存中创建 c 的静态函数,然后将 proxy 中的引用更新为静态函数结果的引用。

我想我在这里误解的是代理 class 的意义是什么,如果你可以直接调用主题(在这种情况下 C)?

示例使用 Swift 游乐场:

class A {
    let proxy: Proxy = Proxy()
    var funds: Int {
        return self.proxy.funds
    }
}

class Proxy {
    private let c: C = C()
    public var funds: Int {
        return c.funds
    }

    private func canIGetFunds() -> Bool {
        guard (self.funds > 0) else {
            return false
        }
        return true
    }

    func subtractFunds(funds: Int = 0) {
        if (canIGetFunds()) {
            print ("you have enough funds")
            willDebit(funds: funds)
        }
        else {
            print ("Not enough funds")
        }
    }

    private func willDebit(funds: Int = 0) {
        self.c.funds -= funds
    }
}

class C {
    private (set) var funds: Int = 100
}

let a = A()
print (a.funds)
a.proxy.subtractFunds(funds: 50)

此代码将在以下位置引发编译器错误:

self.c.funds -= funds

因为:

funds setter is inaccessible

资金变量确实是 private

所以,我也尝试了装饰器;我从 Whosebug 找到的代码(不是我的):

@propertyWrapper
struct Announced<T, U> {

    private var announcedFunction: (T) -> U
    var wrappedValue: (T) -> U { announcedFunction }

    init(wrappedValue: @escaping (T) -> U) {
        announcedFunction = { args in
            let rv = wrappedValue(args)
            print("In: \(args)")
            print("Out: \(rv)")
            return rv
        }
    }
}

extension Wallet {
    @Announced static var add: ((Int, Int)) -> Int = { [=13=].0 + [=13=].1 }
    @Announced static var subtract: ((Int, Int)) -> Int = { [=13=].0 - [=13=].1 }
}

这里的add和subtract是静态变量;并且闭包的内容当然是错误的,因为我没有引用实际的钱包变量——我只是这样写以帮助讨论。

我绕过它的方法是尝试让 (Int, Int) 接受一个 Wallet class,然后 return 一个修改过的 Wallet 对象,其中添加或减去完成

所以像这样:

@Announced static var subtract: ((w:Wallet, Int)) -> Wallet = {
        let newWallet = Wallet()
        newWallet.cash = w.cash
        newWallet.cash -= [=14=].1
        return newWallet
    }

但是如果我采用这种模式,我不明白为什么我不只写一个静态函数而忽略这个装饰器。

我什至尝试让 C 遵循 delegate 模式,其中钱包是 C 的委托并添加、减去资金;但这也有一个问题,您可以直接调用 C,因为它是自己的委托,所以没有理由失败或抛出错误等

所以无论如何,可能我只是过于复杂了:

如果您可以直接调用主题并以这种方式进行操作,那么拥有代理有什么意义?

有没有办法使代理模式成为您可以调用该主题并对其进行操作的唯一方式?

谢谢?

最简单的方法是使用 public/internal setter

class C {
    var funds: Int = 100
}

但是如果您在同一个文件中使用 Proxy 定义 C,那么您可以使用 fileprivate(set) 访问修饰符

class Proxy {
    ...
}

class C {
    fileprivate(set) var funds: Int = 100
}