객체지향 설계란 올바른 객체에게 올바른 책임을 할당하면서 낮은 결합도와 높은 응집도를 가진 구조를 창조하는 활동이다.

객체지향의 두가지 관점

  1. 객체지향 설계의 핵심은 책임이다.
  2. 책임을 할당하는 작업이 응집도와 결합도 같은 설계 품질과 깊이 연관돼 있다는 것이다.

불변하는 설계는 없다. 설계는 항상 변경을 위해 존재하기 때문에 합리적인 비용안에서 변경을 수용할 수 있는 구조를 만드는 것이 훌륭한 설계라고 할 수 있다. (응집도가 높고 결합도가 낮은)

객체를 데이터 중심적으로 설계하면 변경에 취약하기 때문에 데이터가 아닌 객체의 책임에 초점을 두고 설계해야 한다.

데이터 중심의 설계

Untitled

// 영화 예매 절차를 구현하는 클래스

public class ReservationAgency {
    public Reservation reserve(Screening screening, Customer customer,
                               int audienceCount) {
        Movie movie = screening.getMovie();

        boolean discountable = false;
        for(DiscountCondition condition : movie.getDiscountConditions()) {
            if (condition.getType() == DiscountConditionType.PERIOD) {
                discountable = screening.getWhenScreened().getDayOfWeek().equals(condition.getDayOfWeek()) &&
                        condition.getStartTime().compareTo(screening.getWhenScreened().toLocalTime()) <= 0 &&
                        condition.getEndTime().compareTo(screening.getWhenScreened().toLocalTime()) >= 0;
            } else {
                discountable = condition.getSequence() == screening.getSequence();
            }

            if (discountable) {
                break;
            }
        }

        Money fee;
        if (discountable) {
            Money discountAmount = Money.ZERO;
            switch(movie.getMovieType()) {
                case AMOUNT_DISCOUNT:
                    discountAmount = movie.getDiscountAmount();
                    break;
                case PERCENT_DISCOUNT:
                    discountAmount = movie.getFee().times(movie.getDiscountPercent());
                    break;
                case NONE_DISCOUNT:
                    discountAmount = Money.ZERO;
                    break;
            }

            fee = movie.getFee().minus(discountAmount).times(audienceCount);
        } else {
            fee = movie.getFee().times(audienceCount);
        }

        return new Reservation(customer, screening, fee, audienceCount);
    }
}

데이터 중심의 영화 예매 시스템의 문제점

1. 캡슐화 위반

public class Movie {
	private Money fee;
	
	public Money getFee() {
		return fee;
	}
	
	public void setFee(Money fee) {
		this.fee = fee;
	}
}

데이터 중심의 설계는 무분별한 get,set 메서드 생성을 유발하고 (추측에 의한 설계) 캡슐화의 원칙을 위반하는 변경에 취약한 설계를 얻게 된다.

2. 높은 결합도

객체 내부의 구현이 객체의 인터페이스 부분에서 드러난다는 것은 클라이언트가 구현에 강하게 결합되어 있다는 것이다. 그래서 내부 구현이 변경되면 이 인터페이스에 의존하는 모든 클라이언트가 변경 되어야 한다.