如何将try-catch移动到处理所有try-catch逻辑但又返回错误的类中?

时间:2018-04-15 10:04:35

标签: swift try-catch abstraction

我正在编写一个基本的玩家wallet管理类,其中Integers被添加(记入)或减去(借记)给玩家的钱包,其中错误被简单的try-catch逻辑捕获。

  

注意:它仅用于处理Integers

我试图将try-catch逻辑抽象到这个Wallet类中;它应该处理creditdebit个动作,捕获错误并返回错误(如果找到)。

有没有办法将try-catch内容移动到类中然后返回错误?

让我们来看看这个例子:

我目前的班级是这样的:

enum WalletError : Error {
    case mustBePositive
    case notEnoughFunds
}

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

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

    func credit(amount: Int) throws {
        guard amount > 0 else {
            throw WalletError.mustBePositive
        }
        handleCredit(amount: amount)
    }

    func debit(amount: Int) throws {
        guard amount > 0 else {
            throw WalletError.mustBePositive
        }
        guard balance >= amount else {
            throw WalletError.notEnoughFunds
        }
        guard (self.balance - amount >= 0) else {
            throw WalletError.notEnoughFunds
        }
        handleDebit(amount: amount)
    }

    // MARK: (Private)

    private func handleCredit(amount: Int) {
        self.balance += amount
    }

    private func handleDebit(amount: Int) {
        self.balance -= amount
    }
}

测试借记操作,我有XCTest函数

func testDebit() {
    let w = Wallet()

    XCTAssertTrue(w.balance == 0)

    // Can't debit negative numbers
    XCTAssertThrowsError(try w.debit(amount: -100)) { error in
        XCTAssertEqual(error as? WalletError, WalletError.mustBePositive)
    }

    // can't debit money you don't have
    XCTAssertThrowsError(try w.debit(amount: 100)) { error in
        XCTAssertEqual(error as? WalletError, WalletError.notEnoughFunds)
    }

    // credit $100
    XCTAssertNoThrow(try w.credit(amount: 100))

    // debit $0 should throw error
    XCTAssertThrowsError(try w.debit(amount: 0)) { error in
        XCTAssertEqual(error as? WalletError, WalletError.mustBePositive)
    }

    // debit > balance should throw error
    XCTAssertThrowsError(try w.debit(amount: 101)) { error in
        XCTAssertEqual(error as? WalletError, WalletError.notEnoughFunds)
    }

    // debit $1 should be successful
    XCTAssertNoThrow(try w.debit(amount: 1))

    // balance should be 100-1 = $99
    XCTAssertTrue(w.balance == 99)
}

我在这里遇到的问题是:

当我编写应用程序时,我需要每次都编写try-catch块。

我希望Wallet类能够处理所有try-catch内容,并且只报告错误

我试过了:

// changes to wallet class
func canCredit(amount: Int) throws -> Bool {
    guard amount > 0 else {
        throw WalletError.mustBePositive
    }
    return true
}

func credit(amount: Int) -> Error? {
    do {
        if ( try canCredit(amount: amount) ) {
            handleCredit(amount: amount)
        }
        return nil
    } catch let error {
        return error
    }
}

但是现在XCTest不知道投掷,我需要测试现在只返回true / false的canCredit。

此外,赠送金额会尝试返回错误,但我无法使用XCTAssertThrowsError()

有没有办法可以:

  1. 电子钱包类只应负责信用卡,借记卡和验证

  2. 将我所有的try-catch东西逻辑扔进这个类,所以我不必一直重复try-catch的东西?

  3. 我希望我已经澄清了这个问题。

    谢谢

2 个答案:

答案 0 :(得分:1)

创建函数throw并移交错误

func credit(amount: Int) throws {
    try canCredit(amount: amount)
    handleCredit(amount: amount)  
}
  • 如果canCredit成功,代码将转到下一行并处理信用。
  • 如果canCredit失败,则会移交收到的错误并退出该功能。

答案 1 :(得分:1)

您的目标似乎是抛出错误并将其转换为返回的错误。那个目标似乎错了。抛出一种流控制形式。抛出错误如何“向错误回复”给调用者。首先,你不应该想要你想要的东西。

不过,你可以肯定这样做。首先,保持您的credit(amount:)debit(amount:)方法与第一个代码示例中的方法完全一致,以便您的单元测试可以测试它们。其次,在你的“真实代码”中,不要调用那些方法。相反,调用您提供的其他“包装器”方法,捕获抛出的错误并将其转换为返回的错误。

例如:

func realcredit(amount: Int) -> Error? {
    do {
        try credit(amount:amount)
        return nil
    } catch {
        return error
    }
}