1. 객체, 설계

  • 프로그래밍에서는 이론 보다 실무가 더 빠르게 탄생하고, 중요하다

  • 모듈이 크기에 상관 없는, 프로그램을 구성하는 임의의 요소라 할 때, 중요한 것은 - by 로버트 마틴

    1. 실행 중 제대로 동작
    2. 변경에 용이
    3. 읽는 사람이 이해하기 쉬워야 함
  • 이해 가능한 코드란 그 동작이 우리의 예상(직관)에서 크게 벗어나지 않은 코드

  • A 클래스가 B 클래스의 내부에 대해 더 많이 알면 알 수록 변경하기 어려워진다.

    • 객체 사이의 의존성(dependency)
    • 의존성이라는 말 속에는 어떤 객체가 변경될 때 그 객체에게 의존하는 다른 객체도 함께 변경될 수 있다는 사실이 내포되어 있음
    • 최소한의 의존서만 유지하고 불필요한 의존성을 제거해야 함.
  • 의존성이 과한 경우를 결합도(coupling) 이 높다고 한다.

  • 캡슐화: 객체 내부의 세부적인 사항을 감추는 것

    • 캡슐화의 목적은 변경하기 쉬운 객체를 만드는 것
  • 밀접하게 연관된 작업만을 수행하고 연관성 없는 작업은 다른 객체에게 위임하는 객체를 응집도(cohesion) 가 높다고 한다.

  • 프로세스(Process)와 데이터(Data)를 별도의 모듈에 위치시키는 방식을 절차적(Procedural) 프로그래밍

    • 우리의 직관에 벗어남, 개발자들의 의사소통이 어려워짐

    • 수동적인 객체가 많이 생겨남

    • 데이터의 변경으로 인한 영향을 지역적으로 고립시키기 어려움

    • 프로세스가 필요한 모든 데이터에 의존해야 한다는 근본적인 문제가 발생하여 변경에 취약

    • Theater의 enter 메서드가 프로세스, 나머지는 데이터

    • 책임이 Theater에 집중

    • 데이터와 데이터를 사용하는 프로세스가 별도의 객체 안에 위치

  • 데이터와 프로세스가 동일한 모듈에 위치하도록 프로그래밍 하는 방식 => OOP

    • 데이터를 사용하는 프로세스가 데이터를 소유하고 있는 Audience과 TickerSeller 내부로 옮겨짐
    • 필요한 책임이 분산됨
    • 각 객체는 자신을 스스로 책임진다.
    • 객체지향 어플리케이션은 스스로 책임을 수행하는 자율적인 객체들의 공동체를 구성한다.
    • 데이터와 데이터를 사용하는 프로세스가 동일한 객체 안에 위치
  • 책임의 이동(shift of responsibility)

    • 책임기능을 가리키는 객체지향 세계의 용어
  • 의인화(anthropomorphism): 현실에서 수동적인 존재라고 하더라도 객체지향 세계에서 능동적이고 자율적인 존재로 객체를 설계하는 원칙

  • 변경을 수용할 수 있는 설계가 중요한 이유

    • 요구사항은 자주 변경 => 코드 수정 초래 => 버그 발생 가능성 높임
      • 버그의 가장 큰 문제점은 코드 수정 의지를 꺽는다는 점

절차지향 코드

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
class Invitation {
    lateinit var _when: LocalDateTime
}

class Ticket {
    var fee: Int = 0
}

class Bag(val invitation: Invitation?, var amount: Int) {
    var ticket: Ticket? = Ticket()

    fun hasInvitation() = invitation != null
    fun hasTicket() = ticket != null

    fun minusAmount(amount: Int) {
        this.amount -= amount
    }

    fun plusAmount(amount: Int) {
        this.amount += amount
    }
}

class Audience(val bag: Bag) {

}

class TicketOffice(private var amount: Int, vararg tickets: Ticket) {
    private val tickets: MutableList<Ticket> = mutableListOf()
    init {
        this.tickets.addAll(tickets.toList())
    }

    val ticket: Ticket
        get() = tickets.removeAt(0)

    fun minusAmount(amount: Int) {
        this.amount -= amount
    }

    fun plusAmount(amount: Int) {
        this.amount += amount
    }
}

class TicketSeller(val ticketOffice: TicketOffice) {

}

class Theater(val ticketSeller: TicketSeller) {

    fun enter(audience: Audience) {
        if (audience.bag.hasInvitation()) {
            val ticket = ticketSeller.ticketOffice.ticket
            audience.bag.ticket = ticket
        } else {
            val ticket = ticketSeller.ticketOffice.ticket
            audience.bag.minusAmount(ticket.fee)
            ticketSeller.ticketOffice.plusAmount(ticket.fee)
            audience.bag.ticket = ticket
        }
    }
}

객체지향 코드

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
class Invitation {
    lateinit var _when: LocalDateTime
}

class Ticket {
    var fee: Int = 0
}

class Bag(val invitation: Invitation?, var amount: Int) {
    private var ticket: Ticket? = Ticket()

    private fun hasInvitation() = invitation != null
    private fun hasTicket() = ticket != null

    private fun minusAmount(amount: Int) {
        this.amount -= amount
    }

    private fun plusAmount(amount: Int) {
        this.amount += amount
    }

    fun hold(ticket: Ticket): Int {
        if (hasInvitation()) {
            this.ticket = ticket
            return 0
        } else {
            this.ticket = ticket
            minusAmount(ticket.fee)
            return ticket.fee
        }
    }
}


class Audience(private val bag: Bag) {
    fun buy(ticket: Ticket): Int {
        return bag.hold(ticket)
    }
}


class TicketOffice(private var amount: Int, vararg tickets: Ticket) {
    private val tickets: MutableList<Ticket> = mutableListOf()

    init {
        this.tickets.addAll(tickets.toList())
    }

    private val ticket: Ticket
        get() = tickets.removeAt(0)

    private fun minusAmount(amount: Int) {
        this.amount -= amount
    }

    private fun plusAmount(amount: Int) {
        this.amount += amount
    }

    fun sellTicketTo(audience: Audience) {
        plusAmount(audience.buy(ticket))
    }
}

class TicketSeller(private val ticketOffice: TicketOffice) {
    fun sellTo(audience: Audience) {
        ticketOffice.sellTicketTo(audience)
    }
}

class Theater(private val ticketSeller: TicketSeller) {
    fun enter(audience: Audience) {
        ticketSeller.sellTo(audience)
    }
}

Reference