객체지향설계

코드스피츠 1강 오브젝트 1회차 (2)

iOS_Assin 2019. 10. 4. 06:26

책 오브젝트를 기반으로 하는 코드스피츠 강의 오브젝트 - 1회차 (2) 를 정리한 내용입니다.

 

1.코드스피츠 1강 오브젝트 1회차 (1)

2.코드스피츠 1강 오브젝트 1회차 (2)

3.코드스피츠 1강 오브젝트 2회차 

4.코드스피츠 1강 오브젝트 3회차 

5. 코드스피츠 1강 오브젝트 4회차 

6. 코드스피츠 1강 오브젝트 5회차

7. 코드스피츠 1강 오브젝트 6회차

 

들어가기 앞서 오브젝트에서 말하는 책임과 SRP 의 책임은 다릅니다.

여기에서 먼저 확인해 주세요!

Value & Identifier

특정 유형의 데이터를 값으로 볼것인가? 객체로 볼것인가?

 

필드 값으로 객체의 동등성을 평가한다면 더이상 객체가 아니다.

객체는 식별자를 통해서만 객체의 고유성을 평가해야만 한다.

 

협력자 객체를 받아왔다면 이 객체가 누군지인지 알 수 있는 방법은 식별자로 판별하는 방법밖에 없다.

 

함수형 프로그래밍에서는 불변성과 순수함수를 위해서 참조를 지양하고 값을 지향하고 있다.  

Polymorphism

Substitution        : 대체가능성

Internal identity  : 내적동질성

 

대체가능성

 

var worker: Runnable = Worker()

Worker 라는 객체는 Runnable Type 대체할 수 있어야 한다.

 

protocol Runnable {
    func run()
}

class Worker: Runnable {
    func run() {
        print("working")
    }
}

class HardWorker: Worker {
    
    override func run() {
          print("Hardworking")
      }
}

var worker: Runnable = Worker()
print(worker.run())
worker = HardWorker()
print(worker.run())

 

실행결과

working
()
Hardworking
()

 

 

Javascript 에서 대체 가능성을 실현하는 테크닉

 

동적 디스패치: Pointer of Pointer 로 참조해 나가는 과정

동적 바인딩: 동적으로 바인딩 시키는 행위 

 

정적 바인딩 vs 동적 바인딩에 자세한 내용은 여기에서 확인할 수 있습니다.

 

위 링크에서의 동적바인딩 정의

실행 파일을 만들 때 바인딩 되지 않고 보류 상태 둔다.

점프할 메모리 번지를 저장하기 위한 메모리 공간(4 byte)을 가지고 있다가 런타임에 결정.

=> 단점 : 타입 체킹으로 인한 수행 속도 저하 / 메모리 공간 낭비

 

내적동질성

최초 생성한 객체에 함수 포인터를 유지하는 것

 

var worker: Worker = HardWorker()

 

HardWorker 로 만들면 3개의 인스턴스가 생성된다.

  • HardWorker
  • Worker
  • Runnable

 

worker.run() 를 호출하면 Worker의 run() 아닌 HardWorker의 run() 이 호출된다.

 

Object

객체의 조건을 꼽는 두 가지

 

Encapsulation of Functionality (기능의 캡슐화)

Maintenance of State (상태를 관리)

 

Isolation

우리의 궁극적인 목표는 Isolation (격리) 이다.

 

격리를 구분하는 방법

어떤 파일을 수정하기 위해 다른 파일을 열지 않았으면 격리된 것인다. 

 

 

Coding!

자세한 내용은 코드에 주석으로 추가하였습니다. 전체코드

 

 

중요하다고 생각되는 Class에 대해서만 설명합니다. [TicketSeller, Audience]

TicketSeller

TicketSeller는 TicketOffice 의 변화율과 TicketSeller 의 getTicket 변화율이 다르기 때문에 분리된 클래스이다.

새로운 Ticket 의 파는 정책이 변경되었을 때 TicketOffice의 파일을 열지 않아도 된다.  (격리되었다)

즉, 회귀테스트가 일어나지 않는다.

 

Audience 가 구상클래스로 다양한 Audience 로 분리되었을 때의 여파가 TicketOffice 에게 전파되면 

TicketOffice 가 망가지고 TicketOffice를 바라보고 있는 Theater 도 망가지게 된다.

 

TicketOffice와 Audience 사이에서 Ticket 의 파는 정책 변경에 대한 여파를 TicketSeller가 받아주는 역할을 한다.

 

Audience

TicketSeller 와 Transaction 하기 위해서는 아래 Method 들이 오픈되어야 한다.

TransactionCondition 라는 protocol 로 책임을 분리할 수 있다.

protocol TransactionCondition {
    func hasAmount(amount: Long) -> Bool
    func minusAmount(amount: Long) -> Bool
    func getInvitation() -> Invitation
    func remoteInvitation()
}

 

마무리 

절대로 이런 수준의 코드를 처음부터 짤 수가 없다는 것을 명심해야 한다.

 

객체지향 설계를 기반으로 코드를 짜기 위해선 아래와 같이 다양한 의견이 있다.

 

코드스피츠

먼저 Client 의 코드(시나리오를 작성한 후)를 작성해야만 Class 의 책임을 알 수 있다.

 

오브젝트

데이터 중심보다는 "협력이라는 문맥 안에서 책임을 결정하라" 

 

객체지향 설계을 이제 막 진입한 개발자는 코드스피츠에 내용이 맞는 것 같고

어느정도 객체지향 설계를 해봤다 라는 개발자 수준엣는 오브젝트가 말하는 내용이 맞는 것 같다.

 

용어정리

의인화: 능동적이고 자율적인 존재로 소프트웨어 객체를 설계하는 원칙

 

참조: 

https://yubylab.tistory.com/entry/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-Prototype-Chain-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0

https://secretroute.tistory.com/entry/140819

https://www.youtube.com/watch?v=navJTjZlUGk