「リファクタリング 第2版」Swiftでコーディング その20

リファクタリング 第2版

37-38頁 第1章 型による計算処理の再編成「関数をPerformanceCalculatorに移動」「関数の移動(p.206)」

Swift版 createStatementData.swift

import Foundation

struct PerormanceMapPlay {
    let performance: Performance
    let play: Play
    var amount: Int = 0
    var volumeCredits: Int = 0
}

struct StatementData {
    let customer: String
    let performances: [PerormanceMapPlay]
    var totalAmount: Int = 0
    var totalVolumeCredits: Int = 0
}

public class PerformanceCalculator {
    let aPerformance: Performance
    let play: Play

    init(aPerformance: Performance, play: Play) {
        self.aPerformance = aPerformance
        self.play = play
    }

    func amount() -> Int {
        var result = 0

        switch self.play.type {
        case "tragedy":
            result = 40000
            if self.aPerformance.audience > 30 {
                result += 1000 * (self.aPerformance.audience - 30)
            }
        case "comedy":
            result = 30000
            if self.aPerformance.audience > 20 {
                result += 10000 + 500 * (self.aPerformance.audience - 20)
            }
            result += 300 * self.aPerformance.audience
        default:
            print("error")
        }
        return result
    }
    
    func volumeCredits() -> Int {
        var result = 0
        result += max(self.aPerformance.audience - 30, 0)
        if "comedy" == self.play.type {
            result += Int(self.aPerformance.audience / 5)
        }
        return result
    }
}

func playFor(aPerformance:Performance) -> Play {
    return plays[aPerformance.playID]!
}

func usd(aNumber:Int) -> String {
    let format = NumberFormatter()
    format.numberStyle = .currency
    format.locale = Locale(identifier: "en_US")
    return format.string(from: NSNumber(value: aNumber / 100))!
}

func totalVolumeCredits(data:StatementData) -> Int {
    return data.performances.reduce(0) { (num: Int, perf: PerormanceMapPlay) -> Int in
        num + perf.volumeCredits
    }
}

func totalAmount(data:StatementData) -> Int {
    return data.performances.reduce(0) { (num: Int, perf: PerormanceMapPlay) -> Int in
        num + perf.amount
    }
}

func enrichPerfoemance(aPerformance:[Performance], plays:Dictionary<String, Play>) -> [PerormanceMapPlay] {
    var result: [PerormanceMapPlay] = []
    for perf in aPerformance {
        let calculator = PerformanceCalculator(aPerformance: perf, play: playFor(aPerformance: perf))
        var perormanceMapPlay = PerormanceMapPlay(performance: perf, play: calculator.play)
        perormanceMapPlay.amount = calculator.amount()
        perormanceMapPlay.volumeCredits = calculator.volumeCredits()
        result.append(perormanceMapPlay)
    }
    return result
}

func createStatementData(invoice:Invoice, plays:Dictionary<String, Play>) -> StatementData {
    var result = StatementData(customer: invoice.customer, performances: enrichPerfoemance(aPerformance: invoice.performances, plays: plays))
    result.totalAmount = totalAmount(data: result)
    result.totalVolumeCredits = totalVolumeCredits(data: result)
    return result
}

Swift

Posted by shi-n