과제를 하고 있었다.
Calculator 클래스를 만드는 과제다.
그래서 만들었다.
class Calculator {
func add(lhs: Int, rhs: Int) -> Int {
return lhs + rhs
}
func subtract(lhs: Int, rhs: Int) -> Int {
return lhs - rhs
}
func multiply(lhs: Int, rhs: Int) -> Int {
return lhs * rhs
}
func divide(lhs: Int, rhs: Int) -> Int {
return lhs / rhs
}
}
let calculator = Calculator()
calculator.add(lhs: 1, rhs: 3)
calculator.divide(lhs: 4, rhs: 2)
calculator.multiply(lhs: 1, rhs: 4)
calculator.subtract(lhs: 14, rhs: 4)
딱히 문제를 마주하지는 않아서... 그냥 생각나는대로 죽 타이핑을 했다.
어차피 바로 Lv. 2로 넘어갈거라 (후략)
class Calculator {
func add(_ lhs: Int, to rhs: Int) -> Int {
return lhs + rhs
}
func subtract(_ lhs: Int, from rhs: Int) -> Int {
return rhs - lhs
}
func multiply(_ lhs: Int, and rhs: Int) -> Int {
return lhs * rhs
}
func divide(_ lhs: Int, by rhs: Int) -> Int {
return lhs / rhs
}
func getRemainder(of number: Int, dividedBy divisor: Int) -> Int {
return number % divisor
}
}
let calculator = Calculator()
// 영어의 어순에 맞게 바꾸어 보았으나... 어떤지는 모르겠다.
calculator.add(5, to: 1)
calculator.subtract(3, from: 4)
calculator.multiply(3, and: 3)
calculator.divide(4, by: 2)
calculator.getRemainder(of: 12, dividedBy: 5)
getRemainder라는 친구를 추가하고, 함수의 전달인자들을 좀 수정하였다.
함수의 라벨과 파라미터들을 저기 주석에 적어놨듯,
영어를 그대로 읽는 느낌을 주면 어떨까 싶어서 해봤는데,
득과 실이 모두 있었다. 뭐냐면...
subtract(빼기 연산)만 홀로 서순이 반대이다.
-> 직관적이지 않다는 말이다.
-> 나머지 친구들은 부호 방향을 따라간다고 생각하면 되는데 말이야.
그로 인해 영어에 능숙하지 않으면 휴먼에러 발생 확률 ↑↑↑
겹살먹고싶다
메소드를 저렇게 작성하면, 경우에 따라 가독성을 크게 향상시킬 수 있을 것으로 보인다.
물론 통일된 모양새가 덜 헷갈릴 수도 있으니 주의를 요한다.
protocol Operator {
var valueA: Int { get }
var valueB: Int { get }
func operate() -> Int
}
class Calculator {
let valueA: Int
let valueB: Int
var result: Int?
// 호출되기 전엔 메모리를 차지하지 않게 lazy var 선언
lazy var adder = Adder(valueA: valueA, valueB: valueB)
lazy var subtractor = Subtractor(valueA: valueA, valueB: valueB)
lazy var multiplier = Multiplier(valueA: valueA, valueB: valueB)
lazy var divider = Divider(valueA: valueA, valueB: valueB)
init(valueA: Int, valueB: Int, result: Int? = nil) {
self.valueA = valueA
self.valueB = valueB
self.result = result
}
func storeResult(of operation: () -> Int) {
result = operation.self()
}
}
var calculator = Calculator(valueA: 3, valueB: 4)
calculator.adder.operate()
calculator.subtractor.operate()
calculator.multiplier.operate()
calculator.divider.operate()
class Adder: Operator {
var valueA: Int
var valueB: Int
init(valueA: Int, valueB: Int) {
self.valueA = valueA
self.valueB = valueB
}
func operate() -> Int {
return valueA + valueB
}
}
class Subtractor: Operator {
var valueA: Int
var valueB: Int
init(valueA: Int, valueB: Int) {
self.valueA = valueA
self.valueB = valueB
}
func operate() -> Int {
return valueA - valueB
}
}
class Multiplier: Operator {
var valueA: Int
var valueB: Int
init(valueA: Int, valueB: Int) {
self.valueA = valueA
self.valueB = valueB
}
func operate() -> Int {
valueA * valueB
}
}
class Divider: Operator {
var valueA: Int
var valueB: Int
init(valueA: Int, valueB: Int) {
self.valueA = valueA
self.valueB = valueB
}
func operate() -> Int {
valueA / valueB
}
}
Lv. 2에서 느꼈던 통일성 부족을 개선하려 하였다.
새로운 요소인 Operator 프로토콜을 이용해서 말이다.
protocol Operator {
var valueA: Int { get }
var valueB: Int { get }
func operate() -> Int
}
이렇게 프로토콜을 작성해주고, 클래스에서 프로토콜을 받아들이게 하면?
class Adder: Operator {
var valueA: Int
var valueB: Int
init(valueA: Int, valueB: Int) {
self.valueA = valueA
self.valueB = valueB
}
func operate() -> Int {
return valueA + valueB
}
}
// 중략
class Divider: Operator {
var valueA: Int
var valueB: Int
init(valueA: Int, valueB: Int) {
self.valueA = valueA
self.valueB = valueB
}
func operate() -> Int {
valueA / valueB
}
}
요로코롬 통일된 모양새가 되는 것이 아주 마음이 편안하다.
lhs(lefthand side), rhs(righthand side), 각각 왼쪽, 오른쪽이라는 뜻인데,
은근히 눈에 안 들어온다. 카멜케이스를 적용한 valueA, valueB로 바꾸어줬다.
외부에서 Operator를 정의하여 갖다 썼다.
-> 그럼 Calculator 클래스는 데이터를 들고만 있고 계산은 Operator들이 하는것이다.
연산 결과를 저장할 수 있는 변수인 result를 추가했다.
-> 옵셔널인 건, nil로 연산결과가 아직 없음을 표시하려고 옵셔널로 지정했다.
-> 이거랑 storeResult(of operation:) 메소드는 내일 할일에 기록하였다.
근데 아직 쓰지 않는 친구들의 이니셜라이징이 한 곳에서 한 번에 진행되는 걸 보고,
뭔가 모르게 마음이 불편해졌다.
물론 여기선 중간에 한번에 사용되긴 하지만,
보통은 한 번에 사용되진 않을 것이라는 생각이 들었다.
그래서, lazy var로 선언해서, 호출되기 전엔 메모리를 차지하지 않게 해주었다.
맞는... 사용이겠지?
이건 내일 할 일에 적어놓았다.
처음 구현할 때 자료형으로 아무 생각 없이 Int를 넣었다가,
아차, 소숫점 아래를 버려버렸구나 라는 생각에 마지막으로 하나만 더 수정했다.
protocol Operator {
var valueA: Double { get }
var valueB: Double { get }
func operate() -> Double
}
class Calculator {
let valueA: Double
let valueB: Double
var result: Double?
// 호출되기 전엔 메모리를 차지하지 않게 lazy var 선언
lazy var adder = Adder(valueA: valueA, valueB: valueB)
lazy var subtractor = Subtractor(valueA: valueA, valueB: valueB)
lazy var multiplier = Multiplier(valueA: valueA, valueB: valueB)
lazy var divider = Divider(valueA: valueA, valueB: valueB)
init(valueA: Double, valueB: Double, result: Double? = nil) {
self.valueA = valueA
self.valueB = valueB
self.result = result
}
func storeResult(of operation: () -> Double) {
result = operation.self()
}
}
class Adder: Operator {
var valueA: Double
var valueB: Double
init(valueA: Double, valueB: Double) {
self.valueA = valueA
self.valueB = valueB
}
func operate() -> Double {
return valueA + valueB
}
}
class Subtractor: Operator {
var valueA: Double
var valueB: Double
init(valueA: Double, valueB: Double) {
self.valueA = valueA
self.valueB = valueB
}
func operate() -> Double {
return valueA - valueB
}
}
class Multiplier: Operator {
var valueA: Double
var valueB: Double
init(valueA: Double, valueB: Double) {
self.valueA = valueA
self.valueB = valueB
}
func operate() -> Double {
valueA * valueB
}
}
class Divider: Operator {
var valueA: Double
var valueB: Double
init(valueA: Double, valueB: Double) {
self.valueA = valueA
self.valueB = valueB
}
func operate() -> Double {
valueA / valueB
}
}