如何区分玩家现金和现金操纵之间的关系?

问题描述 投票:1回答:1

[在一个非常小的游戏中,我写的player有一些现金(只是Int),但是我不想直接操纵player类中的现金;我觉得玩家阶层不应该在乎现金操纵。

因此,我将所有现金处理都转移到另一个类中。

在这里,我感到困惑。我正在阅读VIPER和其他模式,其中“围墙花园”意味着一个班级通常将不了解其父级或直接访问另一个对象。

因此,在这种情况下,我不确定是否要把玩家的现金与将现金贷记/借记到玩家的钱包之间的担忧分开。

[在我的现金处理器中,我需要进行一些错误检查,throw错误和其他操作;目前,这对我的问题并不重要;因此,我删除了这些内容,以专注于我的问题的主旨。

我正在使用Swift Playgrounds来探讨有关如何解决这个小问题的2个主要想法。

// : Idea #1 -- Use static functions

class Player {
    var cash: Int = 0
}
let p = Player.init()


struct Wallet{
    static func credit(account: Player, amount: Int) {
        // (#TODO) the final one will do some checks, throw an error
        var balance: Int = account.cash
        balance += amount
        account.cash = balance
    }
    static func debit(account: Player, amount: Int)  {
        // (#TODO) the final one will do some checks, throw an error
        var balance: Int = account.cash
        balance -= amount
        account.cash = balance
    }
}
Wallet.credit(account: p, amount: 125)
Wallet.debit(account: p, amount: 25)
print (p.cash)

好吧,在这一章中,我使用静态函数;但是Wallet结构可以直接访问播放器。我觉得这是错的。

我第二次尝试:

class Player {
    var account: Account = Account()

    var cash: Int {
        return account.balance
    }

    init(cash: Int) {
        self.account = Account(openingBalance: cash)
    }
}

var p = Player.init(cash: 50)

class Account {
    public private(set) var balance: Int = 0

    init(openingBalance: Int = 0) {
        self.balance = openingBalance
    }

    func credit(amount: Int) -> Int {
        balance += amount
        return self.balance
    }

    func deposit(amount: Int) -> Int {
        balance -= amount
        return self.balance
    }
}

p.account.credit(amount: 100)
print (p.cash)

这个人感觉更干净,但是现在Player对象可以直接访问Account


编辑:我有第三次尝试。我看到了一个称为proxy design pattern的东西,如果我不熟悉该模式,对不起。据我了解,您可以在玩家和银行帐户之间充当代理人的角色,以决定玩家是否可以贷记或借记他们的帐户。

可悲的是,该实验无法正常进行;现在,我有一个看似无止尽的do-catch语句循环;我不确定如何将其踢回主程序。

// : Third attempt -- I think this follows a Proxy pattern

public enum CashError: Error, Equatable {
    case mustBePositive
    case notEnoughFunds
    case cannotPerformTransaction
    case amountWouldBeNegative
}

class Bank {
    var balance: Int = 0

    enum TransactionType: Int {
        case credit = 0
        case debit
    }

    func performTransaction(transactionType: TransactionType, amount: Int) {
        switch transactionType {
        case .credit:
            self.credit(amount: amount)
        case .debit:
            self.debit(amount: amount)
        }
    }

    private func credit(amount: Int = 0) {
        print ("didCredit: \(amount)")
        self.balance += amount
    }

    private func debit(amount: Int = 0) {
        print ("didDebit: \(amount)")
        self.balance -= amount
    }
}

class Customer {
    private(set) var accountProxy: AccountProxy?

    var cash: Int {
        guard let proxy: AccountProxy = accountProxy else {
            return 0
        }
        return proxy.balance
    }

    init(cash: Int = 0) {
        print ("Create player with $\(cash)")

        self.accountProxy = AccountProxy.init(customer: self)

        guard let proxy = self.accountProxy else {
            return
        }

        do {
            let _ = try proxy.handle(transactionType: .credit, amount: cash)
        } catch {
            print (error)
        }
    }
}

class AccountProxy {
    private var bank: Bank = Bank()
    private var customer: Customer
    public var balance: Int {
        return self.bank.balance
    }

    init(customer: Customer) {
        self.customer = customer
    }

    func handle(transactionType: Bank.TransactionType, amount: Int = 0) throws -> Bool {
        print ("Attempting \(transactionType) of $\(amount)")

        do {
            if let _ = try canPerformTransaction(transactionType: transactionType, amount: amount) {
                print ("proxy: says you can \(transactionType): $\(amount)")
                self.bank.performTransaction(transactionType: transactionType, amount: amount)
                return true
            }
            else {
                print ("proxy: error - Cannot perform transction")
                throw CashError.cannotPerformTransaction
            }
        } catch {
            throw (error)
        }
    }

    // (Private) functions

    private func canPerformTransaction(transactionType: Bank.TransactionType, amount: Int ) throws -> Bool? {
        switch transactionType {
        case .credit:
            do {
                guard let result = try canCredit(amount: amount) else {
                    return false
                }
                return result
            } catch {
                throw error
            }

        case .debit:
            do {
                guard let result = try canDebit(amount: amount) else {
                    return false
                }
                return result
            } catch {
                throw error
            }
        }
    }

    private func canCredit(amount: Int) throws -> Bool? {
        guard amount >= 0 else {
            throw CashError.mustBePositive
        }
        return true
    }

    private func canDebit(amount: Int) throws -> Bool? {
        // amount must be > 0
        guard amount > 0 else {
           throw CashError.mustBePositive
       }
        // balance must be >= amount
       guard balance >= amount else {
           throw CashError.notEnoughFunds
       }
        // the remaining sum must be >= 0
       let sum = balance
       guard ((sum - amount) >= 0) else {
           throw CashError.amountWouldBeNegative
       }
        return true
    }
}


let bob = Customer.init(cash: 100)
print ("Bob has $\(bob.cash)")
do {
    let _ = try bob.accountProxy?.handle(transactionType: .credit, amount: 125)
} catch {
    print (error)
}
print ("Bob has $\(bob.cash)")
do {
    let _ = try bob.accountProxy?.handle(transactionType: .debit, amount: 25)
} catch {
    print (error)
}
print ("Bob has $\(bob.cash)")

// (Logged Output):
// Create player with $100
// Attempting credit of $100
// proxy: says you can credit: $100
// didCredit: 100
// Bob has $100
// Attempting credit of $125
// proxy: says you can credit: $125
// didCredit: 125
// Bob has $225
// Attempting debit of $25
// proxy: says you can debit: $25
// didDebit: 25
// Bob has $200

因此,我的查询基于“围墙花园”的概念?玩家阶层应该了解其帐户吗?

我很抱歉,如果这看起来很明显,我会感到非常沮丧/困惑。

我对此表示感谢/感谢。

swift design-patterns theory separation-of-concerns
1个回答
1
投票

当然有这么小的例子,分离关注点可能不是很有用,但我会继续使用它...

class Player {
    let wallet: Wallet
    // no reference to cash here.
}

class Wallet {
    private var cash: Int
    // methods manipulating cash go here.
}

现在,播放器不需要任何代码来操纵cash变量,但这意味着该播放器将必须公开其电子钱包,以便其他人可以投入现金或将其取出。这将关注点分开,但破坏了围堵。 Player对象无法再控制谁或什么从钱包中取出现金,并且在现实生活中,例如这些东西的例子,这听起来像是个坏主意。

您可以在Player中将电子钱包设为私有,但是这样做会使电子钱包多余。除非您不信任播放器以确保其cash当然不会为负。

用例将决定可能的适当关系。我最喜欢的示例是关于汽车及其引擎的。对于“ startCar”用例,明显的关系是包含[Car]<>-->[Engine]。驾驶员要发动汽车时,并不在乎引擎内部。但是,对于“换油”用例,最佳关系是关联[Car]--->[Engine],因为机械师将希望直接访问发动机,而不必每次将发动机从汽车中提起并更换它时,进行更改。

希望此杂乱无章...

© www.soinside.com 2019 - 2024. All rights reserved.