在一堂课中合并两堂课

时间:2018-10-03 17:23:13

标签: ios swift class

我有两个类:1.分数类:分子和分母与2. 2. OperationWithFractions类执行类似于将两个分数相加的计算,并将结果表示为String分数(例如32/5)。

它可以工作,但是我想通过将两个类合并为一个来简化,因此所有属性,方法和初始化程序都将在同一伞下。

class Fraction {
    var numerator = 0
    var denominator = 0

    init (_ numer: Int, _ denom: Int){
        self.numerator = numer
        self.denominator = denom
    }
}

class OperationWithFractions {
    var fraction1: Fraction
    var fraction2: Fraction

    init(_ fraction1: Fraction, _ fraction2: Fraction) {
        self.fraction1 = fraction1
        self.fraction2 = fraction2
    }

    func addFractions()->String {
        var result = ""

        result = "\(fraction1.numerator * fraction2.denominator + fraction1.denominator * fraction2.numerator) / \(fraction1.denominator * fraction2.denominator)"

        return result
    }
}

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        let result = OperationWithFractions(Fraction(5, 10), Fraction(10, 20)).addFractions()
        print(result)

        let result2 = OperationWithFractions(Fraction(10, 2), Fraction(8, 2)).addFractions()
        print(result2)
    }
}

3 个答案:

答案 0 :(得分:3)

两个分数相加应返回一个Fraction,而不是字符串。转换 仅当需要文本表示形式(例如,打印最终结果)时,才将字符串转换为字符串。

算术运算可以作为运算符 分数类型:

struct Fraction {
    // ...

    static func +(lhs: Fraction, rhs: Fraction) -> Fraction { ... }
}

那可以让你写

let result = Fraction(1, 2) + Fraction(-1, 6)

相对于引用类型和常量属性,它们也更喜欢值类型 超过可变属性。第一个实现可能是

struct Fraction {
    let numerator: Int
    let denominator: Int

    init (_ numer: Int, _ denom: Int) {
        self.numerator = numer
        self.denominator = denom
    }

    static func +(lhs: Fraction, rhs: Fraction) -> Fraction {
        return Fraction(lhs.numerator * rhs.denominator + lhs.denominator * rhs.numerator,
                        lhs.denominator * rhs.denominator)
    }
}

采用CustomStringConvertible协议来提供 文字表示形式:

extension Fraction: CustomStringConvertible {
    var description: String {
        return "\(numerator)/\(denominator)"
    }
}

这已经有效

// Compute 1/2 - 1/6 + 1/3:
let result = Fraction(1, 2) + Fraction(-1, 6) + Fraction(1, 3)
print(result) // 24/36

,但结果并不完全令人满意,因为 不简化为最低的通用术语。也是

 print(Fraction(2, -3)) // 2/-3

不是最佳选择。

这里是一个稍微复杂一些的版本, 结果降低到最低的条件。除了 gcd实用程序功能,所有内容都在 Fraction类型。

// Greatest common divisor
func gcd(_ a : Int, _ b : Int) -> Int {
    var (a, b) = (a, b)
    while b != 0 {
        (a, b) = (b, a % b)
    }
    return a
}

struct Fraction {
    let numerator: Int
    let denominator: Int

    init (_ numer: Int, _ denom: Int, reduce: Bool = false) {
        if reduce {
            let commonFactor = gcd(numer, denom)
            self.numerator = numer / commonFactor
            self.denominator = denom / commonFactor
        } else {
            self.numerator = numer
            self.denominator = denom
        }
    }

    static func +(lhs: Fraction, rhs: Fraction) -> Fraction {
        return Fraction(lhs.numerator * rhs.denominator + lhs.denominator * rhs.numerator,
                        lhs.denominator * rhs.denominator, reduce: true)
    }
}

extension Fraction: CustomStringConvertible {
    var description: String {
        if denominator == 1 {
            return "\(numerator)"
        } else if denominator < 0 {
            return "\(-numerator)/\(-denominator)"
        } else {
            return "\(numerator)/\(denominator)"
        }
    }
}

用法示例:

// Compute 1/2 - 1/6 + 1/3:
let result = Fraction(1, 2) + Fraction(-1, 6) + Fraction(1, 3)
print(result) // 2/3

现在您可以添加其他运算符(例如-*/),错误检查 (例如分母为零或整数溢出),其他实例方法(例如“绝对值”)等。

答案 1 :(得分:2)

Makefile

现在,这是怎么回事?

我将整个分数类转换为$ ls Makefile test.c $ cat Makefile libTest.a: libTest.a(test.o) $(AR) $(ARFLAGS) $@ $? $ make `libTest.a' is up to date. $ ls Makefile test.c ,因为它仅用于格式化输入数据。

接下来,我将您的class OperationWithFractions { typealias Fraction = (numerator: Int, denominator: Int) private let fraction1: Fraction private let fraction2: Fraction init(_ fraction1: Fraction, _ fraction2: Fraction) { self.fraction1 = fraction1 self.fraction2 = fraction2 } func addFractions() -> String { return "\(fraction1.numerator * fraction2.denominator + fraction1.denominator * fraction2.numerator) / \(fraction1.denominator * fraction2.denominator)" } } let fraction1 = OperationWithFractions.Fraction(numerator: 1, denominator: 2) let fraction2 = OperationWithFractions.Fraction(numerator: 2, denominator: 3) let operation = OperationWithFractions(fraction1, fraction2) print(operation.addFractions()) // 7/6 替换为typealias。这封装了只有您的类需要的逻辑。

init函数不变。

最后,由于不需要设置初始变量和单独的收益,因此我清理了您的收益。

也可以只创建一个接受num1,den1,num2,den2等的初始化程序,但是如果要添加3个或更多的分数,这将无法很好地扩展。

答案 2 :(得分:1)

您似乎想避免在两个类中都定义两个属性和初始化程序。这很容易;只需使用泛型,例如

class MathematicalOperation<T> {  // you can limit T to numerics, but there's no advantage here
    var firstOperand: T
    var secondOperand: T

    init (_ first: T, _ second: T){
        firstOperand = first
        secondOperand = second
    }
}

然后,您可以将此子类化为FractionOperationWithFractions子类:

class Fraction: MathematicalOperation<Int> {
    // no need to define another initializer or properties
}

class OperationWithFractions: MathematicalOperation<Fraction> {
    func addFractions()->String {
        return "\(firstOperand.firstOperand * secondOperand.secondOperand + firstOperand.secondOperand * secondOperand.firstOperand) / \(firstOperand.secondOperand * secondOperand.secondOperand)"
    }
}

但是,这显然不理想,因为firstOperand.firstOperandsecondOperand.firstOperand等不是很清楚。 问题就在其中:您正试图为自己节省一些写作时间,但是在此过程中,您混淆了要解决的问题,因为必须选择一个足够通用的名称对于属性。在这种情况下,这样做似乎并不值得。您可能会比以前更好,因为该属性为 meant 命名。