{"componentChunkName":"component---src-containers-post-index-tsx","path":"/backend/object/chapter7/객체_분해/","result":{"pageContext":{"next":{"id":"1d60c7d6-474c-5c82-af8d-2050f2560f1c","html":"<blockquote>\n<p>애플리케이션은 클래스로 구성되지만 메시지를 통해 정의된다는 사실을 기억하라.</p>\n</blockquote>\n<h2 id=\"-61-협력과-메시지\" style=\"position:relative;\"><a href=\"#-61-%ED%98%91%EB%A0%A5%EA%B3%BC-%EB%A9%94%EC%8B%9C%EC%A7%80\" aria-label=\" 61 협력과 메시지 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 6.1 협력과 메시지</h2>\n<h3 id=\"-611-클라이언트-서버-모델\" style=\"position:relative;\"><a href=\"#-611-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EC%84%9C%EB%B2%84-%EB%AA%A8%EB%8D%B8\" aria-label=\" 611 클라이언트 서버 모델 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.1.1 클라이언트-서버 모델</h3>\n<p>메시지는 객체 사이의 협력을 가능하게 하는 매개체다. 두 객체 사이의 협력 관계를 설명하기 위해 사용하는 전통적인 메타포는 <strong>클라이언트-서버 모델</strong> 이다.</p>\n<ul>\n<li><code>Movie</code>와 같이 객체는 협력에 참여하는 동안 클라이언트와 서버의 역할을 동시에 수행하는 것이 일반적</li>\n<li>협력의 관점에서 객체는 두 가지 종류의 메시지 집합으로 구성\n<ul>\n<li>객체가 수신하는 메시지의 집합</li>\n<li>외부의 객체에게 전송하는 메시지의 집합</li>\n</ul>\n</li>\n<li>두 객체 사이의 협력을 가능하게 해주는 매개체가 메시지</li>\n</ul>\n<h3 id=\"-612-메시지와-메시지-전송\" style=\"position:relative;\"><a href=\"#-612-%EB%A9%94%EC%8B%9C%EC%A7%80%EC%99%80-%EB%A9%94%EC%8B%9C%EC%A7%80-%EC%A0%84%EC%86%A1\" aria-label=\" 612 메시지와 메시지 전송 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.1.2 메시지와 메시지 전송</h3>\n<ul>\n<li>메시지는 객체들이 협력하기 위해 사용할 수 있는 유일한 의사소통 수단</li>\n<li><strong>메시지 전송(메시지 패싱)</strong>: 한 객체가 다른 객체에게 도움을 요청하는 것</li>\n<li><strong>메시지 전송자(클라이언트)</strong>: 메시지를 전송하는 객체</li>\n<li><strong>메시지 수신자(서버)</strong>: 메시지를 수신하는 객체</li>\n<li>메시지는 <strong>오퍼레이션명</strong>과 <strong>인자</strong>로 구성\n<ul>\n<li>메시지 전송은 여기에 <strong>메시지 수신자</strong>를 추가한 것</li>\n</ul>\n</li>\n</ul>\n<h3 id=\"-613-메시지와-메서드\" style=\"position:relative;\"><a href=\"#-613-%EB%A9%94%EC%8B%9C%EC%A7%80%EC%99%80-%EB%A9%94%EC%84%9C%EB%93%9C\" aria-label=\" 613 메시지와 메서드 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.1.3 메시지와 메서드</h3>\n<ul>\n<li>메시지를 수신했을 때 실제로 실행되는 함수 또는 프로시저를 <strong>메서드</strong>라고 부른다.\n<ul>\n<li>동일한 메시지를 전송하더라도 객체의 타입에 따라 실행되는 메서드가 달라질 수 있다.</li>\n<li>객체는 메시지와 메서드라는 두 가지 서로 다른 개념을 실행 시점에 연결해야 하기 때문에 컴파일 시점과 실행 시점의 의미가 달라질 수 있다.</li>\n</ul>\n</li>\n<li>메시지와 메서드의 구분은 메시지 전송자와 메시지 수신자가 느슨하게 결합될 수 있게 한다.</li>\n<li>실행 시점에 메시지와 메서드를 바인딩하는 메커니즘은 두 객체 사이의 결합도를 낮춤으로써 유연하고 확장 가능한 코드를 작성할 수 있게 만든다.</li>\n</ul>\n<h3 id=\"-614-퍼블릭-인터페이스와-오퍼레이션\" style=\"position:relative;\"><a href=\"#-614-%ED%8D%BC%EB%B8%94%EB%A6%AD-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EC%99%80-%EC%98%A4%ED%8D%BC%EB%A0%88%EC%9D%B4%EC%85%98\" aria-label=\" 614 퍼블릭 인터페이스와 오퍼레이션 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.1.4 퍼블릭 인터페이스와 오퍼레이션</h3>\n<ul>\n<li><strong>퍼블릭 인터페이스</strong>: 객체가 의사소통을 위해 외부에 공개하는 메시지의 집합</li>\n<li><strong>오퍼레이션</strong>: 프로그래밍 언어의 관점에서 퍼블릭 인터페이스에 포함된 메시지\n<ul>\n<li>수행 가능한 어떤 행동에 대한 추상화</li>\n<li>UML의 관점에서 오퍼레이션이란 실행하기 위해 객체가 호출될 수 있는 변환이나 정의에 관한 명세</li>\n</ul>\n</li>\n</ul>\n<h3 id=\"-615-시그니처\" style=\"position:relative;\"><a href=\"#-615-%EC%8B%9C%EA%B7%B8%EB%8B%88%EC%B2%98\" aria-label=\" 615 시그니처 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.1.5 시그니처</h3>\n<ul>\n<li><strong>시그니처</strong>: 오퍼레이션(또는 메서드)의 이름과 파라미터 목록을 합친 것\n<ul>\n<li>오퍼레이션은 실행 코드 없이 시그니처만을 정의한 것</li>\n<li>메서드는 이 시그니처에 구현을 더한 것</li>\n</ul>\n</li>\n</ul>\n<h2 id=\"-62-인터페이스와-설계-품질\" style=\"position:relative;\"><a href=\"#-62-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EC%99%80-%EC%84%A4%EA%B3%84-%ED%92%88%EC%A7%88\" aria-label=\" 62 인터페이스와 설계 품질 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 6.2 인터페이스와 설계 품질</h2>\n<p>좋은 인터페이스는 <strong>최소한의 인터페이스</strong>와 <strong>추상적인 인터페이스</strong>라는 조건을 만족해야 한다.</p>\n<p>퍼블릭 인터페이스의 품질에 영향을 미치는 원칙과 기법</p>\n<ul>\n<li>디미터 법칙</li>\n<li>묻지 말고 시켜라</li>\n<li>의도를 드러내는 인터페이스</li>\n<li>명령-쿼리 분리</li>\n</ul>\n<h3 id=\"-621-디미터-법칙\" style=\"position:relative;\"><a href=\"#-621-%EB%94%94%EB%AF%B8%ED%84%B0-%EB%B2%95%EC%B9%99\" aria-label=\" 621 디미터 법칙 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.2.1 디미터 법칙</h3>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public class ReservationAgency {\n\n    public Reservation reserve(Screening screening, Customer customer, int audienceCount) {\n        Movie movie = screening.getMovie();\n\n        boolean discountable = false;\n        for (DiscountCondition condition : movie.getDiscountConditions()) {\n            if (condition.getType() == DiscountConditionType.PERIOD) {\n                discountable = screening.getWhenScreened().getDayOfWeek().equals(condition.getDayOfWeek()) &amp;&amp;\n                        !condition.getStartTime().isAfter(screening.getWhenScreened().toLocalTime()) &amp;&amp;\n                        !condition.getEndTime().isBefore(screening.getWhenScreened().toLocalTime());\n            } else {\n                discountable = condition.getSequence() == screening.getSequence();\n            }\n\n            if (discountable) {\n                break;\n            }\n        }\n\n        Money fee;\n        if (discountable) {\n            Money discountAmount = Money.ZERO;\n            switch (movie.getMovieType()) {\n                case AMOUNT_DISCOUNT -&gt; discountAmount = movie.getDiscountAmount();\n                case PERCENT_DISCOUNT -&gt; discountAmount = movie.getFee().times(movie.getDiscountPercent());\n                case NONE_DISCOUNT -&gt; discountAmount = Money.ZERO;\n            }\n\n            fee = movie.getFee().minus(discountAmount);\n        } else {\n            fee = movie.getFee();\n        }\n\n        return new Reservation(customer, screening, fee, audienceCount);\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>위 코드의 가장 큰 단점은 <code>ReservationAgency</code>와 인자로 전달된 <code>Screening</code> 사이의 결합도가 너무 높은 것이다.</li>\n<li>이처럼 협력하는 객체의 내부 구조에 대한 결합으로 인해 발생하는 설계 문제를 해결하기 위해 제안된 원칙이 <strong>디미터 법칙</strong></li>\n</ul>\n<blockquote>\n<p>낯선 자에게 말하지 말라</p>\n<p>오직 인접한 이웃하고만 말하라</p>\n</blockquote>\n<p>디미터 법칙을 따르기 위해서는 클래스가 특정한 조건을 만족하는 대상에게만 메시지를 전송하도록 프로그래밍</p>\n<ul>\n<li>모든 클래스 C와 C에 구현된 모든 메서드 M에 대해서, M이 메시지를 전송할 수 있는 모든 객체는 아래 클래스의 인스턴스여야 한다.\n<ul>\n<li>M의 인자로 전달된 클래스(C 자체를 포함)</li>\n<li>C의 인스턴스 변수의 클래스</li>\n</ul>\n</li>\n<li>M에 의해 생성된 객체나 M이 호출하는 메서드에 의해 생성된 객체, 전역 변수로 선언된 객체는 모두 M의 인자로 간주</li>\n</ul>\n<p>즉, 클래스 내부의 메서드가 아래 조건을 만족하는 인스턴스에만 메시지를 전송하도록 해야 한다.</p>\n<ul>\n<li>this 객체</li>\n<li>메서드의 매개변수</li>\n<li>this의 속성</li>\n<li>this의 속성인 컬렉션의 요소</li>\n<li>메서드 내에서 생성된 지역 객체</li>\n</ul>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public class ReservationAgency {\n\n    public Reservation reserve(Screening screening, Customer customer, int audienceCount) {\n        Money fee = screening.calculateFee(audienceCount);\n        return new Reservation(customer, screening, fee, audienceCount);\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>디미터 법칙을 따른 결과 결합도가 개선되었다.</li>\n<li>디미터 법칙을 따르면 <strong>부끄럼타는 코드(shy code)</strong> 를 작성할 수 있다.\n<ul>\n<li>불필요한 어떤 것도 다른 객체에게 보여주지 않음</li>\n<li>다른 객체의 구현에 의존하지 않는 코드</li>\n</ul>\n</li>\n</ul>\n<p><code>screening.getMovie().getDiscountConditions();</code></p>\n<ul>\n<li>위 코드는 디미터 법칙을 위반한 코드다.</li>\n<li>메시지 전송자가 수신자의 내부 구조에 대해 물어보고 반환받은 요소에 대해 연쇄적으로 메시지를 전송</li>\n<li><strong>기차 충돌(train wreck)</strong>\n<ul>\n<li>여러 대의 기차가 한 줄로 늘어서 충돌한 것처럼 보이기 때문</li>\n<li>클래스의 내부 구현이 외부로 노출됐을 때 나타나는 전형적인 형태</li>\n</ul>\n</li>\n<li>디미터 법칙을 적용한 코드는 <code>screening.calculateFee(audienceCount);</code></li>\n</ul>\n<p>무비판적으로 디미터 법칙을 수용하면 퍼블릭 인터페이스 관점에서 객체의 응집도가 낮아질 수도 있다.</p>\n<h3 id=\"-622-묻지-말고-시켜라\" style=\"position:relative;\"><a href=\"#-622-%EB%AC%BB%EC%A7%80-%EB%A7%90%EA%B3%A0-%EC%8B%9C%EC%BC%9C%EB%9D%BC\" aria-label=\" 622 묻지 말고 시켜라 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.2.2 묻지 말고 시켜라</h3>\n<p>메시지 전송자는 메시지 수신자의 상태를 기반으로 결정을 내린 후 메시지 수신자의 상태를 바꿔서는 안된다.</p>\n<ul>\n<li>묻지 말고 시켜라 원칙을 따르면 밀접하게 연관된 정보와 행동을 함께 가지는 객체를 만들 수 있다.</li>\n<li>상태를 묻는 오퍼레이션을 행동을 요청하는 오퍼레이션으로 대체함으로써 인터페이스를 향상시켜라</li>\n<li>하지만 단순하게 객체에게 묻지 않고 시킨다고 해서 모든 문제가 해결되는 것은 아니다.\n<ul>\n<li>훌륭한 인터페이스를 수확하기 위해서는 객체가 어떻게 작업을 수행하는지를 노출해서는 안 된다.</li>\n</ul>\n</li>\n</ul>\n<h3 id=\"-623-의도를-드러내는-인터페이스\" style=\"position:relative;\"><a href=\"#-623-%EC%9D%98%EB%8F%84%EB%A5%BC-%EB%93%9C%EB%9F%AC%EB%82%B4%EB%8A%94-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4\" aria-label=\" 623 의도를 드러내는 인터페이스 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.2.3 의도를 드러내는 인터페이스</h3>\n<p>메서드를 명명하는 방법</p>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public class PeriodCondition {\n    public boolean isSatisfiedByPeriod(Screening screening) {\n        ...\n    }\n}\n\npublic class SequenceCondition {\n    public boolean isSatisfiedBySequence(Screening screening) {\n        ...\n    }\n}</code>\n        </deckgo-highlight-code>\n<ol>\n<li>\n<p>메서드가 작업을 어떻게 수행하는지를 나타내도록 이름 짓는 것</p>\n<ul>\n<li>메서드의 이름은 내부의 구현 방법을 드러낸다.</li>\n<li>메서드에 대해 제대로 커뮤니케이션하지 못한다.</li>\n<li>메서드 수준에서 캡슐화를 위반한다.\n<ul>\n<li>클라이언트로 하여금 협력하는 객체의 종류를 알도록 강요</li>\n</ul>\n</li>\n</ul>\n</li>\n<li>\n<p>'어떻게'가 아니라 '무엇'을 하는지를 드러내는 것</p>\n<ul>\n<li>어떻게 수행하는지를 드러내는 이름이란 메서드의 내부 구현을 설명하는 이름</li>\n<li>무엇을 하는지를 드러내도록 메서드의 이름을 짓기 위해서는 객체가 협력 안에서 수행해야 하는 책임에 관해 고민</li>\n</ul>\n</li>\n</ol>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public class PeriodCondition {\n    public boolean isSatisfiedBy(Screening screening) {\n        ...\n    }\n}\n\npublic class SequenceCondition {\n    public boolean isSatisfiedBy(Screening screening) {\n        ...\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>위 코드는 자연스레 아래와 같이 바뀐다.</li>\n</ul>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public interface DiscountCondition {\n    boolean isSatisfiedBy(Screening screening);\n}</code>\n        </deckgo-highlight-code>\n<p>이와 같은 메서드 명명 방법을 <strong>의도를 드러내는 선택자(Intention Revealing Selector)</strong> 라고 부른다.</p>\n<ul>\n<li>에릭 에반스는 의도를 드러내는 선택자를 인터페이스 레벨로 확장한 **의도를 드러내는 인터페이스(Intention Revealing Interface)**를 제시\n<ul>\n<li>구현과 관련된 모든 정보를 캡슐화하고 객체의 퍼블릭 인터페이스에는 협력과 관련된 의도만을 표현</li>\n</ul>\n</li>\n</ul>\n<h3 id=\"-624-함께-모으기\" style=\"position:relative;\"><a href=\"#-624-%ED%95%A8%EA%BB%98-%EB%AA%A8%EC%9C%BC%EA%B8%B0\" aria-label=\" 624 함께 모으기 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.2.4 함께 모으기</h3>\n<h4 id=\"️-6241-디미터-법칙을-위반하는-티켓-판매-도메인\" style=\"position:relative;\"><a href=\"#%EF%B8%8F-6241-%EB%94%94%EB%AF%B8%ED%84%B0-%EB%B2%95%EC%B9%99%EC%9D%84-%EC%9C%84%EB%B0%98%ED%95%98%EB%8A%94-%ED%8B%B0%EC%BC%93-%ED%8C%90%EB%A7%A4-%EB%8F%84%EB%A9%94%EC%9D%B8\" aria-label=\"️ 6241 디미터 법칙을 위반하는 티켓 판매 도메인 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🛠️ 6.2.4.1 디미터 법칙을 위반하는 티켓 판매 도메인</h4>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@AllArgsConstructor\npublic class Theater {\n\n    private TicketSeller ticketSeller;\n\n    // 관람객 입장\n    public void enter(Audience audience) {\n        if (audience.getBag().hasInvitation()) {\n            Ticket ticket = ticketSeller.getTicketOffice().getTicket();\n            audience.getBag().setTicket(ticket);\n            return;\n        }\n        Ticket ticket = ticketSeller.getTicketOffice().getTicket();\n        audience.getBag().minusAmount(ticket.getFee());\n        ticketSeller.getTicketOffice().plusAmount(ticket.getFee());\n        audience.getBag().setTicket(ticket);\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>디미터 법칙을 위반한 전형적인 코드</li>\n<li><strong>인터페이스와 구현의 분리 원칙</strong> 위반</li>\n<li>불안정하고, 사용하기 힘들고, 클라이언트에게 구현을 노출</li>\n</ul>\n<h4 id=\"️-6242-묻지-말고-시켜라\" style=\"position:relative;\"><a href=\"#%EF%B8%8F-6242-%EB%AC%BB%EC%A7%80-%EB%A7%90%EA%B3%A0-%EC%8B%9C%EC%BC%9C%EB%9D%BC\" aria-label=\"️ 6242 묻지 말고 시켜라 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🛠️ 6.2.4.2 묻지 말고 시켜라</h4>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@AllArgsConstructor\npublic class TicketSeller {\n\n    private TicketOffice ticketOffice;\n\n    public void setTicket(Audience audience) {\n        if (audience.getBag().hasInvitation()) {\n            Ticket ticket = ticketOffice.getTicket();\n            audience.getBag().setTicket(ticket);\n            return;\n        }\n        Ticket ticket = ticketOffice.getTicket();\n        audience.getBag().minusAmount(ticket.getFee());\n        ticketOffice.plusAmount(ticket.getFee());\n        audience.getBag().setTicket(ticket);\n    }\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@AllArgsConstructor\npublic class Theater {\n\n    private TicketSeller ticketSeller;\n\n    public void enter(Audience audience) {\n        ticketSeller.setTicket(audience);\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>Theater</code>는 <code>TicketSeller</code>와 <code>Audience</code>의 내부 구조에 관해 묻지 말고 원하는 작업을 시켜야 한다.</li>\n</ul>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@AllArgsConstructor\npublic class Audience {\n\n    private Bag bag;\n\n    public Long setTicket(Ticket ticket) {\n        if (bag.hasInvitation()) {\n            bag.setTicket(ticket);\n            return 0L;\n        }\n        bag.setTicket(ticket);\n        bag.minusAmount(ticket.getFee());\n        return ticket.getFee();\n    }\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@AllArgsConstructor\npublic class TicketSeller {\n\n    private TicketOffice ticketOffice;\n\n    public void setTicket(Audience audience) {\n        ticketOffice.plusAmount(audience.setTicket(ticketOffice.getTicket()));\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>TicketSeller</code>는 속성으로 포함되고 있는 <code>TicketOffice</code>의 인스턴스와 인자로 전달된 <code>Audience</code>에게만 메시지를 전송한다.</li>\n<li><code>Audience</code>는 <code>hasInvitation</code> 메서드를 이용해 초대권을 가지고 있는지를 묻는다. 즉, 디미터 법칙을 위반한다.</li>\n</ul>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public class Bag {\n\n    private Long amount;\n    private Invitation invitation;\n    private Ticket ticket;\n\n    public Long setTicket(Ticket ticket) {\n        if (hasInvitation()) {\n            setTicket(ticket);\n            return 0L;\n        }\n        setTicket(ticket);\n        minusAmount(ticket.getFee());\n        return ticket.getFee();\n    }\n\n    public boolean hasInvitation() {\n        return invitation != null;\n    }\n\n    public void minusAmount(Long amount) {\n        this.amount -= amount;\n    }\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@AllArgsConstructor\npublic class Audience {\n\n    private Bag bag;\n\n    public Long setTicket(Ticket ticket) {\n        return bag.setTicket(ticket);\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>Audience</code>는 자율적인 존재가 되었다.</li>\n</ul>\n<p>디미터 법칙과 묻지 말고 시켜라 스타일을 따르면 자연스럽게 자율적인 객체로 구성된 유연한 협력을 얻게 된다.</p>\n<h4 id=\"️-6243-인터페이스에-의도를-드러내자\" style=\"position:relative;\"><a href=\"#%EF%B8%8F-6243-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EC%97%90-%EC%9D%98%EB%8F%84%EB%A5%BC-%EB%93%9C%EB%9F%AC%EB%82%B4%EC%9E%90\" aria-label=\"️ 6243 인터페이스에 의도를 드러내자 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🛠️ 6.2.4.3 인터페이스에 의도를 드러내자</h4>\n<p>위 코드들의 <code>setTicket</code> 메서드는 미묘하게 다른 의미를 가지고 있다❗️</p>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public class TicketSeller {\n    public void sellTo(Audience audience) {\n        ...\n    }\n}\n\npublic class Audience {\n    public Long buy(Ticket ticket) {\n        ...\n    }\n}\n\npublic class Bag {\n    public Long hold(Ticket ticket) {\n        ...\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>위 메서드 명칭은 클라이언트가 객체에게 무엇을 원하는지를 명확하게 표현</li>\n</ul>\n<h2 id=\"-63-원칙의-함정\" style=\"position:relative;\"><a href=\"#-63-%EC%9B%90%EC%B9%99%EC%9D%98-%ED%95%A8%EC%A0%95\" aria-label=\" 63 원칙의 함정 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 6.3 원칙의 함정</h2>\n<p>원칙이 현재 상황에 부적합하다고 판단된다면 과감하게 원칙을 무시하라.</p>\n<h3 id=\"-631-디미터-법칙은-하나의-도트를-강제하는-규칙이-아니다\" style=\"position:relative;\"><a href=\"#-631-%EB%94%94%EB%AF%B8%ED%84%B0-%EB%B2%95%EC%B9%99%EC%9D%80-%ED%95%98%EB%82%98%EC%9D%98-%EB%8F%84%ED%8A%B8%EB%A5%BC-%EA%B0%95%EC%A0%9C%ED%95%98%EB%8A%94-%EA%B7%9C%EC%B9%99%EC%9D%B4-%EC%95%84%EB%8B%88%EB%8B%A4\" aria-label=\" 631 디미터 법칙은 하나의 도트를 강제하는 규칙이 아니다 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.3.1 디미터 법칙은 하나의 도트(.)를 강제하는 규칙이 아니다</h3>\n<p><code>IntStream.of(1, 15, 20, 3, 9).filter(x -> x > 10).distinct().count();</code></p>\n<ul>\n<li>위 코드는 동일한 클래스의 인스턴스를 반환하므로 디미터 법칙을 위반하지 않는다.</li>\n<li>기차 충돌처럼 보이는 코드라도 객체의 내부 구현에 대한 어떤 정보도 외부로 노출하지 않는다면 그것은 디미터 법칙을 준수한 것이다.</li>\n</ul>\n<h3 id=\"-632-결합도와-응집도의-충돌\" style=\"position:relative;\"><a href=\"#-632-%EA%B2%B0%ED%95%A9%EB%8F%84%EC%99%80-%EC%9D%91%EC%A7%91%EB%8F%84%EC%9D%98-%EC%B6%A9%EB%8F%8C\" aria-label=\" 632 결합도와 응집도의 충돌 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.3.2 결합도와 응집도의 충돌</h3>\n<ul>\n<li>모든 상황에서 맹목적으로 위임 메서드를 추가하면 같은 퍼블릭 인터페이스 안에 어울리지 않는 오퍼레이션들이 공존하게 된다. 결과적으로 응집도 ⬇️</li>\n<li>가끔씩은 묻는 것 외에는 다른 방법이 존재하지 않는 경우도 있다.\n<ul>\n<li>컬렉션에 포함된 객체들을 처리하는 유일한 방법은 객체에게 물어보는 것</li>\n<li>묻는 대상이 자료 구조라면 당연히 내부를 노출해야 하므로 디미터 법칙을 적용할 필요가 없다.</li>\n</ul>\n</li>\n</ul>\n<p>설계는 trade-off의 산물이다. 즉, 경우에 따라 다르다</p>\n<p>원칙이 적절한 상황과 부적절한 상황을 판단할 수 있는 안목을 길러라❗️</p>\n<h2 id=\"-64-명령-쿼리-분리-원칙\" style=\"position:relative;\"><a href=\"#-64-%EB%AA%85%EB%A0%B9-%EC%BF%BC%EB%A6%AC-%EB%B6%84%EB%A6%AC-%EC%9B%90%EC%B9%99\" aria-label=\" 64 명령 쿼리 분리 원칙 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 6.4 명령-쿼리 분리 원칙</h2>\n<ul>\n<li><strong>루틴(routine)</strong>: 어떤 절차를 묶어 호출 가능하도록 이름을 부여한 기능 모듈\n<ul>\n<li>**프로시저(procedure)**와 **함수(function)**로 구분</li>\n</ul>\n</li>\n<li>프로시저(procedure): 정해진 절차에 따라 내부의 상태를 변경하는 루틴의 한 종류\n<ul>\n<li>부수효과를 발생시킬 수 있지만 값을 반환할 수 없다.</li>\n<li>객체의 인터페이스 측면에서 **명령(Command)**와 동일</li>\n</ul>\n</li>\n<li>함수(function): 어떤 절차에 따라 필요한 값을 계산해서 반환하는 루틴의 한 종류\n<ul>\n<li>값을 반환할 수 있지만 부수효과를 발생시킬 수 없다.</li>\n<li>객체의 인터페이스 측면에서 **쿼리(Query)**와 동일</li>\n</ul>\n</li>\n</ul>\n<p>명령-쿼리 분리 원칙의 요지는 오퍼레이션은 부수효과를 발생시키는 명령이거나 부수효과를 발생시키지 않는 쿼리 중 하나여야 한다는 것</p>\n<ul>\n<li>객체의 상태를 변경하는 명령은 반환값을 가질 수 없다.</li>\n<li>객체의 정보를 반환하는 쿼리는 상태를 변경할 수 없다.</li>\n<li>\"질문이 답변을 수정해서는 안 된다\"</li>\n</ul>\n<h3 id=\"-641-반복-일정의-명령과-쿼리-분리하기\" style=\"position:relative;\"><a href=\"#-641-%EB%B0%98%EB%B3%B5-%EC%9D%BC%EC%A0%95%EC%9D%98-%EB%AA%85%EB%A0%B9%EA%B3%BC-%EC%BF%BC%EB%A6%AC-%EB%B6%84%EB%A6%AC%ED%95%98%EA%B8%B0\" aria-label=\" 641 반복 일정의 명령과 쿼리 분리하기 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.4.1 반복 일정의 명령과 쿼리 분리하기</h3>\n<p>예시 도메인의 용어 정리</p>\n<ul>\n<li>이벤트: 특정 일자에 실제로 발생하는 사건</li>\n<li>반복 일정: 일주일 단위로 돌아오는 특정 시간 간격에 발생하는 사건 전체를 포괄적으로 지칭</li>\n</ul>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@AllArgsConstructor\npublic class Event {\n\n    private String subject;\n    private LocalDateTime from;\n    private Duration duration;\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@AllArgsConstructor\npublic class RecurringSchedule {\n\n    private String subject;\n\n    @Getter\n    private DayOfWeek dayOfWeek;\n\n    @Getter\n    private LocalTime from;\n\n    @Getter\n    private Duration duration;\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">RecurringSchedule schedule = new RecurringSchedule(&quot;회의&quot;, DayOfWeek.WEDNESDAY, LocalTime.of(10, 30), Duration.ofMinutes(30));\nEvent meeting = new Event(&quot;회의&quot;, LocalDateTime.of(2019, 5, 8, 10, 30), Duration.ofMinutes(30));\n\nassert meeting.isSatisfied(schedule);</code>\n        </deckgo-highlight-code>\n<ul>\n<li>위 코드는 당연히 true를 반환한다.</li>\n</ul>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">RecurringSchedule schedule = new RecurringSchedule(&quot;회의&quot;, DayOfWeek.WEDNESDAY, LocalTime.of(10, 30), Duration.ofMinutes(30));\nEvent meeting = new Event(&quot;회의&quot;, LocalDateTime.of(2019, 5, 9, 10, 30), Duration.ofMinutes(30));\n\nassert !meeting.isSatisfied(schedule);\nassert meeting.isSatisfied(schedule);</code>\n        </deckgo-highlight-code>\n<ul>\n<li>5/9는 목요일이므로 <code>false</code>를 반환한다. 하지만 다시 한번 더 실행시키면 <code>true</code>를 반환한다.</li>\n</ul>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@AllArgsConstructor\npublic class Event {\n\n    private String subject;\n    private LocalDateTime from;\n    private Duration duration;\n\n    public boolean isSatisfied(RecurringSchedule schedule) {\n        if (from.getDayOfWeek() != schedule.getDayOfWeek() ||\n                !from.toLocalTime().equals(schedule.getFrom()) ||\n                !duration.equals(schedule.getDuration())) {\n            reschedule(schedule);\n            return false;\n        }\n        return true;\n    }\n\n    private void reschedule(RecurringSchedule schedule) {\n        from = LocalDateTime.of(from.toLocalDate().plusDays(daysDistance(schedule)), schedule.getFrom());\n        duration = schedule.getDuration();\n    }\n\n    private long daysDistance(RecurringSchedule schedule) {\n        return schedule.getDayOfWeek().getValue() - from.getDayOfWeek().getValue();\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>isSatisfied</code>가 명령과 쿼리의 두 가지 역할을 동시에 수행하고 있었기 때문에 발생한 문제</li>\n<li>명령과 쿼리를 뒤섞으면 실행 결과를 예측하기가 어려워질 수 있다.</li>\n</ul>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@AllArgsConstructor\npublic class Event {\n\n    private String subject;\n    private LocalDateTime from;\n    private Duration duration;\n\n    public boolean isSatisfied(RecurringSchedule schedule) {\n        return from.getDayOfWeek() == schedule.getDayOfWeek() &amp;&amp;\n                from.toLocalTime().equals(schedule.getFrom()) &amp;&amp;\n                duration.equals(schedule.getDuration());\n    }\n\n    public void reschedule(RecurringSchedule schedule) {\n        from = LocalDateTime.of(from.toLocalDate().plusDays(daysDistance(schedule)), schedule.getFrom());\n        duration = schedule.getDuration();\n    }\n\n    private long daysDistance(RecurringSchedule schedule) {\n        return schedule.getDayOfWeek().getValue() - from.getDayOfWeek().getValue();\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>이렇게 분리가 되어 <code>reschedule</code> 메서드 호출 여부를 <code>Event</code>를 사용하는 쪽에서 결정할 수 있다.</li>\n<li>예측 가능하고 이해하기 쉬우며 디버깅이 용이한 동시에 유지보수가 수월해질 것</li>\n</ul>\n<h3 id=\"-642-명령-쿼리-분리와-참조-투명성\" style=\"position:relative;\"><a href=\"#-642-%EB%AA%85%EB%A0%B9-%EC%BF%BC%EB%A6%AC-%EB%B6%84%EB%A6%AC%EC%99%80-%EC%B0%B8%EC%A1%B0-%ED%88%AC%EB%AA%85%EC%84%B1\" aria-label=\" 642 명령 쿼리 분리와 참조 투명성 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.4.2 명령-쿼리 분리와 참조 투명성</h3>\n<p>명령과 쿼리를 분리함으로써 명령형 언어의 틀 안에서 **참조 투명성(referential transparency)**의 장점을 제한적이나마 누릴 수 있게 된다.</p>\n<ul>\n<li>참조 투명성이란 어떤 표현식 e가 있을 때 e의 값으로 e가 나타나는 모든 위치를 교체하더라도 결과가 달라지지 않는 특성</li>\n<li>참조 투명성을 잘 활용하면 버그가 적고, 디버깅이 용이하며, 쿼리의 순서에 따라 실행 결과가 변하지 않는 코드를 작성할 수 있다.</li>\n<li>컴퓨터의 세계와 수학의 세계를 나누는 가장 큰 특징은 <strong>부수효과(side effect)</strong> 의 존재 유무다.</li>\n<li>어떤 값이 변하지 않는 성질을 <strong>불변성(immutability)</strong> 이라고 부른다.</li>\n</ul>\n<p>참조 투명성을 만족하는 식은 우리에게 두 가지 장점을 제공</p>\n<ol>\n<li>모든 함수를 이미 알고 있는 하나의 결괏값으로 대체할 수 있기 때문에 식을 쉽게 계산할 수 있다.</li>\n<li>모든 곳에서 함수의 결괏값이 동일하기 때문에 식의 순서를 변경하더라도 각 식의 결과는 달라지지 않는다.</li>\n</ol>\n<h3 id=\"-643-책임에-초점을-맞춰라\" style=\"position:relative;\"><a href=\"#-643-%EC%B1%85%EC%9E%84%EC%97%90-%EC%B4%88%EC%A0%90%EC%9D%84-%EB%A7%9E%EC%B6%B0%EB%9D%BC\" aria-label=\" 643 책임에 초점을 맞춰라 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.4.3 책임에 초점을 맞춰라</h3>\n<p>메시지를 먼저 선택하고 그 후에 메시지를 처리할 객체를 선택하라.</p>\n<ul>\n<li>디미터 법칙\n<ul>\n<li>협력이라는 컨텍스트 안에서 객체보다 메시지를 먼저 결정하면 두 객체 사이의 구조적인 결합도를 낮출 수 있다.</li>\n</ul>\n</li>\n<li>묻지 말고 시켜라\n<ul>\n<li>메시지를 먼저 선택하면 협력을 구조화하게 된다.</li>\n</ul>\n</li>\n<li>의도를 드러내는 인터페이스\n<ul>\n<li>메시지를 먼저 선택한다는 것은 메시지를 전송하는 클라이언트의 관점에서 메시지의 이름을 정한다는 것</li>\n</ul>\n</li>\n<li>명령-쿼리 분리 원칙\n<ul>\n<li>메시지를 먼저 선택한다는 것은 협력이라는 문맥 안에서 객체의 인터페이스에 관해 고민한다는 것을 의미</li>\n</ul>\n</li>\n</ul>\n<p>협력을 위해 두 객체가 보장해야 하는 실행 시점의 제약을 인터페이스에 명시할 수 있는 방법이 존재하지 않음.</p>\n<ul>\n<li>시그니처에는 어떤 조건이 만족돼야만 오퍼레이션을 호출할 수 있고 어떤 경우에 결과를 반환받을 수 없는지를 표현할 수 없다.</li>\n<li>이 문제를 해결하기 위해 <strong>계약에 의한 설계(Design By Contract)</strong> 개념이 나옴.</li>\n</ul>","excerpt":"애플리케이션은 클래스로 구성되지만 메시지를 통해 정의된다는 사실을 기억하라. 📖 6.1 협력과 메시지 🔖 6.1.1 클라이언트-서버 모델 메시지는 객체 사이의 협력을 가능하게 하는 매개체다. 두 객체 사이의 협력 관계를 설명하기 위해 사용하는 전통적인 메타포는 클라이언트-서버 모델 이다. Movie…","fields":{"slug":"/backend/object/chapter6/메시지와_인터페이스/"},"frontmatter":{"title":"Object - 6장 메시지와 인터페이스","thumbnail":{"childImageSharp":{"fluid":{"src":"/static/dd0e1990925e942697544e2bdcd9332e/9b73b/object.png"}}},"draft":false,"category":"Back-End","tags":["java"],"date":"October 01, 2023"}},"previous":{"id":"7df70221-cf06-58ea-9288-34d2e832195f","html":"<p>협력은 필수적이지만 과도한 협력은 설계를 곤경에 빠트릴 수 있다. 협력을 위해서는 의존성이 필요하지만 과도한 의존성은 애플리케이션을 수정하기 어렵게 만든다.</p>\n<p>객체지향 설계의 핵심은 협력을 위해 필요한 의존성은 유지하면서도 변경을 방해하는 의존성은 제거하는데 있다. 이런 관점에서 객체지향 설계란 의존성을 관리하는 것이고 객체가 변화를 받아들일 수 있게 의존성을 정리하는 기술이라고 할 수 있다.</p>\n<h2 id=\"-81-의존성-이해하기\" style=\"position:relative;\"><a href=\"#-81-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0\" aria-label=\" 81 의존성 이해하기 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 8.1 의존성 이해하기</h2>\n<h3 id=\"-811-변경과-의존성\" style=\"position:relative;\"><a href=\"#-811-%EB%B3%80%EA%B2%BD%EA%B3%BC-%EC%9D%98%EC%A1%B4%EC%84%B1\" aria-label=\" 811 변경과 의존성 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 8.1.1 변경과 의존성</h3>\n<p>어떤 객체가 협력하기 위해 다른 객체를 필요로 할 때 두 객체 사이에 의존성이 존재하게 된다. 의존성은 실행 시점과 구현 시점에 서로 다른 의미를 가진다.</p>\n<ul>\n<li>실행 시점: 의존하는 객체가 정상적으로 동작하기 위해서는 실행 시에 의존 대상 객체가 반드시 존재해야 한다.</li>\n<li>구현 시점: 의존 대상 객체가 변경될 경우 의존하는 객체도 함께 변경된다.</li>\n</ul>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@AllArgsConstructor\npublic class PeriodCondition implements DiscountCondition {\n\n    private DayOfWeek dayOfWeek;\n    private LocalTime startTime;\n    private LocalTime endTime;\n\n    @Override\n    public boolean isSatisfiedBy(Screening screening) {\n        return screening.getStartTime().getDayOfWeek().equals(dayOfWeek) &amp;&amp;\n                !startTime.isAfter(screening.getStartTime().toLocalTime()) &amp;&amp;\n                !endTime.isBefore(screening.getStartTime().toLocalTime());\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>실행 시점에 <code>PeriodCondition</code>의 인스턴스가 정상적으로 동작하기 위해서는 <code>Screening</code>의 인스턴스가 존재해야 한다.</li>\n</ul>\n<p>이처럼 어떤 객체가 예정된 작업을 정상적으로 수행하기 위해 다른 객체를 필요로 하는 경우 두 객체 사이에 의존성이 존재한다고 말한다.</p>\n<ul>\n<li>의존성은 방향성을 가지며 항상 단방향이다.</li>\n<li>두 요소 사이의 의존성은 의존되는 요소가 변경될 때 의존하는 요소도 함께 변경될 수 있다는 것을 의미\n<ul>\n<li>의존성은 변경에 의한 영향의 전파 가능성을 암시</li>\n</ul>\n</li>\n</ul>\n<h3 id=\"-812-의존성-전이\" style=\"position:relative;\"><a href=\"#-812-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A0%84%EC%9D%B4\" aria-label=\" 812 의존성 전이 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 8.1.2 의존성 전이</h3>\n<ul>\n<li>의존성은 함께 변경될 수 있는 <em>가능성</em>을 의미하기 때문에 모든 경우에 의존성이 전이되는 것은 아니다.</li>\n<li>의존성이 실제로 전이될지 여부는 변경의 방향과 캡슐화의 정도에 따라 달라진다.</li>\n<li>의존성 전이는 변경에 의해 영향이 널리 전파될 수도 있다는 경고일 뿐이다.</li>\n</ul>\n<p>직접 의존성</p>\n<ul>\n<li>한 요소가 다른 요소에 직접 의존하는 경우</li>\n<li><code>PeriodCondition</code>이 <code>Screening</code>에 직접 의존하는 경우</li>\n</ul>\n<p>간접 의존성</p>\n<ul>\n<li>직접적인 관계는 존재하지 않지만 의존성 전이에 의해 영향이 전파되는 경우</li>\n</ul>\n<h3 id=\"-813-런타임-의존성과-컴파일타임-의존성\" style=\"position:relative;\"><a href=\"#-813-%EB%9F%B0%ED%83%80%EC%9E%84-%EC%9D%98%EC%A1%B4%EC%84%B1%EA%B3%BC-%EC%BB%B4%ED%8C%8C%EC%9D%BC%ED%83%80%EC%9E%84-%EC%9D%98%EC%A1%B4%EC%84%B1\" aria-label=\" 813 런타임 의존성과 컴파일타임 의존성 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 8.1.3 런타임 의존성과 컴파일타임 의존성</h3>\n<p>런타임 의존성</p>\n<ul>\n<li>런타임: 애플리케이션이 실행되는 시점</li>\n<li>객체 사이의 의존성</li>\n</ul>\n<p>컴파일타임 의존성</p>\n<ul>\n<li>컴파일타임: 코드를 컴파일하는 시점, 문맥에 따라서는 코드 그 자체</li>\n<li>클래스 사이의 의존성</li>\n</ul>\n<p>유연하고 재사용 가능한 설계를 창조하기 위해서는 동일한 소스코드 구조를 가지고 다양한 실행 구조를 만들 수 있어야 한다.</p>\n<ul>\n<li>어떤 클래스의 인스턴스가 다양한 클래스의 인스턴스와 협력하기 위해서는 협력할 인스턴스의 구체적인 클래스를 알아서는 안 된다.</li>\n</ul>\n<h3 id=\"-814-컨텍스트-독립성\" style=\"position:relative;\"><a href=\"#-814-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%EB%8F%85%EB%A6%BD%EC%84%B1\" aria-label=\" 814 컨텍스트 독립성 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 8.1.4 컨텍스트 독립성</h3>\n<ul>\n<li>클래스가 사용될 특정한 문맥에 대해 최소한의 가정만으로 이뤄져 있다면 다른 문맥에서 재사용하기가 더 수월해진다.</li>\n<li>가능한 한 자신이 실행될 컨텍스트에 대한 구체적인 정보를 최대한 적게 알아야 한다.\n<ul>\n<li>더 다양한 컨텍스트에서 재사용될 수 있기 때문</li>\n</ul>\n</li>\n</ul>\n<blockquote>\n<p>시스템을 구성하는 객체가 컨텍스트 독립적이라면 해당 시스템은 변경하기 쉽다.\n여기서 컨텍스트 독립적이라는 말은 각 객체가 해당 객체를 실행하는 시스템에 관해 아무것도 알지 못한다는 의미다.</p>\n</blockquote>\n<h3 id=\"-815-의존성-해결하기\" style=\"position:relative;\"><a href=\"#-815-%EC%9D%98%EC%A1%B4%EC%84%B1-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0\" aria-label=\" 815 의존성 해결하기 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 8.1.5 의존성 해결하기</h3>\n<p>컴파일타임 의존성은 구체적인 런타임 의존성으로 대체돼야 한다.</p>\n<ul>\n<li>의존성 해결: 컴파일타임 의존성을 실행 컨텍스트에 맞는 적절한 런타임 의존성으로 교체하는 것\n<ul>\n<li>객체를 생성하는 시점에 생성자를 통해 의존성 해결</li>\n<li>객체 생성 후 setter 메서드를 통해 의존성 해결\n<ul>\n<li>객체를 생성한 이후에도 의존하고 있는 대상을 변경할 수 있는 가능성을 열어 놓고 싶은 경우에 유용</li>\n<li>객체가 생성된 후에 협력에 필요한 의존 대상을 설정하기 때문에 객체를 생성하고 의존 대상을 설정하기 전까지는 객체의 상태가 불완전할 수 있다.</li>\n<li>생성자 방식과 혼합해서 사용하는 걸 권장</li>\n</ul>\n</li>\n<li>메서드 실행 시 인자를 이용해 의존성 해결\n<ul>\n<li>메서드가 실행되는 동안만 일시적으로 의존 관계가 존재해도 무방할 때 사용</li>\n<li>메서드가 실행될 때마다 의존 대상이 매번 달라져야 하는 경우에 유용</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n<h2 id=\"-82-유연한-설계\" style=\"position:relative;\"><a href=\"#-82-%EC%9C%A0%EC%97%B0%ED%95%9C-%EC%84%A4%EA%B3%84\" aria-label=\" 82 유연한 설계 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 8.2 유연한 설계</h2>\n<h3 id=\"-821-의존성과-결합도\" style=\"position:relative;\"><a href=\"#-821-%EC%9D%98%EC%A1%B4%EC%84%B1%EA%B3%BC-%EA%B2%B0%ED%95%A9%EB%8F%84\" aria-label=\" 821 의존성과 결합도 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 8.2.1 의존성과 결합도</h3>\n<p>의존성은 객체들의 협력을 가능하게 만드는 매개체라는 관점에서는 바람직한 것이다. 하지만 의존성이 과하면 문제가 될 수 있다.</p>\n<p>바람직한 의존성은 <strong>재사용성</strong>과 관련이 있다.</p>\n<ul>\n<li>어떤 의존성이 다양한 환경에서 클래스를 재사용할 수 없도록 제한한다면 그 의존성은 바람직하지 못한 것이다.</li>\n<li>독립적인 의존성은 바람직한 의존성이고 특정한 컨텍스트에 강하게 결합된 의존성은 바람직하지 않은 의존성이다.</li>\n<li>의존성이 바람직할 때 느슨한 결합도(loose coupling) 또는 약한 결합도(weak coupling)를 가진다고 말한다.</li>\n<li>의존성이 바람직하지 못할 때 단단한 결합도(tight coupling) 또는 강한 결합도(strong coupling)를 가진다고 말한다.</li>\n</ul>\n<h3 id=\"-822-지식이-결합을-낳는다\" style=\"position:relative;\"><a href=\"#-822-%EC%A7%80%EC%8B%9D%EC%9D%B4-%EA%B2%B0%ED%95%A9%EC%9D%84-%EB%82%B3%EB%8A%94%EB%8B%A4\" aria-label=\" 822 지식이 결합을 낳는다 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 8.2.2 지식이 결합을 낳는다</h3>\n<p>결합도의 정도는 한 요소가 자신이 의존하고 있는 다른 요소에 대해 알고 있는 정보의 양으로 결정</p>\n<ul>\n<li>한 요소가 다른 요소에 대해 더 많은 정보를 알고 있을수록 강하게 결합\n<ul>\n<li>더 적은 컨텍스트에서 재사용 가능하다는 것을 의미</li>\n</ul>\n</li>\n<li>한 요소가 다른 요소에 대해 더 적은 정보를 알고 있을수록 두 요소는 약하게 결합</li>\n</ul>\n<p>결합도를 느슨하게 만들기 위해서는 협력하는 대상에 대해 필요한 정보 외에는 최대한 감추는 것이 중요</p>\n<h3 id=\"-823-추상화에-의존하라\" style=\"position:relative;\"><a href=\"#-823-%EC%B6%94%EC%83%81%ED%99%94%EC%97%90-%EC%9D%98%EC%A1%B4%ED%95%98%EB%9D%BC\" aria-label=\" 823 추상화에 의존하라 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 8.2.3 추상화에 의존하라</h3>\n<p>추상화란 어떤 양상, 세부사항, 구조를 좀 더 명확하게 이해하기 위해 특정 절차나 물체를 의도적으로 생략하거나 감춤으로써 복잡도를 극복하는 방법</p>\n<p>일반적으로 추상화와 결합도의 관점에서 의존 대상을 다음과 같이 구분하는 것이 유용하다. 아래로 갈수록 결합도가 느슨해진다.</p>\n<ul>\n<li>구체 클래스 의존성</li>\n<li>추상 클래스 의존성\n<ul>\n<li>상속 계층이 무엇인지 알아야 한다.</li>\n</ul>\n</li>\n<li>인터페이스 의존성\n<ul>\n<li>상속 계층을 모르더라도 협력이 가능해진다.</li>\n</ul>\n</li>\n</ul>\n<p>의존하는 대상이 더 추상적일수록 결합도는 더 낮아진다.</p>\n<h3 id=\"-824-명시적인-의존성\" style=\"position:relative;\"><a href=\"#-824-%EB%AA%85%EC%8B%9C%EC%A0%81%EC%9D%B8-%EC%9D%98%EC%A1%B4%EC%84%B1\" aria-label=\" 824 명시적인 의존성 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 8.2.4 명시적인 의존성</h3>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public class Movie {\n\n  private DiscountPolicy discountPolicy;\n\n  public Movie(String title, Duration runningTime, Money fee) {\n    this.discountPolicy = new AmountDiscountPolicy(...);\n  }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>구체 클래스인 <code>AmountDiscountPolicy</code>의 인스턴스를 직접 생성해서 대입하고 있어 결합도가 불필요하게 높아졌다.</li>\n<li><strong>숨겨진 의존성</strong>: 의존성이 퍼블릭 인터페이스에 표현되지 않는다.</li>\n</ul>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public class Movie {\n\n  private DiscountPolicy discountPolicy;\n\n  public Movie(String title, Duration runningTime, Money fee, DiscountPolicy discountPolicy) {\n    this.discountPolicy = discountPolicy;\n  }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>생성자를 사용해 의존성을 해결했다.</li>\n<li><strong>명시적인 의존성</strong>: 모든 경우에 의존성은 명시적으로 퍼블릭 인터페이스에 노출된다.</li>\n</ul>\n<p>의존성을 구현 내부에 숨겨두지 마라. 명시적인 의존성을 사용해야만 퍼블릭 인터페이스를 통해 컴파일타임 의존성을 적절한 런타임 의존성으로 교체할 수 있다.</p>\n<ul>\n<li>클래스가 다른 클래스에 의존하는 것은 부끄러운 것이 아니다❗️</li>\n<li>경계해야 할 것은 의존성 자체가 아니라 의존성을 감추는 것이다.</li>\n</ul>\n<h3 id=\"-825-new는-해롭다\" style=\"position:relative;\"><a href=\"#-825-new%EB%8A%94-%ED%95%B4%EB%A1%AD%EB%8B%A4\" aria-label=\" 825 new는 해롭다 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 8.2.5 new는 해롭다</h3>\n<p><code>new</code>를 잘못 사용하면 클래스 사이의 결합도가 극단적으로 높아진다.</p>\n<ul>\n<li><code>new</code> 연산자를 사용하기 위해서는 구체 클래스의 이름을 직접 기술해야한다. 즉, 구체 클래스에 의존할 수 밖에 없기에 결합도가 높아진다.</li>\n<li><code>new</code> 연산자는 생성하려는 구체 클래스뿐만 아니라 어떤 인자를 이용해 클래스의 생성자를 호출해야 하는지도 알아야 한다. 즉, 지식의 양이 늘어나기 때문에 결합도가 높아진다.</li>\n</ul>\n<p>사용과 생성의 책임을 분리하고, 의존성을 생성자에 명시적으로 드러내고, 구체 클래스가 아닌 추상 클래스에 의존하게 함으로써 설계를 유연하게 만들 수 있다.</p>\n<ul>\n<li>객체를 생성하는 책임을 객체 내부가 아니라 클라이언트로 옮겨라❗️</li>\n</ul>\n<h3 id=\"-826-가끔은-생성해도-무방하다\" style=\"position:relative;\"><a href=\"#-826-%EA%B0%80%EB%81%94%EC%9D%80-%EC%83%9D%EC%84%B1%ED%95%B4%EB%8F%84-%EB%AC%B4%EB%B0%A9%ED%95%98%EB%8B%A4\" aria-label=\" 826 가끔은 생성해도 무방하다 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 8.2.6 가끔은 생성해도 무방하다</h3>\n<p>주로 협력하는 기본 객체를 설정하고 싶은 경우 클래스 안에서 객체의 인스턴스를 직접 생성하는 방식이 유용하다.</p>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public class Movie {\n\n  private DiscountPolicy discountPolicy;\n\n  public Movie(String title, Duration runningTime, Money fee) {\n    this(title, runningTime, fee, new AmountDiscountPolicy(...));\n  }  \n\n  public Movie(String title, Duration runningTime, Money fee, DiscountPolicy discountPolicy) {\n    this.discountPolicy = discountPolicy;\n  }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>생성자 체이닝을 활용</li>\n<li>메서드 오버로딩에도 사용 가능</li>\n</ul>\n<p>모든 결합도가 모이는 새로운 클래스를 추가함으로써 사용성과 유연성이라는 두 마리 토끼를 잡을 수 있는 경우도 있다.</p>\n<h3 id=\"-827-표준-클래스에-대한-의존은-해롭지-않다\" style=\"position:relative;\"><a href=\"#-827-%ED%91%9C%EC%A4%80-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%97%90-%EB%8C%80%ED%95%9C-%EC%9D%98%EC%A1%B4%EC%9D%80-%ED%95%B4%EB%A1%AD%EC%A7%80-%EC%95%8A%EB%8B%A4\" aria-label=\" 827 표준 클래스에 대한 의존은 해롭지 않다 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 8.2.7 표준 클래스에 대한 의존은 해롭지 않다</h3>\n<p>의존성이 불편한 이유는 그것이 항상 변경에 대한 영향을 암시하기 때문</p>\n<ul>\n<li>변경될 확률이 거의 없는 클래스라면 의존성이 문제가 되지 않는다.</li>\n</ul>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public abstract class DiscountPolicy {\n  \n  private List&lt;DiscountCondition&gt; conditions = new ArrayList&lt;&gt;();\n\n  public void switchConditions(List&lt;DiscountCondition&gt; conditions) {\n    this.conditions = conditions;\n  }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>ArrayList</code>의 코드가 수정될 확률은 0에 가깝기 때문에 인스턴스를 직접 생성하더라도 문제가 되지 않는다.</li>\n<li>클래스를 직접 생성하더라도 가능한 한 추상적인 타입을 사용하는 것이 확장성 측면에서 유리하다.\n<ul>\n<li>인터페이스 <code>List</code>를 사용하여 다양한 객체로 대체가능하도록 설계</li>\n</ul>\n</li>\n</ul>\n<h3 id=\"-828-컨텍스트-확장하기\" style=\"position:relative;\"><a href=\"#-828-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%ED%99%95%EC%9E%A5%ED%95%98%EA%B8%B0\" aria-label=\" 828 컨텍스트 확장하기 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 8.2.8 컨텍스트 확장하기</h3>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public class Movie {\n\n  private DiscountPolicy discountPolicy;\n\n  public Movie(String title, Duration runningTime, Money fee) {\n    this(title, runningTime, fee, null);\n  }  \n\n  public Movie(String title, Duration runningTime, Money fee, DiscountPolicy discountPolicy) {\n    this.discountPolicy = discountPolicy;\n  }\n\n  public Money calculateMovieFee(Screening screening) {\n    if (discountPolicy == null) {\n      return fee;\n    }\n\n    return fee.minus(discountPolicy.calculateDiscountAmount(screening))\n  }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>예외 케이스가 추가되어 내부 코드가 수정되었다.\n<ul>\n<li>버그 발생 가능성 ⬆️</li>\n</ul>\n</li>\n</ul>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public class NoneDiscountPolicy extends DiscountPolicy {\n    \n    @Override\n    protected Money getDiscountAmount(Screening screening) {\n        return Money.ZERO;\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>내부 코드를 수정하지 않아도 된다.</li>\n</ul>\n<p>설계를 유연하게 만들 수 있었던 이유는 <code>Movie</code>가 <code>DiscountPolicy</code>라는 추상화에 의존하고, 생성자를 통해 <code>DiscountPolicy</code>에 대한 의존성을 명시적으로 드러냈으며, <code>new</code>와 같이 구체 클래스를 직접적으로 다뤄야 하는 책임을 <code>Movie</code> 외부로 옮겼기 때문이다.</p>\n<ul>\n<li>결합도를 낮춤으로써 얻게 되는 컨텍스트 확장이라는 개념이 유연하고 재사용 가능한 설계를 만드는 핵심</li>\n</ul>\n<h3 id=\"-828-조합-가능한-행동\" style=\"position:relative;\"><a href=\"#-828-%EC%A1%B0%ED%95%A9-%EA%B0%80%EB%8A%A5%ED%95%9C-%ED%96%89%EB%8F%99\" aria-label=\" 828 조합 가능한 행동 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 8.2.8 조합 가능한 행동</h3>\n<p>어떤 객체와 협력하느냐에 따라 객체의 행동이 달라지는 것은 유연하고 재사용 가능한 설계가 가진 특징이다. 유연하고 재사용 가능한 설계는 응집도 높은 책임들을 가진 작은 객체들을 다양한 방식으로 연결함으로써 애플리케이션의 기능을 쉽게 확장할 수 있다.</p>\n<p>훌륭한 객체지향 설계란 객체가 어떻게 하는지를 표현하는 것이 아니라 객체들의 조합을 선언적으로 표현함으로써 객체들이 무엇을 하는지를 표현하는 설계다.</p>\n<p>설계를 창조하는 데 있어서의 핵심은 <strong>의존성을 관리</strong>하는 것이다.</p>","excerpt":"협력은 필수적이지만 과도한 협력은 설계를 곤경에 빠트릴 수 있다. 협력을 위해서는 의존성이 필요하지만 과도한 의존성은 애플리케이션을 수정하기 어렵게 만든다. 객체지향 설계의 핵심은 협력을 위해 필요한 의존성은 유지하면서도 변경을 방해하는 의존성은 제거하는데 있다. 이런 관점에서 객체지향 설계란 의존성을 관리하는 것이고 객체가 변화를 받아들일 수 있게 의존성을 정리하는 기술이라고 할 수 있다. 📖 8.1 의존성 이해하기 🔖 8.1.…","fields":{"slug":"/backend/object/chapter8/의존성_관리하기/"},"frontmatter":{"title":"Object - 8장 의존성 관리하기","thumbnail":{"childImageSharp":{"fluid":{"src":"/static/dd0e1990925e942697544e2bdcd9332e/9b73b/object.png"}}},"draft":false,"category":"Back-End","tags":["java"],"date":"October 15, 2023"}},"node":{"id":"5c30d890-7e1f-5638-9630-e5d1dea7f6c9","html":"<p>사람의 기억은 단기 기억과 장기 기억으로 분류할 수 있다. 실제로 문제를 해결하기 위해 사용하는 저장소는 장기 기억이 아니라 단기 기억이다.</p>\n<ul>\n<li>인지 과부하(cognitive overload): 문제 해결에 필요한 요소의 수가 단기 기억의 용량을 초과하는 순간 문제 해결 능력이 급격하게 떨어지는 것</li>\n<li>인지 과부하를 줄이는 가장 좋은 방법은 단기 기억 안에 보관할 정보의 양을 조절하는 것\n<ul>\n<li>추상화: 불필요한 정보를 제거하고 현재의 문제 해결에 필요한 핵심만 남기는 작업</li>\n<li>분해(decomposition): 큰 문제를 해결 가능한 작은 문제로 나누는 작업</li>\n</ul>\n</li>\n</ul>\n<blockquote>\n<p>한 번에 단기 기억에 담을 수 있는 추상화의 수에는 한계가 있지만 추상화를 더 큰 규모의 추상화로 압축시킴으로써 단기 기억의 한계를 초월할 수 있다.</p>\n</blockquote>\n<h2 id=\"-71-프로시저-추상화와-데이터-추상화\" style=\"position:relative;\"><a href=\"#-71-%ED%94%84%EB%A1%9C%EC%8B%9C%EC%A0%80-%EC%B6%94%EC%83%81%ED%99%94%EC%99%80-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B6%94%EC%83%81%ED%99%94\" aria-label=\" 71 프로시저 추상화와 데이터 추상화 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 7.1 프로시저 추상화와 데이터 추상화</h2>\n<p>모든 프로그래밍 패러다임은 추상화와 분해의 관점에서 설명할 수 있다.</p>\n<ol>\n<li>프로시저 추상화\n<ul>\n<li>소프트웨어가 무엇을 해야하는지를 추상화</li>\n<li>프로시저 추상화를 중심으로 시스템을 분해한다면 기능 분해(알고리즘 분해)</li>\n</ul>\n</li>\n<li>데이터 추상화\n<ul>\n<li>소프트웨어가 무엇을 알아야 하는지를 추상화</li>\n<li>데이터 추상화를 중심으로 시스템을 분해한다면 <strong>타입을 추상화(추상 데이터 타입)</strong> 하거나 <strong>프로시저를 추상화(객체지향)</strong> 해야한다.</li>\n</ul>\n</li>\n</ol>\n<p><code>협력하는 공동체</code>를 구성하도록 객체들로 나누는 과정이 바로 객체지향 패러다임에서의 분해를 의미</p>\n<h2 id=\"-72-프로시저-추상화와-기능-분해\" style=\"position:relative;\"><a href=\"#-72-%ED%94%84%EB%A1%9C%EC%8B%9C%EC%A0%80-%EC%B6%94%EC%83%81%ED%99%94%EC%99%80-%EA%B8%B0%EB%8A%A5-%EB%B6%84%ED%95%B4\" aria-label=\" 72 프로시저 추상화와 기능 분해 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 7.2 프로시저 추상화와 기능 분해</h2>\n<h3 id=\"-721-메인-함수로의-시스템\" style=\"position:relative;\"><a href=\"#-721-%EB%A9%94%EC%9D%B8-%ED%95%A8%EC%88%98%EB%A1%9C%EC%9D%98-%EC%8B%9C%EC%8A%A4%ED%85%9C\" aria-label=\" 721 메인 함수로의 시스템 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 7.2.1 메인 함수로의 시스템</h3>\n<p>기능 분해의 관점에서 추상화의 단위는 프로시저이며 시스템은 프로시저를 단위로 분해</p>\n<ul>\n<li>프로시저는 반복적으로 실행되거나 거의 유사하게 실행되는 작업들을 하나의 장소에 모아놓음으로써 로직을 재사용하고 중복을 방지할 수 있는 추상화 방법</li>\n<li>프로시저는 잠재적으로 정보은닉의 가능성을 제시</li>\n</ul>\n<blockquote>\n<p>시스템은 필요한 더 작은 작업으로 분해될 수 있는 하나의 커다란 메인 함수다.</p>\n</blockquote>\n<p>전통적인 기능 분해 방법은 **하향식 접근법(Top-Down Approach)**을 따른다.</p>\n<ul>\n<li>가장 최상위 기능을 정의하고, 이 기능을 좀 더 작은 단계의 하위 기능으로 분해해 나가는 방법</li>\n<li>분해는 세분화된 마지막 하위 기능이 프로그래밍 언어로 구현 가능한 수준이 될 때까지 계속된다.</li>\n</ul>\n<h3 id=\"-722-급여-관리-시스템\" style=\"position:relative;\"><a href=\"#-722-%EA%B8%89%EC%97%AC-%EA%B4%80%EB%A6%AC-%EC%8B%9C%EC%8A%A4%ED%85%9C\" aria-label=\" 722 급여 관리 시스템 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 7.2.2 급여 관리 시스템</h3>\n<p><code>급여 = 기본급 - (기본급 * 소득세율)</code></p>\n<p><code>직원의 급여를 계산한다</code></p>\n<ul>\n<li>급여 관리 시스템에 대한 추상적인 최상위 문장</li>\n</ul>\n<deckgo-highlight-code language=\"text\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">직원의 급여를 계산한다\n  사용자로부터 소득세율을 입력받는다.\n  직원의 급여를 계산한다.\n  양식에 맞게 결과를 출력한다.</code>\n        </deckgo-highlight-code>\n<ul>\n<li>세부적인 절차로 구체화</li>\n</ul>\n<deckgo-highlight-code language=\"text\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">직원의 급여를 계산한다\n  사용자로부터 소득세율을 입력받는다.\n    &quot;세율을 입력하세요: &quot;라는 문장을 화면에 출력한다.\n    키보드를 통해 세율을 입력받는다.\n  직원의 급여를 계산한다.\n    전역 변수에 저장된 직원의 기본급 정보를 얻는다.\n    급여를 계산한다.\n  양식에 맞게 결과를 출력한다.\n    &quot;이름: {직원명}, 급여: {계산된 금액}&quot; 형식에 다라 출력 문자열을 생성한다.</code>\n        </deckgo-highlight-code>\n<ul>\n<li>기능 분해의 결과</li>\n<li>입력 정보는 직원정보와 소득세율이고 출력은 계산된 급여 정보</li>\n</ul>\n<h3 id=\"-723-급여-관리-시스템-구현\" style=\"position:relative;\"><a href=\"#-723-%EA%B8%89%EC%97%AC-%EA%B4%80%EB%A6%AC-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EA%B5%AC%ED%98%84\" aria-label=\" 723 급여 관리 시스템 구현 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 7.2.3 급여 관리 시스템 구현</h3>\n<p>루비 언어를 기반으로 예시를 든다.</p>\n<p><code>직원의 급여를 계산한다</code></p>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">def main(name)\nend</code>\n        </deckgo-highlight-code>\n<ul>\n<li>최상위 문장은 하나의 메인 함수로 매핑된다.</li>\n</ul>\n<deckgo-highlight-code language=\"text\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">  사용자로부터 소득세율을 입력받는다.\n  직원의 급여를 계산한다.\n  양식에 맞게 결과를 출력한다.</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">def main(name)\n  taxRate = getTaxRate()\n  pay = calculatePayFor(name, taxRate)\n  puts(describeResult(name, pay))\nend</code>\n        </deckgo-highlight-code>\n<ul>\n<li>각 문장에 대응된다.</li>\n</ul>\n<deckgo-highlight-code language=\"text\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">  사용자로부터 소득세율을 입력받는다.\n    &quot;세율을 입력하세요: &quot;라는 문장을 화면에 출력한다.\n    키보드를 통해 세율을 입력받는다.</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">def getTaxRate()\n  print(&quot;세율을 입력하세요: &quot;)\n  return gets().chomp().to_f()\nend</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"text\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">  직원의 급여를 계산한다.\n    전역 변수에 저장된 직원의 기본급 정보를 얻는다.\n    급여를 계산한다.</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">$employees = [&quot;직원A&quot;, &quot;직원B&quot;, &quot;직원C&quot;]\n$basePays = [400, 300, 250]</code>\n        </deckgo-highlight-code>\n<ul>\n<li>동일한 직원에 대한 이름과 기본급 정보는 두 배열 내의 동일한 인덱스에 저장</li>\n</ul>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">def calculatePayFor(name, taxRate)\n  index = $imployees.index(name)\n  basePay = $basePays[index]\n  return basePay - (basePay * taxRate)\nend</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"text\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">  양식에 맞게 결과를 출력한다.\n    &quot;이름: {직원명}, 급여: {계산된 금액}&quot; 형식에 다라 출력 문자열을 생성한다.</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">def describeResult(name, pay)\n  return &quot;이름: #{name}, 급여: #{pay}&quot;\nend</code>\n        </deckgo-highlight-code>\n<p>하향식 기능 분해 방식으로 설계한 시스템은 메인 함수를 루트로 하는 '트리(tree)'로 표현할 수 있다. 체계적이고 이상적으로 보이지만 우리가 사는 세계는 그렇게 체계적이지도, 이상적이지도 않다.</p>\n<h3 id=\"-724-하향식-기능-분해의-문제점\" style=\"position:relative;\"><a href=\"#-724-%ED%95%98%ED%96%A5%EC%8B%9D-%EA%B8%B0%EB%8A%A5-%EB%B6%84%ED%95%B4%EC%9D%98-%EB%AC%B8%EC%A0%9C%EC%A0%90\" aria-label=\" 724 하향식 기능 분해의 문제점 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 7.2.4 하향식 기능 분해의 문제점</h3>\n<ul>\n<li>시스템은 하나의 메인 함수로 구성돼 있지 않다.</li>\n<li>기능 추가나 요구사항 변경으로 인해 메인 함수를 빈번하게 수정해야 한다.</li>\n<li>비즈니스 로직이 사용자 인터페이스와 강하게 결합된다.</li>\n<li>하향식 분해는 너무 이른 시기에 함수들의 실행 순서를 고정시키기 때문에 유연성과 재사용성이 저하된다.</li>\n<li>데이터 형식이 변경될 경우 파급효과를 예측할 수 없다.</li>\n</ul>\n<h4 id=\"-하나의-메인-함수라는-비현실적인-아이디어\" style=\"position:relative;\"><a href=\"#-%ED%95%98%EB%82%98%EC%9D%98-%EB%A9%94%EC%9D%B8-%ED%95%A8%EC%88%98%EB%9D%BC%EB%8A%94-%EB%B9%84%ED%98%84%EC%8B%A4%EC%A0%81%EC%9D%B8-%EC%95%84%EC%9D%B4%EB%94%94%EC%96%B4\" aria-label=\" 하나의 메인 함수라는 비현실적인 아이디어 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🛠 하나의 메인 함수라는 비현실적인 아이디어</h4>\n<ul>\n<li>어떤 시스템도 최초에 release됐던 당시의 모습을 그대로 유지하지는 않는다. 즉, 지속적으로 새로운 기능을 추가하게 된다.</li>\n<li>대부분의 추가되는 기능은 메인 함수의 일부가 아닐 것이다. 결국 어느 시점에 이르면 유일한 메인 함수라는 개념은 의미가 없어지고 시스템은 여러 개의 동등한 수준의 함수 집합으로 성장하게 될 것이다.</li>\n<li>하향식 접근법은 하나의 알고리즘을 구현하거나 배치 처리를 구현하기에는 적합하지만 현대적인 상호작용 시스템을 개발하는 데는 적합하지 않다.</li>\n</ul>\n<blockquote>\n<p>실제 시스템에 정상(top)이란 존재하지 않는다.      - 버트란드 마이어</p>\n</blockquote>\n<h4 id=\"-메인-함수의-빈번한-재설계\" style=\"position:relative;\"><a href=\"#-%EB%A9%94%EC%9D%B8-%ED%95%A8%EC%88%98%EC%9D%98-%EB%B9%88%EB%B2%88%ED%95%9C-%EC%9E%AC%EC%84%A4%EA%B3%84\" aria-label=\" 메인 함수의 빈번한 재설계 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🛠 메인 함수의 빈번한 재설계</h4>\n<ul>\n<li>기존 로직과는 아무런 상관이 없는 새로운 함수의 적절한 위치를 확보해야 하기 때문에 메인 함수의 구조를 급격하게 변경할 수밖에 없다.</li>\n</ul>\n<p>급여 관리 시스템에 모든 직원들의 기본급의 총합을 구하는 기능을 추가해 달라는 새로운 요구사항이 접수됐다고 가정</p>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">def sumOfBasePays()\n  result = 0\n  for basePay in $basePays\n    result += basePay\n  end\n  puts(result)\nend</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">def main(name)\n  taxRate = getTaxRate()\n  pay = calculatePayFor(name, taxRate)\n  puts(describeResult(name, pay))\nend</code>\n        </deckgo-highlight-code>\n<ul>\n<li>메인함수 안에서 호출할 자리가 마땅치 않다.</li>\n</ul>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">def calculatePay(name)\n  taxRate = getTaxRate()\n  pay = calculatePayFor(name, taxRate)\n  puts(describeResult(name, pay))\nend</code>\n        </deckgo-highlight-code>\n<ul>\n<li>메인함수를 <code>calcuatePay</code> 함수로 옮기자</li>\n</ul>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">def main(operation, args={})\n  case(operation)\n  when :pay then calculatePay(args[:name])\n  when :basePays then sumOfBasePays()\n  end\nend</code>\n        </deckgo-highlight-code>\n<ul>\n<li>인자에 따라 다른 함수를 호출</li>\n<li>결과적으로 기존 코드의 빈번한 수정으로 인한 버그 발생 확률이 높아지기 때문에 시스템 변경에 취약해질 수 밖에 없다.</li>\n</ul>\n<h4 id=\"-비즈니스-로직과-사용자-인터페이스의-결합\" style=\"position:relative;\"><a href=\"#-%EB%B9%84%EC%A6%88%EB%8B%88%EC%8A%A4-%EB%A1%9C%EC%A7%81%EA%B3%BC-%EC%82%AC%EC%9A%A9%EC%9E%90-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EC%9D%98-%EA%B2%B0%ED%95%A9\" aria-label=\" 비즈니스 로직과 사용자 인터페이스의 결합 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🛠 비즈니스 로직과 사용자 인터페이스의 결합</h4>\n<ul>\n<li>비즈니스 로직을 설계하는 초기 단계부터 입력 방법과 출력 양식을 함께 고민하도록 강요</li>\n<li>코드 안에서 비즈니스 로직과 사용자 인터페이스 로직이 밀접하게 결합\n<ul>\n<li>사용자 인터페이스가 변경되는 빈번도 ⏫</li>\n<li>비즈니스 로직이 변경되는 빈번도 ⏬</li>\n<li>사용자 인터페이스가 변경되는 경우 비즈니스 로직까지 변경에 영향을 받음</li>\n<li>근본적으로 변경에 불안정한 아키텍처를 낳는다.</li>\n</ul>\n</li>\n<li>하향식 접근법은 기능을 분해하는 과정에서 사용자 인터페이스의 관심사와 비즈니스 로직의 관심사를 동시에 고려하도록 강요하기 때문에 \"관심사의 분리\"라는 아키텍처 설계의 목적을 달성하기 어렵다.</li>\n</ul>\n<h4 id=\"-성급하게-결정된-실행-순서\" style=\"position:relative;\"><a href=\"#-%EC%84%B1%EA%B8%89%ED%95%98%EA%B2%8C-%EA%B2%B0%EC%A0%95%EB%90%9C-%EC%8B%A4%ED%96%89-%EC%88%9C%EC%84%9C\" aria-label=\" 성급하게 결정된 실행 순서 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🛠 성급하게 결정된 실행 순서</h4>\n<ul>\n<li>하향식 기능 분해는 설계를 시작하는 시점에서 시스템이 무엇(what)을 해야 하는지가 아니라 어떻게(how) 동작해야 하는지에 집중하도록 만든다.</li>\n<li>처음부터 구현을 염두에 두기 때문에 함수들의 실행 순서를 정의하는 시간 제약을 강조</li>\n<li>중앙집중 제어 스타일의 형태를 띈다.</li>\n<li>하향식 접근법을 통해 분해한 함수들은 재사용이 어렵다.</li>\n</ul>\n<p>하향식 설계와 관련된 모든 문제의 원인은 <strong>결합도</strong> ❗️</p>\n<ul>\n<li>전체 시스템의 핵심적인 구조를 결정하는 함수들이 데이터와 강하게 결합된다는 것</li>\n</ul>\n<h4 id=\"-데이터-변경으로-인한-파급효과\" style=\"position:relative;\"><a href=\"#-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B3%80%EA%B2%BD%EC%9C%BC%EB%A1%9C-%EC%9D%B8%ED%95%9C-%ED%8C%8C%EA%B8%89%ED%9A%A8%EA%B3%BC\" aria-label=\" 데이터 변경으로 인한 파급효과 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🛠 데이터 변경으로 인한 파급효과</h4>\n<ul>\n<li>하향식 기능 분해의 가장 큰 문제점은 어떤 데이터를 어떤 함수가 사용하고 있는지를 추적하기 어렵다는 것이다.\n<ul>\n<li>데이터 변경으로 인해 어떤 함수가 영향을 받을지 예상하기 어렵다.</li>\n</ul>\n</li>\n</ul>\n<p>정규 직원의 급여뿐만 아니라 아르바이트 직원에 대한 급여도 관리를 할 수 있도록 해달라는 변경 요청이 왔다고 가정</p>\n<ul>\n<li>아르바이트 직원은 시간에 시급을 곱한 금액만큼을 지급</li>\n</ul>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">$employees = [&quot;직원A&quot;, &quot;직원B&quot;, &quot;직원C&quot;, &quot;아르바이트D&quot;, &quot;아르바이트E&quot;, &quot;아르바이트F&quot;]\n$basePays = [400, 300, 250, 1, 1, 1.5]\n$hourlys = [false, false, false, true, true, true]\n$timeCards = [0, 0, 0, 120, 120, 120]</code>\n        </deckgo-highlight-code>\n<ul>\n<li>hourlys: true: 아르바이트, false: 정규직원</li>\n<li>timeCards: 한달 간의 업무 누적 시간</li>\n</ul>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">def calculateHourlyPayFor(name, taxRate)\n  index = $imployees.index(name)\n  basePay = $basePays[index] * $timeCards[index]\n  return basePay - (basePay * taxRate)\nend</code>\n        </deckgo-highlight-code>\n<ul>\n<li>아르바이트 직원의 급여를 계산하는 함수</li>\n</ul>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">def hourly?(name)\n  return $hourlys[$employees.index(name)]\nend</code>\n        </deckgo-highlight-code>\n<ul>\n<li>정규직원과 아르바이트 직원을 판단하는 함수</li>\n</ul>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">def calculatePay(name)\n  taxRate = getTaxRate()\n  if (hourly?(name)) then\n    pay = calculateHourlyPayFor(name, taxRate)\n  else\n    pay = calculatePayFor(name, taxRate)\n  end\n  puts(describeResult(name, pay))\nend</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">def sumOfBasePays()\n  result = 0\n  for name in $employees\n    if (not hourly?(name)) then\n      result += $basePays[$employees.index(name)]\n    end\n  end\n  puts(result)\nend</code>\n        </deckgo-highlight-code>\n<p>이처럼 데이터 변경으로 인해 발생하는 함수에 대한 영향도를 파악하는 것이 쉽지 않다.</p>\n<ul>\n<li>변경에 대한 영향을 최소화하기 위해 영향을 받는 부분과 받지 않는 부분을 명확하게 분리하고 잘 정의된 퍼블릭 인터페이스를 통해 변경되는 부분에 대한 접근을 통제하는 것이 의존성 관리의 핵심이다.</li>\n</ul>\n<h3 id=\"-725-언제-하향식-분해가-유용한가\" style=\"position:relative;\"><a href=\"#-725-%EC%96%B8%EC%A0%9C-%ED%95%98%ED%96%A5%EC%8B%9D-%EB%B6%84%ED%95%B4%EA%B0%80-%EC%9C%A0%EC%9A%A9%ED%95%9C%EA%B0%80\" aria-label=\" 725 언제 하향식 분해가 유용한가 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 7.2.5 언제 하향식 분해가 유용한가?</h3>\n<p>하향식 설계는 설계가 어느 정도 안정화 된 후에는 설계의 다양한 측면을 논리적으로 설명하고 문서화하기에 용이하다.</p>\n<blockquote>\n<p>하향식은 이미 완전히 이해된 사실을 서술하기에 적합한 방법이다.</p>\n</blockquote>\n<ul>\n<li>하향식 분해는 작은 프로그램과 개별 알고리즘을 위해서는 유용하다.</li>\n<li>이미 해결된 알고리즘을 문서화하고 서술하는 데 유용하다.</li>\n</ul>\n<h2 id=\"-73-모듈\" style=\"position:relative;\"><a href=\"#-73-%EB%AA%A8%EB%93%88\" aria-label=\" 73 모듈 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 7.3 모듈</h2>\n<h3 id=\"-731-정보-은닉과-모듈\" style=\"position:relative;\"><a href=\"#-731-%EC%A0%95%EB%B3%B4-%EC%9D%80%EB%8B%89%EA%B3%BC-%EB%AA%A8%EB%93%88\" aria-label=\" 731 정보 은닉과 모듈 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 7.3.1 정보 은닉과 모듈</h3>\n<p><strong>정보 은닉</strong>은 시스템을 모듈 단위로 분해하기 위한 기본 원리로 시스템에서 자주 변경되는 부분을 상대적으로 덜 변경되는 안정적인 인터페이스 뒤로 감춰야 한다는 것이 핵심이다.</p>\n<blockquote>\n<p>모듈은 서브 프로그램이라기보다는 책임의 할당이다.</p>\n</blockquote>\n<ul>\n<li>기능 분해는 하나의 기능을 구현하기 위해 필요한 기능들을 순차적으로 찾아가는 탐색의 과정</li>\n<li>모듈 분해는 감춰야 하는 비밀을 선택하고 비밀 주변에 안정적인 보호막을 설치하는 보존의 과정</li>\n</ul>\n<p>모듈이 감춰야 할 비밀</p>\n<ol>\n<li>복잡성</li>\n<li>변경 가능성</li>\n</ol>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">module Employees\n  $employees = [&quot;직원A&quot;, &quot;직원B&quot;, &quot;직원C&quot;, &quot;아르바이트D&quot;, &quot;아르바이트E&quot;, &quot;아르바이트F&quot;]\n  $basePays = [400, 300, 250, 1, 1, 1.5]\n  $hourlys = [false, false, false, true, true, true]\n  $timeCards = [0, 0, 0, 120, 120, 120]\n\n  def Employees.calculatePay(name, taxRate)\n    if (Employees.hourly?(name)) then\n      pay = calculateHourlyPayFor(name, taxRate)\n    else\n      pay = calculatePayFor(name, taxRate)\n    end\n  end\n\n  def Employees.hourly?(name)\n    return $hourlys[$employees.index(name)]\n  end\n\n  def Employees.calculateHourlyPayFor(name, taxRate)\n    index = $imployees.index(name)\n    basePay = $basePays[index] * $timeCards[index]\n    return basePay - (basePay * taxRate)\n  end\n\n  def Employees.calculatePayFor(name, taxRate)\n    return basePay - (basePay * taxRate)\n  end\n\n  def Employees.sumOfBasePays()\n    result = 0\n    for name in $employees\n      if (not Employees.hourly?(name)) then\n        result += $basePays[$employees.index(name)]\n      end\n    end\n    return result\n  end</code>\n        </deckgo-highlight-code>\n<ul>\n<li>ruby 언어는 <code>module</code>이라는 키워드를 제공하지만 모듈은 키워드의 지원 여부와 상관없이 적용할 수 있는 논리적인 개념이다.</li>\n<li>모듈 외부에서는 모듈 내부에 어떤 데이터가 존재하는지 알 수 없다.</li>\n</ul>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">def main(operation, args={})\n  case(operation)\n  when :pay then calculatePay(args[:name])\n  when :basePays then sumOfBasePays()\n  end\nend\n\ndef calculatePay(name)\n  taxRate = getTaxRate()\n  pay = Employees.calculatePayFor(name, taxRate)\n  puts(describeResult(name, pay))\nend\n\ndef getTaxRate()\n  print(&quot;세율을 입력하세요: &quot;)\n  return gets().chomp().to_f()\nend\n\ndef describeResult(name, pay)\n  return &quot;이름: #{name}, 급여: #{pay}&quot;\nend\n\ndef sumOfBasePays()\n  puts(Employees.sumOfBasePays())\nend</code>\n        </deckgo-highlight-code>\n<h3 id=\"-732-모듈의-장점과-한계\" style=\"position:relative;\"><a href=\"#-732-%EB%AA%A8%EB%93%88%EC%9D%98-%EC%9E%A5%EC%A0%90%EA%B3%BC-%ED%95%9C%EA%B3%84\" aria-label=\" 732 모듈의 장점과 한계 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 7.3.2 모듈의 장점과 한계</h3>\n<p>모듈의 장점</p>\n<ul>\n<li>모듈 내부의 변수가 변경되더라도 모듈 내부에만 영향을 미친다.\n<ul>\n<li>데이터 변경으로 인한 파급효과를 제어할 수 있으므로 코드를 수정하고 디버깅이 용이</li>\n</ul>\n</li>\n<li>비즈니스 로직과 사용자 인터페이스에 대한 관심사를 분리한다.\n<ul>\n<li>사용자 인터페이스가 변경되어도 비즈니스 로직은 변경되지 않는다.</li>\n</ul>\n</li>\n<li>전역 변수와 전역 함수를 제거함으로써 네임스페이스 오염을 방지한다.\n<ul>\n<li>모듈은 네임스페이스를 제공</li>\n<li>이름 충돌의 위험 방지</li>\n</ul>\n</li>\n</ul>\n<p>모듈은 기능이 아니라 변경의 정도에 따라 시스템을 분해하게 한다.</p>\n<ul>\n<li>높은 응집도\n<ul>\n<li>비밀과 관련성 높은 데이터의 집합</li>\n</ul>\n</li>\n<li>낮은 결합도\n<ul>\n<li>모듈과 모듈은 퍼블릭 인터페이스를 통해서만 통신</li>\n</ul>\n</li>\n</ul>\n<p>모듈은 데이터와 함수가 통합된 한 차원 높은 추상화를 제공하는 설계 단위이다 ❗️</p>\n<p>모듈의 가장 큰 단점은 인스턴스의 개념을 제공하지 않는다는 점이다. 다수의 직원 인스턴스가 존재하는 추상화 메커니즘이 추상 데이터 타입이다.</p>\n<h2 id=\"-74-데이터-추상화와-추상-데이터-타입\" style=\"position:relative;\"><a href=\"#-74-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%B6%94%EC%83%81%ED%99%94%EC%99%80-%EC%B6%94%EC%83%81-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85\" aria-label=\" 74 데이터 추상화와 추상 데이터 타입 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 7.4 데이터 추상화와 추상 데이터 타입</h2>\n<h3 id=\"-741-추상-데이터-타입\" style=\"position:relative;\"><a href=\"#-741-%EC%B6%94%EC%83%81-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85\" aria-label=\" 741 추상 데이터 타입 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 7.4.1 추상 데이터 타입</h3>\n<p>프로그래밍 언어에서 <strong>타입(type)</strong> 이란 변수에 저장할 수 있는 내용물의 종류와 변수에 적용될 수 있는 연산의 가짓수를 의미한다.</p>\n<p>추상 데이터 타입을 구현하려면 다음과 같은 특성을 위한 프로그래밍 언어의 지원이 필요하다.</p>\n<ul>\n<li>타입 정의를 선언할 수 있어야 한다.</li>\n<li>타입의 인스턴스를 다루기 위해 사용할 수 있는 오퍼레이션의 집합을 정의할 수 있어야 한다.</li>\n<li>제공된 오퍼레이션을 통해서만 조작할 수 있도록 데이터를 외부로부터 보호할 수 있어야 한다.</li>\n<li>타입에 대해 여러 개의 인스턴스를 생성할 수 있어야 한다.</li>\n</ul>\n<p>리스코프는 추상 데이터 타입을 정의하기 위해 제시한 언어적인 메커니즘을 오퍼레이션 클러스터라고 불렀다.</p>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">Employee = Struct.new(:name, :basePay, :hourly, :timeCard) do\nEnd</code>\n        </deckgo-highlight-code>\n<ul>\n<li>개별 직원을 위한 추상 데이터 타입</li>\n</ul>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">Employee = Struct.new(:name, :basePay, :hourly, :timeCard) do\n  def calculatePay(taxRate)\n    if (hourly) then\n      return calculateHourlyPayFor(taxRate)\n    end\n    return calculateSalariedFor(taxRate)\n  end\n\nprivate\n  def calculateHourlyPayFor(taxRate)\n    return (basePay * timeCard) - (basePay * timeCard) * taxRate\n  end\n\n  def calculateSalariedFor(taxRate)\n    return basePay - (basePay * taxRate)\n  end\nend</code>\n        </deckgo-highlight-code>\n<ul>\n<li>직원을 지정하지 않아도 된다.</li>\n</ul>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">Employee = Struct.new(:name, :basePay, :hourly, :timeCard) do\n  def monthlyBasePay()\n    if (hourly) then return 0 end\n    return basePay\n  end\nend</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">$employees = [\n    Employee.new(&quot;직원A&quot;, 400, false, 0),\n    Employee.new(&quot;직원B&quot;, 300, false, 0),\n    Employee.new(&quot;직원C&quot;, 200, false, 0),\n    Employee.new(&quot;아르바이트D&quot;, 1, true, 120),\n    Employee.new(&quot;아르바이트E&quot;, 1, true, 120),\n    Employee.new(&quot;아르바이트F&quot;, 1, true, 120),\n]</code>\n        </deckgo-highlight-code>\n<ul>\n<li>직원들의 인스턴스</li>\n</ul>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">def calculatePay(name)\n  taxRate = getTaxRate()\n  for each in $employees\n    if (each.name === name) then employee = each; break end\n  end\n  pay = employee. calculatePay(taxRate)\n  puts(describeResult(name, pay))\nend</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">def sumOfBasePays()\n  result = 0\n  for each in $employees\n    result += each.monthlyBasePay()\n  end\n  puts(result)\nend</code>\n        </deckgo-highlight-code>\n<ul>\n<li>추상 데이터 타입은 사람들이 세상을 바라보는 방식에 좀 더 근접해지도록 추상화 수준을 향상시킨다.</li>\n<li>여전히 데이터와 기능을 분리해서 바라본다.</li>\n<li>추상 데이터 타입은 말 그대로 시스템의 상태를 저장할 데이터를 표현한다.</li>\n</ul>\n<p>추상 데이터 타입의 기본 의도는 프로그래밍 언어가 제공하는 타입처럼 동작하는 사용자 정의 타입을 추가할 수 있게 하는 것</p>\n<h2 id=\"-75-클래스\" style=\"position:relative;\"><a href=\"#-75-%ED%81%B4%EB%9E%98%EC%8A%A4\" aria-label=\" 75 클래스 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 7.5 클래스</h2>\n<h3 id=\"-751-클래스는-추상-데이터-타입인가\" style=\"position:relative;\"><a href=\"#-751-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%8A%94-%EC%B6%94%EC%83%81-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85%EC%9D%B8%EA%B0%80\" aria-label=\" 751 클래스는 추상 데이터 타입인가 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 7.5.1 클래스는 추상 데이터 타입인가?</h3>\n<p>클래스와 추상 데이터 타입 모두 데이터 추상화를 기반으로 시스템을 분해한다. 그러나 명확한 의미에서 추상 데이터 타입과 클래스는 동일하지 않다.</p>\n<ul>\n<li>클래스는 상속과 다형성을 지원(객체지향 프로그래밍)하지만 추상 데이터 타입은 지원하지 못한다(객체기반 프로그래밍).</li>\n</ul>\n<p>하나의 대표적인 타입이 다수의 세부적인 타입을 감추기 때문에 이를 타입 추상화라 부른다.</p>\n<ul>\n<li>Employee 타입은 직원 타입과 아르바이트 타입이 있다.</li>\n<li>타입 추상화를 기반으로 하는 대표적인 기법이 바로 추상 데이터 타입이다.</li>\n</ul>\n<p>추상 데이터 타입이 오퍼레이션을 기준으로 타입을 묶는 방법이라면 객체지향은 타입을 기준으로 오퍼레이션을 묶는다.</p>\n<ul>\n<li>클래스를 이용한 다형성은 절차에 대한 차이점을 감춘다.</li>\n<li>객체 지향은 <strong>절차 추상화</strong>다.</li>\n</ul>\n<h3 id=\"-752-추상-데이터-타입에서-클래스로-변경하기\" style=\"position:relative;\"><a href=\"#-752-%EC%B6%94%EC%83%81-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85%EC%97%90%EC%84%9C-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%A1%9C-%EB%B3%80%EA%B2%BD%ED%95%98%EA%B8%B0\" aria-label=\" 752 추상 데이터 타입에서 클래스로 변경하기 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 7.5.2 추상 데이터 타입에서 클래스로 변경하기</h3>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class Employee\n  attr_reader :name, :basePay\n\n  def initialize(name, basePay)\n    @name = name\n    @basePay = basePay\n  end\n\n  def calculatePay(taxRate)\n    raise NotImplementedError\n  end\n\n  def monthlyBasePay()\n    raise NotImplementedError\n  end\nend</code>\n        </deckgo-highlight-code>\n<ul>\n<li>java 기준으로 보면 <code>Employee</code> class는 추상 클래스, <code>calculatePay</code>, <code>monthlyBasePay</code>는 추상 메서드이다.</li>\n</ul>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class SalariedEmployee &lt; Employee\n  def initialize(name, basePay)\n    super(name, basePay)\n  end\n\n  def calculatePay(taxRate)\n    return basePay - (basePay * taxRate)\n  end\n\n  def monthlyBasePay()\n    return basePay\n  end\nend</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class HourlyEmployee &lt; Employee\n  attr_reader :timeCard\n  def initialize(name, basePay, timeCard)\n    super(name, basePay)\n    @timeCard = timeCard\n  end\n\n  def calculatePay(taxRate)\n    return (basePay * timeCard) - (basePay * timeCard) * taxRate\n  end\n\n  def monthlyBasePay()\n    return 0\n  end\nend</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">$employees = [\n    SalariedEmployee.new(&quot;직원A&quot;, 400),\n    SalariedEmployee.new(&quot;직원B&quot;, 300),\n    SalariedEmployee.new(&quot;직원C&quot;, 200),\n    HourlyEmployee.new(&quot;아르바이트D&quot;, 1, 120),\n    HourlyEmployee.new(&quot;아르바이트E&quot;, 1, 120),\n    HourlyEmployee.new(&quot;아르바이트F&quot;, 1, 120),\n]</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"ruby\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">def sumOfBasePays()\n  result = 0\n  for each in $employees\n    result += each.monthlyBasePay()\n  end\n  puts(result)\nend</code>\n        </deckgo-highlight-code>\n<ul>\n<li>메시지를 수신한 객체는 자신의 클래스에 구현된 메서드를 이용해 적절하게 반응할 수 있다.</li>\n</ul>\n<h3 id=\"-753-변경을-기준으로-선택하라\" style=\"position:relative;\"><a href=\"#-753-%EB%B3%80%EA%B2%BD%EC%9D%84-%EA%B8%B0%EC%A4%80%EC%9C%BC%EB%A1%9C-%EC%84%A0%ED%83%9D%ED%95%98%EB%9D%BC\" aria-label=\" 753 변경을 기준으로 선택하라 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 7.5.3 변경을 기준으로 선택하라</h3>\n<p>비록 클래스를 사용하고 있더라도 타입을 기준으로 절차를 추상화하지 않았다면 그것은 객체지향 분해가 아니다.</p>\n<ul>\n<li>클래스가 추상 데이터 타입의 개념을 다르는지를 확인할 수 있는 가장 간단한 방법은 클래스 내부에 인스턴스의 타입을 표현하는 변수가 있는지를 살펴보는 것</li>\n<li>객체지향에서는 타입 변수를 이용한 조건문을 다형성으로 대체</li>\n</ul>\n<p>개방-폐쇄 원칙(Open-Closed Principle, OCP)</p>\n<ul>\n<li>기존 코드에 아무런 영향도 미치지 않고 새로운 객체 유형과 행위를 추가할 수 있는 객체지향의 특성</li>\n<li>대부분의 객체지향 서적에서는 추상 데이터 타입을 기반으로 애플리케이션을 설계하는 방식을 잘못된 것으로 설명한다.\n<ul>\n<li>설계에 요구되는 변경의 압력이 '타입 추가'에 관한 것인지, 아니면 '오퍼레이션 추가'에 관한 것인지에 따라 달라진다.</li>\n<li>새로운 타입을 빈번하게 추가해야 한다면 객체지향의 클래스 구조가 더 유용</li>\n<li>새로운 오퍼레이션을 빈번하게 추가해야 한다면 추상 데이터 타입이 더 유용</li>\n</ul>\n</li>\n</ul>\n<h3 id=\"-754-협력이-중요하다\" style=\"position:relative;\"><a href=\"#-754-%ED%98%91%EB%A0%A5%EC%9D%B4-%EC%A4%91%EC%9A%94%ED%95%98%EB%8B%A4\" aria-label=\" 754 협력이 중요하다 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 7.5.4 협력이 중요하다</h3>\n<p>협력이라는 문맥을 고려하지 않고 객체를 고립시킨 채 오퍼레이션의 구현 방식을 타입별로 분배하는 것은 올바른 접근법이 아니다.</p>\n<p>객체가 참여할 협력을 결정하고 협력에 필요한 책임을 수행하기 위해 어떤 객체가 필요한지에 관해 고민하라.</p>\n<ul>\n<li>그 책임을 다양한 방식으로 수행해야 할 때만 타입 계층 안에 각 절차를 추상화하라.</li>\n<li>타입 계층과 다형성은 협력이라는 문맥 안에서 책임을 수행하는 방법에 관해 고민한 결과물이어야 하며 그 자체가 목적이 되어서는 안 된다.</li>\n</ul>","excerpt":"사람의 기억은 단기 기억과 장기 기억으로 분류할 수 있다. 실제로 문제를 해결하기 위해 사용하는 저장소는 장기 기억이 아니라 단기 기억이다. 인지 과부하(cognitive overload): 문제 해결에 필요한 요소의 수가 단기 기억의 용량을 초과하는 순간 문제 해결 능력이 급격하게 떨어지는 것 인지 과부하를 줄이는 가장 좋은 방법은 단기 기억 안에 보관할 정보의 양을 조절하는 것 추상화: 불필요한 정보를 제거하고 현재의 문제 해결에 필요한 핵심만 남기는 작업 분해(decomposition…","fields":{"slug":"/backend/object/chapter7/객체_분해/"},"frontmatter":{"title":"Object - 7장 객체 분해","thumbnail":{"childImageSharp":{"fluid":{"src":"/static/dd0e1990925e942697544e2bdcd9332e/9b73b/object.png"}}},"draft":false,"category":"Back-End","tags":["java"],"date":"October 08, 2023"}}}},"staticQueryHashes":["2374173507","2996537568","3691437124"]}