-
추상화 된 프로토콜 만들기iOS 앱 개발 부트캠프/TIL 2024. 10. 31. 21:04
이번주 내내 하던 계산기 과제의 Lv4에서는 추상화 개념을 사용해 AbstractOperation 이라는 추상화된 프로토콜을 만들어 기존의 클래스들과 관계를 맺고 Calculator 클래스 내부 코드를 변경하는 작업을 해야한다.
추상화??
추상화란 무엇일까? 추상화란 복잡한 시스템을 간단한 개념으로 변환하는 것을 말하며 관련성이 없는 세부 사항을 제거하고 중요한 특성만을 강조하는 것이다. 일종의 청사진을 만드는 것으로, 프로토콜에서 특정 기능을 수행하는 로직을 정의하고, 어떻게 수행할지는 하위 클래스들에게 맡기는 것이다.
따라서 추상화 된 프로토콜을 만들라고 하는 것은 AbstractOperation 프로토콜에서 함수나 변수, 매개변수 등을 정의하고, 자세한 구현은 관계를 맺을 더하기, 빼기, 곱하기, 나누기 클래스들에게 맡기는 식으로 작성할 수 있을 것이다.
프로토콜 선언
이전에 작성한 코드에서 프로토콜을 사용해 코드를 수정해보았다.
// 추상화를 통해 공통된 인터페이스(calculate) 정의 protocol AbstractOperation { func calculate (_ firstNumber: Double, _ secondNumber: Double) -> Double }
AbstractOperation 이라는 프로토콜에 calculate 함수를 정의하여 이후 작성할 연산 클래스들이 공통으로 사용할 인터페이스를 제공하면서도 구체적인 구현은 하지 않았다. 이제 구체적인 구현, 여기서는 각 연산에 맞는 retrun을 작성하게 될 것이다.
덧셈, 뺼셈, 곱셈, 나눗셈, 나머지 연산 클래스 만들기
다음은 연산 클래스 작성이다.
// 더하기 클래스 class AddOperation: AbstractOperation { func calculate(_ firstNumber: Double, _ secondNumber: Double) -> Double { return firstNumber + secondNumber } } // 빼기 클래스 class SubtractOperation: AbstractOperation { func calculate(_ firstNumber: Double, _ secondNumber: Double) -> Double { return firstNumber - secondNumber } } // 곱하기 클래스 class MultiplyOperation: AbstractOperation { func calculate(_ firstNumber: Double, _ secondNumber: Double) -> Double { return firstNumber * secondNumber } } // 나누기 클래스 class DivideOperation: AbstractOperation { func calculate(_ firstNumber: Double, _ secondNumber: Double) -> Double { return firstNumber / secondNumber } } // 나머지 클래스 class RemainderOperation: AbstractOperation { func calculate(_ firstNumber: Double, _ secondNumber: Double) -> Double { return firstNumber.truncatingRemainder(dividingBy: secondNumber) } }
이전에 작성한 코드와 거의 같지만 클래스 선언 시 '클래스명: AbstractOperation' 이라는 구문을 추가하여 AbstractOperation 프로토콜을 따르도록 작성하였다.
Calculator 클래스 수정하기
다음은 Calculator 클래스를 수정하였는데,
//이전 Calculator 클래스의 내용 var addOperation: AddOperation var subOperation: SubtractOperation var mulOperation: MultiplyOperation var divOperation: DivideOperation var remOperation: RemainderOperation init() { self.addOperation = AddOperation() self.subOperation = SubtractOperation() self.mulOperation = MultiplyOperation() self.divOperation = DivideOperation() self.remOperation = RemainderOperation() } }
이런 식으로 모든 연산에 대한 인스턴스를 생성하고 초기화 했던 것과 달리,
class Calculator { var operation: AbstractOperation // 프로토콜을 따르는 인스턴스 생성, 모든 연산에 대한 인스턴스를 생성할 필요 없다 init(parameterOperation: AbstractOperation) { // 필요한 연산을 파라미터로 받음 self.operation = parameterOperation } // operation 객체에 따라 구체적인 연산을 대신 호출하는 메서드 func performCalculation(_ firstNumber: Double, _ secondNumber: Double) -> Double { return operation.calculate(firstNumber, secondNumber) } }
이런 식으로 AbstractOperation 프로토콜을 따르는 operation 인스턴스 하나만 생성하였고, 각 연산에 대한 부분은 이 클래스가 사용될 때 매개변수로 parameterOperation 이라는 매개변수로 하여 필요한 연산을 그때 그때 받아 초기화하도록 하였다.
이후 Calculator 클래스 안에 operation.calculate() 형식으로 하여 초기화 된 operation의 객체에 따라 필요한 연산을 수행하도록 대신 호출하는 함수를 작성하였다.
Calculator 클래스가 구체적인 구현체인 각 연산 클래스에 직접 의존하던 기존 방식과 달리 추상화 된 프로토콜인 AbsctractOperationd을 따르므로 의존성 역전 원칙이 지켜지게 되어 모듈간 결합도가 낮아지고 다양한 곳에서 재사용 할 수 있게 될 것이고, 새로운 기능을 추가할 때 Calculator 코드를 수정할 필요 없이 새로운 클래스를 AbstractOperation 프로토콜에 맞게 구현하면 되기 때문에 기존 코드의 수정을 최소화 할 수 있다.
출력 구현
// 출력 구현부 let firstNumber: Double = 14 let secondNumber: Double = 10 // 배열을 통해 다양한 연산을 동일한 인터페이스로 처리(다형성) let definedOperations: [AbstractOperation] = [AddOperation(), SubtractOperation(), MultiplyOperation(), DivideOperation(), RemainderOperation()] // 반복문을 통해 배열에 저장된 각 연산의 인스턴스를 파라미터로 넘기기 for currentOperation in definedOperations { let calculator = Calculator(parameterOperation: currentOperation) print(calculator.performCalculation(firstNumber, secondNumber)) }
마지막으로 출력 구현부는 위와 같이 작성하였다.
객체지향에 대해 찾아보다가 다형성이라는 개념을 찾았는데, 같은 인터페이스를 통해 다양한 형태의 객체를 다룰 수 있게 하는 걸 말한다고 한다. 쉽게 말하면, + 연산자가 숫자 사이에 있을 땐 기호 양쪽의 숫자를 더하는 덧셈 기호이지만, 문자 사이에 있으면 문자열을 만드는 기호로 작동하는 것처럼, 같은 구문을 가지고 다른 동작을 하도록 만드는 것을 말한다.
이런 개념을 좀 더 응용해서, 출력 함수 구문이 다른 출력을 하지만 내용이 거의 같아서 이걸 일일이 다 쓰는 게 아니라 좀 더 간단하게 만들 수 있을 것 같았다.
각 연산의 인스턴스를 배열에 넣은 뒤, 반복문을 통해 각각의 인스턴스를 따로 뽑아 Calculator에 파라미터로 전달하여 같은 구문을 사용하지만 파라미터로 쓰인 인스턴스에 따라 덧셈, 뺄셈, 나눗셈, 곱셈, 나머지 연산 등 다양한 동작을 하도록 다형성을 활용하였다.
결과 화면 'iOS 앱 개발 부트캠프 > TIL' 카테고리의 다른 글
짝수의 합, 배열의 평균 값 (2) 2024.11.02 클래스와 구조체의 인스턴스 그리고 초기화 (0) 2024.11.01 자동완성 없이 코딩하기 (0) 2024.10.30 swift 문법 기초 챕터1 Recap (0) 2024.10.29 간단한 계산 로직 만들기 (0) 2024.10.28