Объединить два класса в один класс - PullRequest
0 голосов
/ 03 октября 2018

У меня есть два класса: 1. Класс дроби: числитель и знаменатель И 2. Класс OperationWithFractions, который выполняет вычисления, такие как сложение двух дробей, и представляет результат в виде строковой дроби (например, 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 голосов
/ 03 октября 2018

Похоже, вы хотите избежать определения двух свойств и инициализатора в обоих классах.Это достаточно просто;просто используйте дженерики, такие как

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
    }
}

Затем вы можете создать подкласс этого класса для создания подклассов Fraction и OperationWithFractions:

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.firstOperand, secondOperand.firstOperand и т. Д. Не очень понятны. И в этом заключается ваша проблема: вы пытаетесь сэкономить себе немного времени, но в процессе вы запутали проблему, которую решаете, потому что вам пришлось выбрать достаточно общее имя длясвойства.В таком случае вряд ли стоит делать это.Тебе было бы лучше, чем раньше, где имена свойств означали что-то.

0 голосов
/ 03 октября 2018

Добавление двух дробей должно возвращать 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

Теперь вы можете добавлять другие операторы (например, * 1035).*, *, /), проверка ошибок (например, для нулевого знаменателя или целочисленное переполнение), дополнительные методы экземпляра (например, «абсолютное значение») и т. Д.

0 голосов
/ 03 октября 2018
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, поскольку он существует исключительно для форматирования ваших входящих данных.

Далее язаменил ваш var fraction1: Fraction на private let fraction1: Fraction.Это инкапсулирует логику, которая нужна только вашему классу.

Функция init не изменилась.

Наконец, я очистил ваш возврат, поскольку нет необходимости устанавливать исходную переменную и отдельный возврат.

Также можно просто создать инициализатор, который принимает num1, den1, num2, den2 и т. Д., Но это не будет хорошо масштабироваться, если вы захотите добавить 3 или более дроби.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...