객체, 설계
객체지향 설계의 중점은 변경이 용이한 코드를 작성하는 것이다. 변경이 용이한 코드를 작성하기 위해선 결합도를 낮추고 각 오브젝트에게 책임을 부여 해야 한다.
가령 극장에서 입장을 위해 표를 구입해야하는 프로그램을 만든다고 가정하자. 다음과 같이 코드를 작성할 수 있다.
1 2 3 4 5 6 7 public class Ticket { private Long fee; public Long getFee () { return fee; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class Bag { private Ticket ticket; private Long amount; public boolean hasTicket () { return ticket != null ; } public void setTicket (Ticket ticket) { this .ticket = ticket; } public void minusAmount (Long amount) { this .amount -= amount; } public void plusAmount (Long amount) { this .amount += amount; } }
1 2 3 4 5 6 7 8 9 10 11 public class Audience { private Bag bag; public void setBag (Bag bag) { this .bag = bag; } public Bag getBag () { return bag; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class TicketOffice { private Long amount; private List<Ticket> ticketList = new LinkedList <>(); public TicketOffice (Long amount, Ticket ... tickets) { this .amount = amount; this .ticketList.addAll(Arrays.asList(tickets)); } public Ticket getTicket () { return ticketList.remove(0 ); } public void minusAmount (Long amount) { this .amount -= amount; } public void plusAmount (Long amount) { this .amount += amount; } }
1 2 3 4 5 6 7 8 9 10 11 public class TicketSeller { private TicketOffice ticketOffice; public void setTicketOffice (TicketOffice ticketOffice) { this .ticketOffice = ticketOffice; } public TicketOffice getTicketOffice () { return ticketOffice; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class Theater { private TicketSeller ticketSeller; public Theater (TicketSeller ticketSeller) { this .ticketSeller = ticketSeller; } public void enter (Audience audience) { if (!audience.getBag().hasTicket()) { Ticket ticket = ticketSeller.getTicketOffice().getTicket(); audience.getBag().minusAmount(ticket.getFee()); audience.getBag().setTicket(ticket); ticketSeller.getTicketOffice().plusAmount(ticket.getFee()); } } }
위 코드는 필요한 요구사항인 관람객의 가방에 티켓이 없다면 구입한다는 내용을 충족한다. 하지만 문제가 있다. 티켓을 구매하고 판매하는 모든 책임 이 Theater 클래스의 enter 메소드에만 있다는 것이다. 이런 코드는 변경을 어렵게 만든다.
위의 코드는 다음과 같이 수정할 수 있다.
1 2 3 4 5 6 7 public class Ticket { private Long fee; public Long getFee () { return fee; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class Bag { private Ticket ticket; private Long amount; public boolean hasTicket () { return ticket != null ; } public void setTicket (Ticket ticket) { this .ticket = ticket; } public void minusAmount (Long amount) { this .amount -= amount; } public void plusAmount (Long amount) { this .amount += amount; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class Audience { private Bag bag; public void setBag (Bag bag) { this .bag = bag; } public Long buyTicket (Ticket ticket) { if (bag.hasTicket()) { return 0L ; } else { this .bag.minusAmount(ticket.getFee()); this .bag.setTicket(ticket); return ticket.getFee(); } } }
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 public class TicketOffice { private Long amount; private List<Ticket> ticketList = new LinkedList <>(); public TicketOffice (Long amount, Ticket ... tickets) { this .amount = amount; this .ticketList.addAll(Arrays.asList(tickets)); } private Ticket getTicket () { return ticketList.remove(0 ); } private void minusAmount (Long amount) { this .amount -= amount; } private void plusAmount (Long amount) { this .amount += amount; } public void sellTicketTo (Audience audience) { this .plusAmount(audience.buyTicket(this .getTicket())); } }
1 2 3 4 5 6 7 8 9 10 11 public class TicketSeller { private TicketOffice ticketOffice; public void setTicketOffice (TicketOffice ticketOffice) { this .ticketOffice = ticketOffice; } public void sellTo (Audience audience) { ticketOffice.sellTicketTo(audience); } }
1 2 3 4 5 6 7 8 9 10 11 public class Theater { private TicketSeller ticketSeller; public Theater (TicketSeller ticketSeller) { this .ticketSeller = ticketSeller; } public void enter (Audience audience) { ticketSeller.sellTo(audience); } }
위 코드는 각각의 행동에 대한 책임을 각 클래스로 위임했다. 기존의 Theater 클래스의 enter 메소드는 관람객이 티켓을 가지고 있는지를 확인해 없다면 티켓을 구매하고 있다면 들여보내는 모든 행동을 관리했다. 하지만 변경 후에는 입장을 담당하는 책임만을 부여받는다. 그렇다면 다른 로직들은 어디로 위임이 되었을까?
관람객을 매표소로 이동시키는 로직은 TicketSeller에게 위임되었다. 티켓을 판매하는 로직은 TicketOffice에게 위임되었다. 돈을 지출하고 티켓을 소유하는 로직은 Audience에 위임되었다.
이렇게 바꿈으로써 각각의 오브젝트는 자신만이 담당하는 책임 이 적절하게 부여되었다. 하지만 Audience와 TicketOffice간의 결합도가 생성되는 단점도 있었다.