이번 주차에는 개인이 계산기(UI없는)를 만드는 과제가 주어졌다.
Lv1에서 만든 Calculator 클래스에 “나머지 연산”이 가능하도록 코드를 추가하고, 연산 진행 후 출력
Lv1에서 Lv2는 한가지의 기능(나머지 연산)만 추가되기에 같이 작성해보려 한다.
먼저 각 연산을 수행할 수 있는 class를 만드기 위해 Calculator
이라는 class
안에 함수들을 선언해 놓았다. 이 함수들은 값을 받아 연산 후 값을 반환하도록 정의해 놓았다.
사칙연산 이외에도 나머지연산을 위해 함수를 한가지 더 추가했다.
아쉽게도 이 계산기는 직접 값을 입력받아 오는 기능이 없기에 우리는 미리 값을 정의해 놓았다.
Calculator
클래스를 인스턴스로 생성 후 두 값을 각 각의 해당 함수를 실행해 출력해준다.
truncationgRemainder(dividingBy:)
을 이용한다면 Double타입도 쉽게 사용이 가능했다.아래 각각의 클래스들을 만들고 클래스간의 관계를 고려하여 Calculator 클래스와 관계 맺기
Calculator 클래스의 내부코드를 변경
관계를 맺은 후 필요하다면 별도로 만든 연산 클래스의 인스턴스를 Calculator 내부에서 사용
이번에는 아까 만들어 사용했던 함수들을 Calculator
클래스가 아닌 각 함수가 개별적인 class를 갖도록 한 후 클래스들간의 관계를 맺어야한다.
보시는거와 같이 AddOperation
이라는 class를 정의 후 그 안에 메서드로 calculate
를 정의하듯이 연산자별로 class를 정의한 후에 메서드를 정의했다.
앞의 Lv1,2에서는 두개의 값을 미리 변수에 선언하였지만, 이번에는 class내에서 변수를 선언하고 선언한 변수를 init
를 통해 초기화를 해준다.(class는 initializer를 해줘야하지만 struct는 자체에서 memberwise initializer가 존재하기에 필요 없다.)
두 값 뿐만 아니라 연산자를 입력 받아와 switch-case
을 이용해 분기처리를 했으며, 다른 값이 들어온다면 에러를 출력하도록 구성했다.
입력받은 연산자에 맞게 위와 같이 미리 class로 선언했던 class를 인스턴스로 생성 후 그 안의 메서드를 호출해 계산을 한 값을 리턴해서 받아오는 코드로 구현했다.
하나의 파일에 모든 코드를 넣기보단 디렉토리를 나눠서 코드를 작성을 했다.
internal
타입으로 설정되어 있다. swift에서는 5가지의 접근제어가 open
, public
, ìnternal
, fileprivate
, private
이루어져있다. 그래서 기본 타입은 하나의 모듈 내부에서만 접근이 가능하다. 그래서 public
접근자로 바꿔주면 모듈 외부에서도 접근이 가능하게 변경되게 되어 다른 파일에 있는 클래스와 메서드를 사용하게 될 수 있었다.단일 책임 원칙
에 맞게 수정을 하게된 것이다. 이렇게 클래스별로 책임을 분산하여 수정이 이루어지더라도 다른 기능에는 영향이 가지않게 된다.AbstractOperation라는 추상화된 프로토콜 만들기
기존에 구현한 AddOperation(더하기), SubtractOperation(빼기), MultiplyOperation(곱하기), DivideOperation(나누기) 클래스들과 관계를 맺고 Calculator 클래스의 내부 코드를 변경
다음으로는 추상화된 프로토콜을 만들어 클래스간의 결합도, 의존성을 낮추는 과정이다.
현재 각 연산자별 계산하는 함수들은 공통된 특징이 있다. 두 값을 받아와 계산 후 값을 반환한다.
그렇기에 위와 같이 추상화된 프로토콜을 선언해주었다.
그렇게 선언한 프로토콜을 각 연산자의 클래스에서 채택해 사용하고 있다.
그 다음으로 operation
이라는 변수에 프로토콜 타입을 사용할 수 있게 만들었다. 그리고 이니셜라이져할 때도 추상화 프로토콜을 채택한 클래스들 중에서 사용할 클래스를 받아오도록 변경을 했다. 그리고 operating
이라는 메서드를 만들어 계산을 하도록 정의했다.
Public
으로 선언했지만 아래와 같은 오류가 발생했다.initializer
가 접근레벨이 internal
이라고 한다. 하지만 나는 클래스안에 메서드외에는 저장프로퍼티를 작성하지 않았었다. 하지만 찾아보니 클래스가 모든 저장 프로퍼티에 대한 초기값을 가지고 있지 않을때, 직접 초기화해줘야한다고 한다. 그래서 현재 클래스 안에 저장프로퍼티가 없기에 직접 초기화 메서드를 선언해줘야했다.init()
을 직접 선언해주었고, 접근레벨도 public
으로 변경해주었더니 이상없이 잘 작동하게 되었다.Calculator
클래스 안에 정의되어 있기에 만약 연산자 클래스 중 하나가 없어지거나 수정이 된다면 switch-case문에 에러가 발생하게 된다. 이렇듯 Calculator
클래스는 연산자 클래스에 의존을 하고있다고 보면된다. 그렇기에 이런 의존성을 낮추기위해 의존성 역전 원칙(DIP)
을 적용해서 코드를 개선해보았다. 직접 의존하지 않고 AbstractOperation
이라는 추상화한 프로토콜을 거쳐서 Calculator
클래스에 사용하게 된다면 연산자 클래스가 변경이 이루어지더라도 Calculator
클래스에는 영향이 가지않고 직접 의존을 하지않게 된다. 이렇게 결합도를 낮추고 의존성을 낮추어 유지보수에 용이하게 만들 수 있었다.이번 과제를 하면서 모르는게 많았고, 객체지향에 대해서 많이 배우는 계기가 되었으며 앞으로 어떤 방향으로 프로그래밍을 설계해야하는지 조금은 느낌이 오는거 같다. 이 과정까지 오는데는 튜터님과 팀원들의 정말 많은 도움으로 완성할 수 있게된거 같다.
눈물 업시 볼 수 없네요