1장: 객체, 설계
프로그래밍 이론
이론보다 실무가 먼저
어떤 분야든 초기 단계에서는 아무것도 없는 상태에서 이론을 정립하기보단 실무를 관찰한 결과를 바탕으로 이론을 정립하는 것이 최선이다.
추상적인 개념과 이론은 훌륭한 코드를 작성하는 데 필요한 도구일 뿐 프로그래밍을 통해 개념과 이론을 배우는 것이 개념과 이론을 통해 프로그래밍을 배우는 것보다 더 좋다.
티켓 판매 애플리케이션
아래 요구사항에 맞게 프로그램을 객체지향적으로 작성하도록 한다.
극장에는 이벤트 당첨자와 표를 구매하는 관람객이 입장할 수 있다.
관람객
이벤트에 당첨되었다면 초대장을 티켓으로 교환해야만 입장 가능하다.
이벤트에 당첨되지 않았다면 티켓을 구매해야만 입장 가능하다.
판매원
매표소에서 초대장을 티켓으로 교환해주거나 티켓을 판매한다.
자신이 일하는 매표소를 알고 있어야 한다.
객체로 표현하기
이벤트 당첨자가 가지는 초대장 클래스이다.
초대장을 통해 교환하거나 구매가 가능한 티켓 클래스이다.
현금, 초대장, 티켓 등을 보관할 수 있는 가방 클래스이다.
가방을 갖는 관람객 클래스이다.
매표소를 구현하는 클래스이다. 판매하거나 교환해줄 티켓의 목록과 판매 금액을 포함한다.
매표소에서 초대장을 티켓으로 교환하거나 티켓을 판매하는 판매원 클래스이다. 자신이 일하는 매표소를 알고 있어야 한다.
극장 클래스에서는 관람객을 입장시키는 역할을 한다.
설계 개선하기
소프트웨어 모듈의 필수 기능
정상적으로 동작해야 한다.
변경을 위해 존재해야 하며 변경이 어려운 모듈은 변경이 용이하도록 개선해야 한다.
코드를 읽는 사람과 의사소통 가능해야 한다.
애플리케이션의 기능을 구현하는 데에 필요한 최소한의 의존성만 유지하고 불필요한 의존성을 제거해야 한다. 즉, 결합도를 낮춰 변경이 용이한 설계를 만들어야 한다.
기존 객체의 경우 관람객과 판매원이 소극장인 Theater 클래스에 의해 동작하는 수동적인 존재로 표현된다. 심지어 관람객의 가방을 직접 확인해 돈을 계산해 다시 넣어두므로, 결합도가 강하다.
또한 Audience, TicketSeller 클래스를 변경하면 Theater에도 같이 변경해주어야 한다.
이를 아래와 같이 TicketSeller 클래스가 직접 티켓 판매 역할을 담당하도록 하고, Audience 클래스가 직접 티켓 구매 역할을 담당하도록 하여 해결할 수 있다.
객체 내부의 세부적인 사항을 캡슐화를 통해 감추어 변경하기 쉬운 객체를 만든다.
이를 통해 Audience와 TicketSeller는 자신이 가진 소지품을 스스로 관리하므로 이해하기 용이하다.
밀접하게 연관된 작업만을 수행하고 연관성 없는 작업은 다른 객체에게 위임하는 객체를 응집도(cohesion)가 높다고 한다. 객체 스스로 자신의 데이터를 처리하는 자율적인 존재여야 한다.
절차지향 vs 객체지향
절차지향적인 방식
기존의 설계는 모든 처리가 하나의 클래스 내에 위치하고 나머지 클래스는 단지 데이터의 역할만 수행하는 절차지향적인 방식이었다.
하지만 이는 인간의 직관적인 생각과 반대되며 변경하기 어려운 코드를 양산한다.
객체지향적 방식
자신의 데이터는 스스로 처리하도록 동일한 클래스 내부에 데이터와 이를 제어하는 프로세스를 위치하도록 한다.
즉, 캡슐화를 이용해 의존성을 적절히 관리하여 객체 사이의 결합도를 낮추어 변화에 용이하게 만든다.
책임을 개별 객체로 이동시켜 스스로 수행하도록 한다. 적절한 객체에 적절한 책임을 할당하면 이해하기 쉬운 구조와 가독성있는 코드를 만들 수 있다.
책임 분리하기
기존 Audience 클래스는 Bag 객체의 메서드들을 호출해 초대권이 있는지 확인하고 티켓으로 교환받거나 구매하였다. 이 로직을 bag의 hold 메서드 내부로 캡슐화하여 Bag 클래스에 책임을 주었다.
트레이드오프
동일한 기능을 한 가지 이상의 방법으로 설계할 수 있기 때문에 결국 설계는 트레이드오프의 산물이다. 어떤 경우에도 모든 사람들을 만족시킬 수 있는 설계를 만들 수는 없다.
TicketSeller는 TicketOffice 클래스의 티켓을 꺼내 판매하지만 이는 TicketOffice의 자율권을 침해한다. 따라서 sellTicketTo 메서드를 추가하여 직접 관람객에게 티켓을 팔도록 한다.
하지만 위와 같은 변경은 TicketOffice와 Audience 클래스 간의 의존성을 초래하였다. TicketOffice의 자율성과 Audience에 대한 결합도 제거 중 더 중요한 것을 선택해야만 한다.
의인화
현실에서는 수동적인 존재라고 하더라도 객체지향의 세계에서는 모든 것을 능동적이고 자율적인 존재로 설계하는 원칙을 의미한다.
설계의 필요성
좋은 설계란? 오늘 요구하는 기능을 온전히 수행하면서 내일의 변경을 매끄럽게 수용 할 수 있는 설계다.
요구사항은 항상 변경되기 때문에 개발을 시작하는 시점에 모든 요구사항을 만족시키는 것은 불가능에 가깝다.
코드 수정으로 인해 버그가 발생하지 않도록 하려면 쉽게 이해 가능한 코드와 변경을 수용할 수 있는 설계가 중요하다.
훌륭한 객체지향 설계란? 객체 사이의 의존성을 적절하게 (강결합되지 않도록) 관리하는 설계다.
Last updated