{"componentChunkName":"component---src-containers-post-index-tsx","path":"/backend/object/chapter9/유연한_설계/","result":{"pageContext":{"next":{"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"}},"previous":{"id":"a37febe6-8388-5efc-91d5-5fac75bdd784","html":"<p>코드를 재사용하려는 강력한 동기 이면에는 중복된 코드를 제거하려는 욕망이 숨어 있다.</p>\n<h2 id=\"-101-상속과-중복-코드\" style=\"position:relative;\"><a href=\"#-101-%EC%83%81%EC%86%8D%EA%B3%BC-%EC%A4%91%EB%B3%B5-%EC%BD%94%EB%93%9C\" aria-label=\" 101 상속과 중복 코드 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>📖 10.1 상속과 중복 코드</h2>\n<p>중복 코드는 사람들의 마음속에 의심과 불신의 씨앗을 뿌린다.</p>\n<h3 id=\"-1011-dry-원칙\" style=\"position:relative;\"><a href=\"#-1011-dry-%EC%9B%90%EC%B9%99\" aria-label=\" 1011 dry 원칙 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>🔖 10.1.1 DRY 원칙</h3>\n<p><strong>중복 코드는 변경을 방해한다.</strong> 이것이 중복 코드를 제거해야 하는 가장 큰 이유다.</p>\n<ul>\n<li>중복 여부를 판단하는 기준은 변경이다.</li>\n<li>요구사항이 변경됐을 때 두 코드를 함께 수정해야 한다면 중복</li>\n<li>DRY 원칙을 따르자.\n<ul>\n<li>\n<blockquote>\n<p>Don't Repeat Yourself</p>\n</blockquote>\n</li>\n<li>한 번, 단 한 번의 원칙</li>\n<li>단일 지점 제어 원칙</li>\n<li>모든 지식은 시스템 내에서 단일하고, 애매하지 않고, 정말로 믿을 만한 표현 양식을 가져야 한다.</li>\n</ul>\n</li>\n</ul>\n<h3 id=\"-1012-중복과-변경\" style=\"position:relative;\"><a href=\"#-1012-%EC%A4%91%EB%B3%B5%EA%B3%BC-%EB%B3%80%EA%B2%BD\" aria-label=\" 1012 중복과 변경 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>🔖 10.1.2 중복과 변경</h3>\n<h4 id=\"-중복-코드-살펴보기\" style=\"position:relative;\"><a href=\"#-%EC%A4%91%EB%B3%B5-%EC%BD%94%EB%93%9C-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0\" 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<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@RequiredArgsConstructor\npublic class Call {\n    \n    @Getter\n    private final LocalDateTime from;\n    \n    private final LocalDateTime to;\n\n    public Duration getDuration() {\n        return Duration.between(from, to);\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>개별 통화 기간울 저장하는 Class</li>\n</ul>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@Getter\n@RequiredArgsConstructor\npublic class Phone {\n\n    private final Money amount;\n\n    private final Duration seconds;\n\n    private List&lt;Call&gt; calls = new ArrayList&lt;&gt;();\n\n    public void call(Call call) {\n        calls.add(call);\n    }\n\n    public Money calculateFee() {\n        Money result = Money.ZERO;\n\n        for (Call call : calls) {\n            result = result.plus(amount.times((double) call.getDuration().getSeconds() / seconds.getSeconds()));\n        }\n\n        return result;\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>위 요금제는 일반 요금제이다.</li>\n<li>여기서, 심야 할인 요금제(밤 10시 이후의 통화에 대해 할인)가 추가 되었다.</li>\n</ul>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@RequiredArgsConstructor\npublic class NightlyDiscountPhone {\n    \n    private static final int LATE_NIGHT_HOUR = 22;\n\n    private final Money nightlyAmount;\n\n    private final Money regularAmount;\n\n    private final Duration seconds;\n\n    private List&lt;Call&gt; calls = new ArrayList&lt;&gt;();\n\n    public Money calculateCallFee() {\n        Money result = Money.ZERO;\n\n        for (Call call : calls) {\n            if (call.getFrom().getHour() &gt;= LATE_NIGHT_HOUR) {\n                result = result.plus(nightlyAmount.times((double) call.getDuration().getSeconds() / seconds.getSeconds()));\n            } else {\n                result = result.plus(regularAmount.times((double) call.getDuration().getSeconds() / seconds.getSeconds()));\n            }\n        }\n\n        return result;\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>중복 코드가 생겼다!</li>\n</ul>\n<h4 id=\"-중복-코드-수정하기\" style=\"position:relative;\"><a href=\"#-%EC%A4%91%EB%B3%B5-%EC%BD%94%EB%93%9C-%EC%88%98%EC%A0%95%ED%95%98%EA%B8%B0\" 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<p>새로운 요구사항: 통화 요금에 부과할 세금 계산</p>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@Getter\n@RequiredArgsConstructor\npublic class Phone {\n\n    private final Money amount;\n\n    private final Duration seconds;\n    \n    private final double taxRate;\n\n    private List&lt;Call&gt; calls = new ArrayList&lt;&gt;();\n\n    public void call(Call call) {\n        calls.add(call);\n    }\n\n    public Money calculateFee() {\n        Money result = Money.ZERO;\n\n        for (Call call : calls) {\n            result = result.plus(amount.times((double) call.getDuration().getSeconds() / seconds.getSeconds()));\n        }\n\n        return result.plus(result.times(taxRate));\n    }\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@RequiredArgsConstructor\npublic class NightlyDiscountPhone {\n\n    private static final int LATE_NIGHT_HOUR = 22;\n\n    private final Money nightlyAmount;\n    \n    private final Money regularAmount;\n    \n    private final Duration seconds;\n    \n    private final double taxRate;\n    \n    private List&lt;Call&gt; calls = new ArrayList&lt;&gt;();\n\n    public Money calculateCallFee() {\n        Money result = Money.ZERO;\n\n        for (Call call : calls) {\n            if (call.getFrom().getHour() &gt;= LATE_NIGHT_HOUR) {\n                result = result.plus(nightlyAmount.times((double) call.getDuration().getSeconds() / seconds.getSeconds()));\n            } else {\n                result = result.plus(regularAmount.times((double) call.getDuration().getSeconds() / seconds.getSeconds()));\n            }\n        }\n\n        return result.minus(result.times(taxRate));\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>이처럼 중복코드는 새로운 중복코드를 부른다.</li>\n<li><code>minus</code>를 호출하고 있다.</li>\n</ul>\n<h4 id=\"-타입-코드-사용하기\" style=\"position:relative;\"><a href=\"#-%ED%83%80%EC%9E%85-%EC%BD%94%EB%93%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0\" 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<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@Getter\n@RequiredArgsConstructor\npublic class Phone {\n\n    private static final int LATE_NIGHT_HOUR = 22;\n\n    enum PhoneType {REGULAR, NIGHTLY}\n\n    private final PhoneType type;\n\n    private final Money amount;\n\n    private final Money regularAmount;\n\n    private final Money nightlyAmount;\n\n    private final Duration seconds;\n\n    private List&lt;Call&gt; calls = new ArrayList&lt;&gt;();\n\n    public Phone(Money amount, Duration seconds) {\n        this(PhoneType.REGULAR, amount, Money.ZERO, Money.ZERO, seconds);\n    }\n\n    public Phone(Money regularAmount, Money nightlyAmount, Duration seconds) {\n        this(PhoneType.NIGHTLY, Money.ZERO, regularAmount, nightlyAmount, seconds);\n    }\n\n    public Money calculateFee() {\n        Money result = Money.ZERO;\n\n        for (Call call : calls) {\n            if (type == PhoneType.REGULAR) {\n                result = result.plus(amount.times((double) call.getDuration().getSeconds() / seconds.getSeconds()));\n            } else {\n                if (call.getFrom().getHour() &gt;= LATE_NIGHT_HOUR) {\n                    result = result.plus(nightlyAmount.times((double) call.getDuration().getSeconds() / seconds.getSeconds()));\n                } else {\n                    result = result.plus(regularAmount.times((double) call.getDuration().getSeconds() / seconds.getSeconds()));\n                }\n            }\n        }\n\n        return result;\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>낮은 응집도와 높은 결합도를 가진다.</li>\n</ul>\n<h3 id=\"-1013-상속을-이용해서-중복-코드-제거하기\" style=\"position:relative;\"><a href=\"#-1013-%EC%83%81%EC%86%8D%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%B4%EC%84%9C-%EC%A4%91%EB%B3%B5-%EC%BD%94%EB%93%9C-%EC%A0%9C%EA%B1%B0%ED%95%98%EA%B8%B0\" aria-label=\" 1013 상속을 이용해서 중복 코드 제거하기 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>🔖 10.1.3 상속을 이용해서 중복 코드 제거하기</h3>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public class NightlyDiscountPhone extends Phone {\n    private static final int LATE_NIGHT_HOUR = 22;\n\n    private Money nightlyAmount;\n\n    public NightlyDiscountPhone(Money nightlyAmount, Money regularAmount, Duration seconds) {\n        super(regularAmount, seconds);\n        this.nightlyAmount = nightlyAmount;\n    }\n\n    @Override\n    public Money calculateFee() {\n        Money result = super.calculateFee();\n        \n        Money nightlyFee = Money.ZERO;\n        for (Call call : getCalls()) {\n            if (call.getFrom().getHour() &gt;= LATE_NIGHT_HOUR) {\n                nightlyFee = nightlyFee.plus(getAmount().minus(nightlyAmount.times((double) call.getDuration().getSeconds() / getSeconds().getSeconds())));\n            }\n        }\n        \n        return result.minus(nightlyFee);\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>위 코드 처럼 상속을 염두에 두고 설계되지 않은 클래스를 상속을 이용해 재사용하는 것은 쉽지 않다.</li>\n<li>자식 클래스의 작성자가 부모 클래스의 구현 방법에 대한 정확한 지식을 가져야 한다.</li>\n</ul>\n<h3 id=\"-1014-강하게-결합된-phone과-nightlydiscountphone\" style=\"position:relative;\"><a href=\"#-1014-%EA%B0%95%ED%95%98%EA%B2%8C-%EA%B2%B0%ED%95%A9%EB%90%9C-phone%EA%B3%BC-nightlydiscountphone\" aria-label=\" 1014 강하게 결합된 phone과 nightlydiscountphone 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>🔖 10.1.4 강하게 결합된 Phone과 NightlyDiscountPhone</h3>\n<p>새로운 요구사항: 세금 부과</p>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@Getter\n@RequiredArgsConstructor\npublic class Phone {\n\n    private final Money amount;\n\n    private final Duration seconds;\n\n    private final double taxRate;\n\n    private List&lt;Call&gt; calls = new ArrayList&lt;&gt;();\n\n    public Money calculateFee() {\n        Money result = Money.ZERO;\n\n        for (Call call : calls) {\n            result = result.plus(amount.times((double) call.getDuration().getSeconds() / seconds.getSeconds()));\n        }\n\n        return result.plus(result.times(taxRate));\n    }\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public class NightlyDiscountPhone extends Phone {\n    private static final int LATE_NIGHT_HOUR = 22;\n\n    private Money nightlyAmount;\n\n    public NightlyDiscountPhone(Money nightlyAmount, Money regularAmount, Duration seconds, double taxRate) {\n        super(regularAmount, seconds, taxRate);\n        this.nightlyAmount = nightlyAmount;\n    }\n\n    @Override\n    public Money calculateFee() {\n        Money result = super.calculateFee();\n\n        Money nightlyFee = Money.ZERO;\n        for (Call call : getCalls()) {\n            if (call.getFrom().getHour() &gt;= LATE_NIGHT_HOUR) {\n                nightlyFee = nightlyFee.plus(getAmount().minus(nightlyAmount.times((double) call.getDuration().getSeconds() / getSeconds().getSeconds())));\n            }\n        }\n\n        return result.minus(nightlyFee.plus(nightlyFee.times(getTaxRate())));\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>중복 로직을 제거하기 위해 상속을 사용했음에도 중복 코드가 생겼다❗</li>\n</ul>\n<blockquote>\n<p>자식 클래스의 메서드 안에서 super 참조를 이용해 부모 클래스의 메서드를 직접 호출할 경우 두 클래스는 강하게 결합된다. super 호출을 제거할 수 있는 방법을 찾아 결합도를 제거하라.</p>\n</blockquote>\n<h2 id=\"-102-취약한-기반-클래스-문제\" style=\"position:relative;\"><a href=\"#-102-%EC%B7%A8%EC%95%BD%ED%95%9C-%EA%B8%B0%EB%B0%98-%ED%81%B4%EB%9E%98%EC%8A%A4-%EB%AC%B8%EC%A0%9C\" aria-label=\" 102 취약한 기반 클래스 문제 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>📖 10.2 취약한 기반 클래스 문제</h2>\n<ul>\n<li>부모 클래스의 변경에 의해 자식 클래스가 영향을 받는 현상</li>\n<li>상속을 사용한다면 피할 수 없는 OOP의 근본적인 취약성</li>\n<li>캡슐화를 약화시키고 결합도를 높인다.</li>\n</ul>\n<h3 id=\"-1021-불필요한-인터페이스-상속-문제\" style=\"position:relative;\"><a href=\"#-1021-%EB%B6%88%ED%95%84%EC%9A%94%ED%95%9C-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%EC%83%81%EC%86%8D-%EB%AC%B8%EC%A0%9C\" aria-label=\" 1021 불필요한 인터페이스 상속 문제 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>🔖 10.2.1 불필요한 인터페이스 상속 문제</h3>\n<p>Java 초기 버전의 대표적인 사례</p>\n<ul>\n<li><code>java.util.Stack</code>\n<ul>\n<li>Stack을 Vector의 자식 클래스로 구현</li>\n<li>Stack이 규칙을 무너뜨릴 여지가 있는 위험한 Vector의 퍼블릭 인터페이스까지도 함께 상속받음.</li>\n</ul>\n</li>\n<li><code>java.util.Properties</code>\n<ul>\n<li>Map의 조상인 Hashtable을 상속</li>\n<li>String 타입 이외의 키와 값이라도 저장이 가능하게 되어버림.</li>\n</ul>\n</li>\n</ul>\n<blockquote>\n<p>상속받은 부모 클래스의 메서드가 자식 클래스의 내부 구조에 대한 규칙을 깨트릴 수 있다.</p>\n</blockquote>\n<h3 id=\"-1022-메서드-오버라이딩의-오작용-문제\" style=\"position:relative;\"><a href=\"#-1022-%EB%A9%94%EC%84%9C%EB%93%9C-%EC%98%A4%EB%B2%84%EB%9D%BC%EC%9D%B4%EB%94%A9%EC%9D%98-%EC%98%A4%EC%9E%91%EC%9A%A9-%EB%AC%B8%EC%A0%9C\" aria-label=\" 1022 메서드 오버라이딩의 오작용 문제 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>🔖 10.2.2 메서드 오버라이딩의 오작용 문제</h3>\n<ul>\n<li><a href=\"https://bottleh.netlify.app/backend/effective-java/4%EC%9E%A5_%ED%81%B4%EB%9E%98%EC%8A%A4%EC%99%80_%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4/#%EC%95%84%EC%9D%B4%ED%85%9C18-%EC%83%81%EC%86%8D%EB%B3%B4%EB%8B%A4%EB%8A%94-%EC%BB%B4%ED%8F%AC%EC%A7%80%EC%85%98%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%98%EB%9D%BC\">이펙티브 자바 아이템18</a></li>\n</ul>\n<blockquote>\n<p>자식 클래스가 부모 클래스의 메서드를 오버라이딩할 경우 부모 클래스가 자식의 메서드를 사용하는 방법에 자식 클래스가 결합될 수 있다.</p>\n</blockquote>\n<h3 id=\"-1023-부모-클래스와-자식-클래스의-동시-수정-문제\" style=\"position:relative;\"><a href=\"#-1023-%EB%B6%80%EB%AA%A8-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%99%80-%EC%9E%90%EC%8B%9D-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%9D%98-%EB%8F%99%EC%8B%9C-%EC%88%98%EC%A0%95-%EB%AC%B8%EC%A0%9C\" aria-label=\" 1023 부모 클래스와 자식 클래스의 동시 수정 문제 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>🔖 10.2.3 부모 클래스와 자식 클래스의 동시 수정 문제</h3>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@Getter\n@RequiredArgsConstructor\npublic class Song {\n\n    private final String singer;\n    \n    private final String title;\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public class Playlist {\n\n    @Getter\n    private final List&lt;Song&gt; tracks = new ArrayList&lt;&gt;();\n\n    public void append(Song song) {\n        getTracks().add(song);\n    }\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public class PersonalPlaylist extends Playlist {\n    \n    public void remove(Song song) {\n        getTracks().remove(song);\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\">@Getter\npublic class Playlist {\n\n    private final List&lt;Song&gt; tracks = new ArrayList&lt;&gt;();\n\n    private final Map&lt;String, String&gt; singers = new HashMap&lt;&gt;();\n\n    public void append(Song song) {\n        getTracks().add(song);\n        singers.put(song.getSinger(), song.getTitle());\n    }\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public class PersonalPlaylist extends Playlist {\n\n    public void remove(Song song) {\n        getTracks().remove(song);\n        getSingers().remove(song.getSinger());\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>결합도란 다른 대상에 대해 알고 있는 지식의 양이다.</li>\n</ul>\n<blockquote>\n<p>클래스를 상속하면 결합도로 인해 자식 클래스와 부모 클래스의 구현을 영원히 변경하지 않거나, 자식 클래스와 부모 클래스를 동시에 변경하거나 둘 중 하나를 선택할 수 밖에 없다.</p>\n</blockquote>\n<h2 id=\"-103-phone-다시-살펴보기\" style=\"position:relative;\"><a href=\"#-103-phone-%EB%8B%A4%EC%8B%9C-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0\" aria-label=\" 103 phone 다시 살펴보기 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>📖 10.3 Phone 다시 살펴보기</h2>\n<h3 id=\"-1031-추상화에-의존하자\" style=\"position:relative;\"><a href=\"#-1031-%EC%B6%94%EC%83%81%ED%99%94%EC%97%90-%EC%9D%98%EC%A1%B4%ED%95%98%EC%9E%90\" aria-label=\" 1031 추상화에 의존하자 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>🔖 10.3.1 추상화에 의존하자</h3>\n<ul>\n<li>부모 클래스와 자식 클래스 모두 추상화에 의존하도록 수정</li>\n</ul>\n<p>코드 중복을 제거하기 위해 상속을 도입할 때 따르는 원칙</p>\n<ol>\n<li>두 메서드가 유사하게 보인다면 차이점을 메서드로 추출</li>\n<li>부모 클래스의 코드를 하위로 내리지 말고 자식 클래스의 코드를 상위로 옮겨라.</li>\n</ol>\n<h3 id=\"-1032-차이를-메서드로-추출하라\" style=\"position:relative;\"><a href=\"#-1032-%EC%B0%A8%EC%9D%B4%EB%A5%BC-%EB%A9%94%EC%84%9C%EB%93%9C%EB%A1%9C-%EC%B6%94%EC%B6%9C%ED%95%98%EB%9D%BC\" aria-label=\" 1032 차이를 메서드로 추출하라 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>🔖 10.3.2 차이를 메서드로 추출하라</h3>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@Getter\n@RequiredArgsConstructor\npublic class Phone {\n\n    private final Money amount;\n\n    private final Duration seconds;\n\n    private List&lt;Call&gt; calls = new ArrayList&lt;&gt;();\n\n    public Money calculateFee() {\n        Money result = Money.ZERO;\n\n        for (Call call : calls) {\n            result = result.plus(calculateCallFee(call));\n        }\n\n        return result;\n    }\n\n    private Money calculateCallFee(Call call) {\n        return amount.times((double) call.getDuration().getSeconds() / seconds.getSeconds());\n    }\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@RequiredArgsConstructor\npublic class NightlyDiscountPhone {\n\n    private static final int LATE_NIGHT_HOUR = 22;\n\n    private final Money nightlyAmount;\n\n    private final Money regularAmount;\n\n    private final Duration seconds;\n\n    private List&lt;Call&gt; calls = new ArrayList&lt;&gt;();\n\n    public Money calculateCallFee() {\n        Money result = Money.ZERO;\n\n        for (Call call : calls) {\n            result = result.plus(calculateCallFee(call));\n        }\n\n        return result;\n    }\n\n    private Money calculateCallFee(Call call) {\n        if (call.getFrom().getHour() &gt;= LATE_NIGHT_HOUR) {\n            return nightlyAmount.times((double) call.getDuration().getSeconds() / seconds.getSeconds());\n        }\n        return regularAmount.times((double) call.getDuration().getSeconds() / seconds.getSeconds());\n    }\n}</code>\n        </deckgo-highlight-code>\n<h3 id=\"-1033-중복-코드를-부모-클래스로-올려라\" style=\"position:relative;\"><a href=\"#-1033-%EC%A4%91%EB%B3%B5-%EC%BD%94%EB%93%9C%EB%A5%BC-%EB%B6%80%EB%AA%A8-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%A1%9C-%EC%98%AC%EB%A0%A4%EB%9D%BC\" aria-label=\" 1033 중복 코드를 부모 클래스로 올려라 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>🔖 10.3.3 중복 코드를 부모 클래스로 올려라</h3>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public abstract class AbstractPhone {\n\n    private final List&lt;Call&gt; calls = new ArrayList&lt;&gt;();\n\n    public Money calculateFee() {\n        Money result = Money.ZERO;\n\n        for (Call call : calls) {\n            result = result.plus(calculateCallFee(call));\n        }\n\n        return result;\n    }\n\n    protected abstract Money calculateCallFee(Call call);\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@Getter\n@RequiredArgsConstructor\npublic class Phone extends AbstractPhone{\n\n    private final Money amount;\n\n    private final Duration seconds;\n\n    @Override\n    protected Money calculateCallFee(Call call) {\n        return amount.times((double) call.getDuration().getSeconds() / seconds.getSeconds());\n    }\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@RequiredArgsConstructor\npublic class NightlyDiscountPhone extends AbstractPhone {\n\n    private static final int LATE_NIGHT_HOUR = 22;\n\n    private final Money nightlyAmount;\n\n    private final Money regularAmount;\n\n    private final Duration seconds;\n\n    @Override\n    protected Money calculateCallFee(Call call) {\n        if (call.getFrom().getHour() &gt;= LATE_NIGHT_HOUR) {\n            return nightlyAmount.times((double) call.getDuration().getSeconds() / seconds.getSeconds());\n        }\n        return regularAmount.times((double) call.getDuration().getSeconds() / seconds.getSeconds());\n    }\n}</code>\n        </deckgo-highlight-code>\n<h3 id=\"-1034-추상화가-핵심이다\" style=\"position:relative;\"><a href=\"#-1034-%EC%B6%94%EC%83%81%ED%99%94%EA%B0%80-%ED%95%B5%EC%8B%AC%EC%9D%B4%EB%8B%A4\" aria-label=\" 1034 추상화가 핵심이다 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>🔖 10.3.4 추상화가 핵심이다</h3>\n<ul>\n<li>세 클래스는 각각 하나의 변경 이유만을 가진다.\n<ul>\n<li>단일 책임 원칙을 준수하므로 응집도가 높다.</li>\n</ul>\n</li>\n<li>부모 클래스의 내부 구현이 변경되더라도 자식 클래스는 영향을 받지 않는다.</li>\n<li>상속 계층이 코드를 진화시키는 데 걸림돌이 된다면 추상화를 찾아내고 상속 계층 안의 클래스들이 그 추상화에 의존하도록 코드를 리팩터링</li>\n</ul>\n<h3 id=\"-1035-의도를-드러내는-이름-선택하기\" style=\"position:relative;\"><a href=\"#-1035-%EC%9D%98%EB%8F%84%EB%A5%BC-%EB%93%9C%EB%9F%AC%EB%82%B4%EB%8A%94-%EC%9D%B4%EB%A6%84-%EC%84%A0%ED%83%9D%ED%95%98%EA%B8%B0\" aria-label=\" 1035 의도를 드러내는 이름 선택하기 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>🔖 10.3.5 의도를 드러내는 이름 선택하기</h3>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public abstract class Phone {\n}\n\npublic class RegularPhone extends Phone {\n}\n\npublic class NightlyDiscountPhone extends Phone {\n}</code>\n        </deckgo-highlight-code>\n<h3 id=\"-1036-세금-추가하기\" style=\"position:relative;\"><a href=\"#-1036-%EC%84%B8%EA%B8%88-%EC%B6%94%EA%B0%80%ED%95%98%EA%B8%B0\" aria-label=\" 1036 세금 추가하기 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>🔖 10.3.6 세금 추가하기</h3>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@RequiredArgsConstructor\npublic abstract class Phone {\n    \n    private final double taxRate;\n    \n    private List&lt;Call&gt; calls = new ArrayList&lt;&gt;();\n\n    public Money calculateFee() {\n        Money result = Money.ZERO;\n\n        for (Call call : calls) {\n            result = result.plus(calculateCallFee(call));\n        }\n\n        return result.plus(result.times(taxRate));\n    }\n\n    protected abstract Money calculateCallFee(Call call);\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@Getter\npublic class RegularPhone extends Phone {\n\n    private final Money amount;\n\n    private final Duration seconds;\n\n    public RegularPhone(double taxRate, Money amount, Duration seconds) {\n        super(taxRate);\n        this.amount = amount;\n        this.seconds = seconds;\n    }\n\n    @Override\n    protected Money calculateCallFee(Call call) {\n        return amount.times((double) call.getDuration().getSeconds() / seconds.getSeconds());\n    }\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public class NightlyDiscountPhone extends Phone {\n\n    private static final int LATE_NIGHT_HOUR = 22;\n\n    private final Money nightlyAmount;\n\n    private final Money regularAmount;\n\n    private final Duration seconds;\n\n    public NightlyDiscountPhone(double taxRate, Money nightlyAmount, Money regularAmount, Duration seconds) {\n        super(taxRate);\n        this.nightlyAmount = nightlyAmount;\n        this.regularAmount = regularAmount;\n        this.seconds = seconds;\n    }\n\n    @Override\n    protected Money calculateCallFee(Call call) {\n        if (call.getFrom().getHour() &gt;= LATE_NIGHT_HOUR) {\n            return nightlyAmount.times((double) call.getDuration().getSeconds() / seconds.getSeconds());\n        }\n        return regularAmount.times((double) call.getDuration().getSeconds() / seconds.getSeconds());\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>책임을 아무리 잘 분리하더라도 인스턴스 변수의 추가는 종종 상속 계층 전반에 걸친 변경을 유발</li>\n<li>우리가 원하는 것은 행동을 변경하기 위해 인스턴스 변수를 추가하더라도 상속 계층 전체에 걸쳐 부작용이 퍼지지 않게 막는 것</li>\n</ul>\n<h2 id=\"-104-차이에-의한-프로그래밍\" style=\"position:relative;\"><a href=\"#-104-%EC%B0%A8%EC%9D%B4%EC%97%90-%EC%9D%98%ED%95%9C-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D\" aria-label=\" 104 차이에 의한 프로그래밍 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>📖 10.4 차이에 의한 프로그래밍</h2>\n<ul>\n<li>기존 코드와 다른 부분만을 추가함으로써 애플리케이션의 기능을 확장하는 방법</li>\n<li>중복 코드를 제거하고 코드를 재사용하는 것이 목표</li>\n<li>상속은 코드 재사용과 관련된 대부분의 경우에 우아한 해결 방법이 아니다.\n<ul>\n<li><strong>합성</strong>이 더 좋은 방법❗</li>\n</ul>\n</li>\n</ul>","excerpt":"코드를 재사용하려는 강력한 동기 이면에는 중복된 코드를 제거하려는 욕망이 숨어 있다. 📖 10.1 상속과 중복 코드 중복 코드는 사람들의 마음속에 의심과 불신의 씨앗을 뿌린다. 🔖 10.1.1 DRY 원칙 중복 코드는 변경을 방해한다. 이것이 중복 코드를 제거해야 하는 가장 큰 이유다. 중복 여부를 판단하는 기준은 변경이다. 요구사항이 변경됐을 때 두 코드를 함께 수정해야 한다면 중복 DRY 원칙을 따르자. Don't Repeat Yourself…","fields":{"slug":"/backend/object/chapter10/상속과_코드_재사용/"},"frontmatter":{"title":"Object - 10장 상속과 코드 재사용","thumbnail":{"childImageSharp":{"fluid":{"src":"/static/dd0e1990925e942697544e2bdcd9332e/9b73b/object.png"}}},"draft":false,"category":"Back-End","tags":["java"],"date":"October 29, 2023"}},"node":{"id":"b14e7f9b-76a7-59bf-b641-5c48cac92a69","html":"<h2 id=\"-91-개방-폐쇄-원칙\" style=\"position:relative;\"><a href=\"#-91-%EA%B0%9C%EB%B0%A9-%ED%8F%90%EC%87%84-%EC%9B%90%EC%B9%99\" aria-label=\" 91 개방 폐쇄 원칙 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>📖 9.1 개방-폐쇄 원칙</h2>\n<blockquote>\n<p>소프트웨어 개체(클래스, 모듈, 함수 등등)는 확장에 대해 열려 있어야 하고, 수정에 대해서는 닫혀 있어야 한다.</p>\n</blockquote>\n<ul>\n<li>확장에 대해 열려 있다: 애플리케이션의 요구사항이 변경될 때 이 변경에 맞게 새로운 '동작'을 추가해서 애플리케이션의 기능을 확장할 수 있다.</li>\n<li>수정에 대해 닫혀 있다: 기존의 '코드'를 수정하지 않고도 애플리케이션의 동작을 추가하거나 변경할 수 있다.</li>\n</ul>\n<h3 id=\"-911-컴파일타임-의존성을-고정시키고-런타임-의존성을-변경하라\" style=\"position:relative;\"><a href=\"#-911-%EC%BB%B4%ED%8C%8C%EC%9D%BC%ED%83%80%EC%9E%84-%EC%9D%98%EC%A1%B4%EC%84%B1%EC%9D%84-%EA%B3%A0%EC%A0%95%EC%8B%9C%ED%82%A4%EA%B3%A0-%EB%9F%B0%ED%83%80%EC%9E%84-%EC%9D%98%EC%A1%B4%EC%84%B1%EC%9D%84-%EB%B3%80%EA%B2%BD%ED%95%98%EB%9D%BC\" aria-label=\" 911 컴파일타임 의존성을 고정시키고 런타임 의존성을 변경하라 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>🔖 9.1.1 컴파일타임 의존성을 고정시키고 런타임 의존성을 변경하라</h3>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1114px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 29.333333333333332%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAIAAABM9SnKAAAACXBIWXMAABYlAAAWJQFJUiTwAAAA9klEQVQY013Ny27CMBCFYd7/7WikIEsE0hhiHNnO+JL4MjhTEWgX/Vaz+c8ctm1DxFIKIj6fz5xL/rVtGxHlnGNMMcZSyn7HdV0RkYgOiAgA4zgaY7TW0zRxfrter0qpUgoRzfMshJBSWmuVUm3bNk0DAK+YiEIIAOCcq7WGEB6PB+fcWltrJaIYY9jVWkvBJSwhhJzzJ35LKUkpT6eTlFJrzRjrus45573XWhtj1nX13l8ul/P5vCzL/5gxdjx+DcPrLed8GAbnHAAIIcZxFELc77fvnff+E9sUjbXTNHVdxxjr+14pBQDGmJTSe7rWaq19N39+AAmIU6iuKMtnAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"9.1\"\n        title=\"9.1\"\n        src=\"/static/c48c54664a1af80484ca8ea31a6937f8/cd536/9.1.png\"\n        srcset=\"/static/c48c54664a1af80484ca8ea31a6937f8/5a46d/9.1.png 300w,\n/static/c48c54664a1af80484ca8ea31a6937f8/0a47e/9.1.png 600w,\n/static/c48c54664a1af80484ca8ea31a6937f8/cd536/9.1.png 1114w\"\n        sizes=\"(max-width: 1114px) 100vw, 1114px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n        decoding=\"async\"\n      />\n    </span></p>\n<ul>\n<li>기존 클래스는 전혀 수정하지 않은 채 애플리케이션의 동작을 확장했다.</li>\n<li>단순히 새로운 클래스를 추가하는 것만으로 <code>Movie</code>를 새로운 컨텍스트에 사용되도록 확장할 수 있었던 것</li>\n</ul>\n<p>OCP를 수용하는 코드는 컴파일타임 의존성을 수정하지 않고도 런타임 의존성을 쉽게 변경할 수 있다. 의존성 관점에서 OCP를 따르는 설계란 컴파일타임 의존성은 유지하면서 런타임 의존성의 가능성을 확장하고 수정할 수 있는 구조라고 할 수 있다.</p>\n<h3 id=\"-912-추상화가-핵심이다\" style=\"position:relative;\"><a href=\"#-912-%EC%B6%94%EC%83%81%ED%99%94%EA%B0%80-%ED%95%B5%EC%8B%AC%EC%9D%B4%EB%8B%A4\" aria-label=\" 912 추상화가 핵심이다 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>🔖 9.1.2 추상화가 핵심이다</h3>\n<p>OCP의 핵심은 <strong>추상화에 의존하는 것</strong></p>\n<ul>\n<li>추상화란 핵심적인 부분만 남기고 불필요한 부분은 생략함으로써 복잡성을 극복하는 기법</li>\n<li>OCP의 관점에서 생략되지 않고 남겨지는 부분은 다양한 상황에서의 공통점을 반영한 추상화의 결과물</li>\n</ul>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public abstract class DiscountPolicy {\n    private final List&lt;DiscountCondition&gt; conditions;\n    \n    protected DiscountPolicy(DiscountCondition... conditions) {\n        this.conditions = Arrays.asList(conditions);\n    }\n    \n    public Money calculateDiscountAmount(Screening screening) {\n        for (DiscountCondition condition : conditions) {\n            if (condition.isSatisfiedBy(screening)) {\n                return getDiscountAmount(screening);\n            }\n        }\n        return screening.getMovieFee();\n    }\n    protected abstract Money getDiscountAmount(Screening screening);\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>언제라도 추상화의 생략된 부분을 채워넣음으로써 새로운 문맥에 맞게 기능을 확장할 수 있다.</li>\n<li>OCP에서 폐쇄를 가능하게 하는 것은 의존성의 방향이다.</li>\n<li>수정에 대한 영향을 최소화하기 위해서는 모든 요소가 추상화에 의존해야 한다.</li>\n</ul>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@AllArgsConstructor\npublic class Movie {\n\n    private String title;\n\n    private Duration runningTime;\n\n    @Getter\n    private Money fee;\n\n    private DiscountPolicy discountPolicy;\n    \n    public Money calculateMovieFee(Screening screening) {\n        return fee.minus(discountPolicy.calculateDiscountAmount(screening));\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>Movie</code>는 안정된 추상화인 <code>DiscountPolicy</code>에 의존하기 때문에 할인 정책을 추가하기 위해 <code>DiscountPolicy</code>의 자식 클래스를 추가하더라도 영향을 받지 않는다. 따라서 수정에 대해 닫혀 있다.</li>\n</ul>\n<p>추상화를 했다고 해서 모든 수정에 대해 설계가 폐쇄되는 것은 아니다. 추상화가 수정에 대해 닫혀 있을 수 있는 이유는 변경되지 않을 부분을 신중하게 결정하고 올바른 추상화를 주의 깊게 선택했기 때문이다.</p>\n<h2 id=\"-92-생성-사용-분리\" style=\"position:relative;\"><a href=\"#-92-%EC%83%9D%EC%84%B1-%EC%82%AC%EC%9A%A9-%EB%B6%84%EB%A6%AC\" aria-label=\" 92 생성 사용 분리 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>📖 9.2 생성 사용 분리</h2>\n<p>결합도가 높아질수록 개방-폐쇄 원칙을 따르는 구조를 설계하기가 어려워진다.</p>\n<ul>\n<li>알아야 하는 지식이 많으면 결합도도 높아진다.</li>\n<li>객체 생성에 대한 지식은 과도한 결합도를 초래하는 경향이 있다.\n<ul>\n<li>부적절한 곳에서 객체를 생성한다는 것이 문제❗️</li>\n</ul>\n</li>\n</ul>\n<p>유연하고 재사용 가능한 설계를 원한다면 <strong>객체에 대한 생성과 사용을 분리(seperating use from creation)</strong> 해야 한다.</p>\n<p>사용으로부터 생성을 분리하는 데 사용되는 가장 보편적인 방법은 <strong>객체를 생성할 책임을 클라이언트로 옮기는 것</strong></p>\n<h3 id=\"-921-factory-추가하기\" style=\"position:relative;\"><a href=\"#-921-factory-%EC%B6%94%EA%B0%80%ED%95%98%EA%B8%B0\" aria-label=\" 921 factory 추가하기 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>🔖 9.2.1 FACTORY 추가하기</h3>\n<blockquote>\n<p>생성과 사용을 분리하기 위해 객체 생성에 특화된 객체를 FACTORY라고 부른다.</p>\n</blockquote>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public class Factory {\n    public Movie createAvatarMovie() {\n        return new Movie(&quot;아바타&quot;, Duration.ofMinutes(120), Money.wons(10000), new AmountDiscountPolicy(...));\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 Client {\n    private Factory factory;\n\n    public Money getAvatarFee() {\n        Movie avatar = factory.createAvatarMovie();\n        return avatar.getFee();\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>Client는 오직 사용과 관련된 책임만 지고 생성과 관련된 어떤 지식도 가지지 않을 수 있다.</li>\n</ul>\n<h3 id=\"-922-순수한-가공물에게-책임-할당하기\" style=\"position:relative;\"><a href=\"#-922-%EC%88%9C%EC%88%98%ED%95%9C-%EA%B0%80%EA%B3%B5%EB%AC%BC%EC%97%90%EA%B2%8C-%EC%B1%85%EC%9E%84-%ED%95%A0%EB%8B%B9%ED%95%98%EA%B8%B0\" aria-label=\" 922 순수한 가공물에게 책임 할당하기 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>🔖 9.2.2 순수한 가공물에게 책임 할당하기</h3>\n<p>도메인 모델은 Information expert를 찾기 위해 참조할 수 있는 일차적인 재료다.</p>\n<p>시스템을 객체로 분해하는 데는 크게 두 가지 방식이 존재</p>\n<ol>\n<li>\n<p>표현적 분해</p>\n<ul>\n<li>도메인에 존재하는 사물 또는 개념을 표현하는 객체들을 이용해 시스템을 분해하는 것</li>\n<li>도메인 모델에 담겨 있는 개념과 관계를 따르며 도메인과 소프트웨어 사잉의 표현적 차이를 최소화하는 것을 목적으로 함.</li>\n</ul>\n</li>\n<li>\n<p>행위적 분해</p>\n<ul>\n<li>순수한 가공물(pure fabrication): 책임을 할당하기 위해 창조되는 도메인과 무관한 인공적인 객체</li>\n</ul>\n</li>\n</ol>\n<p>도메인 개념이 만족스럽지 못하다면 주저하지 말고 인공적인 객체를 창조하라. 객체지향이 실세계의 모방이라는 말은 옳지 않다.</p>\n<h2 id=\"-93-의존성-주입\" style=\"position:relative;\"><a href=\"#-93-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85\" aria-label=\" 93 의존성 주입 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>📖 9.3 의존성 주입</h2>\n<p>의존성 주입: 사용하는 객체가 아닌 외부의 독립적인 객체가 인스턴스를 생성한 후 이를 전달해서 의존성을 해결하는 방법</p>\n<ul>\n<li>생성자 주입: 객체를 생성하는 시점에 생성자를 통한 의존성 해결</li>\n<li>setter 주입: 객체 생성 후 setter 메서드를 통한 의존성 해결</li>\n<li>메서드 주입: 메서드 실행 시 인자를 이용한 의존성 해결</li>\n</ul>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">Movie avatar = new Movie(&quot;아바타&quot;, Duration.ofMinutes(120), Money.wons(10000), new AmountDiscountPolicy(...));</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\">avatar.setDiscountPolicy(new AmountDiscountPolicy(...));</code>\n        </deckgo-highlight-code>\n<ul>\n<li>setter 주입</li>\n<li>장점: 언제라도 의존 대상을 교체할 수 있다.</li>\n<li>단점: 객체가 올바로 생성되기 위해 어떤 의존성이 필수적인지를 명시적으로 표현할 수 없다.</li>\n</ul>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">avatar.calculateDiscountAmount(screening, new AmountDiscountPolicy(...));</code>\n        </deckgo-highlight-code>\n<ul>\n<li>메서드 주입(메서드 호출 주입)</li>\n<li>메서드가 의존성을 필요로하는 유일한 경우일 때 사용할 수 있다.</li>\n</ul>\n<h3 id=\"-931-숨겨진-의존성은-나쁘다\" style=\"position:relative;\"><a href=\"#-931-%EC%88%A8%EA%B2%A8%EC%A7%84-%EC%9D%98%EC%A1%B4%EC%84%B1%EC%9D%80-%EB%82%98%EC%81%98%EB%8B%A4\" aria-label=\" 931 숨겨진 의존성은 나쁘다 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>🔖 9.3.1 숨겨진 의존성은 나쁘다</h3>\n<p>Service Locator 패턴</p>\n<ul>\n<li>의존성을 해결할 수 있는 방법</li>\n<li>Service Locator는 의존성을 해결할 객체들을 보관하는 일종의 저장소</li>\n<li>객체가 직접 Service Locator에게 의존성을 해결해줄 것을 요청</li>\n<li>서비스를 사용하는 코드로부터 서비스가 누구인지(서비스를 구현한 구체 클래스의 타입이 무엇인지), 어디에 있는지(클래스 인스턴스를 어떻게 얻을지)를 몰라도 되게 해준다.</li>\n</ul>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic class ServiceLocator {\n    \n    private static final ServiceLocator soleInstance = new ServiceLocator();\n    private DiscountPolicy discountPolicy;\n    \n    public static DiscountPolicy discountPolicy() {\n        return soleInstance.discountPolicy;\n    }\n    \n    public static void provide(DiscountPolicy discountPolicy) {\n        soleInstance.discountPolicy = discountPolicy;\n    }\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">ServiceLocator.provide(new AmountDiscountPolicy(...));\nMovie avatar = new Movie(&quot;아바타&quot;, Duration.ofMinutes(120), Money.wons(10000));</code>\n        </deckgo-highlight-code>\n<ul>\n<li>위 패턴의 가장 큰 단점은 의존성을 감춘다는 것</li>\n</ul>\n<p>의존성을 구현 내부로 감출 경우</p>\n<ul>\n<li>의존성과 관련된 문제가 컴파일타임이 아닌 런타임에 가서야 발견된다.</li>\n<li>단위 테스트 작성이 어렵다.\n<ul>\n<li>각 단위 테스트는 서로 고립돼야 한다는 기본 원칙 위반</li>\n</ul>\n</li>\n<li>의존성을 이해하기 위해 코드의 내부 구현을 이해할 것을 강요한다.</li>\n<li>의존성의 대상을 설정하는 시점과 의존성이 해결되는 시점을 멀리 떨어트려 놓는다.\n<ul>\n<li>코드를 이해하고 디버깅하기 어렵게 만든다.</li>\n</ul>\n</li>\n</ul>\n<p>의존성 주입을 지원하는 프레임워크를 사용하지 못하는 경우나 깊은 호출 계층에 걸쳐 동일한 객체를 계속해서 전달해야 하는 고통을 견디기 어려운 경우에는 어쩔 수 없이 Service Locator 패턴을 사용하는 것을 고려하라.</p>\n<h2 id=\"-94-의존성-역전-원칙\" style=\"position:relative;\"><a href=\"#-94-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%97%AD%EC%A0%84-%EC%9B%90%EC%B9%99\" aria-label=\" 94 의존성 역전 원칙 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>📖 9.4 의존성 역전 원칙</h2>\n<h3 id=\"-941-추상화와-의존성-역전\" style=\"position:relative;\"><a href=\"#-941-%EC%B6%94%EC%83%81%ED%99%94%EC%99%80-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%97%AD%EC%A0%84\" aria-label=\" 941 추상화와 의존성 역전 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>🔖 9.4.1 추상화와 의존성 역전</h3>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public class Movie {\n    private AmountDiscountPolicy discountPolicy;\n}</code>\n        </deckgo-highlight-code>\n<p>의존성은 변경의 전파와 관련된 것이기 때문에 설계는 변경의 영향을 최소화하도록 의존성을 관리해야 한다.</p>\n<ul>\n<li>상위 수준의 클래스는 어떤 식으로든 하위 수준의 클래스에 의존해서는 안 된다.</li>\n<li>대부분의 경우 우리가 재사용하려는 대상은 상위 수준의 클래스다.</li>\n</ul>\n<p>가장 중요한 것은 추상화에 의존하는 것이다.</p>\n<ul>\n<li>모든 의존성의 방향이 추상 클래스나 인터페이스와 같은 추상화를 따라야 한다.</li>\n</ul>\n<p>의존성 역전 원칙(Dependency Inversion Principle, DIP)</p>\n<ol>\n<li>상위 수준의 모듈은 하위 수준의 모듈에 의존해서는 안 된다. 둘 모두 추상화에 의존해야 한다.</li>\n<li>추상화는 구체적인 사항에 의존해서는 안 된다. 구체적인 사항은 추상화에 의존해야 한다.</li>\n<li>역전이라는 단어를 사용한 이유는 DIP를 따르는 설계는 의존성의 방향이 전통적인 절차형 프로그래밍과는 반대 방향으로 나타나기 때문</li>\n</ol>\n<h3 id=\"-942-의존성-역전-원칙과-패키지\" style=\"position:relative;\"><a href=\"#-942-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%97%AD%EC%A0%84-%EC%9B%90%EC%B9%99%EA%B3%BC-%ED%8C%A8%ED%82%A4%EC%A7%80\" aria-label=\" 942 의존성 역전 원칙과 패키지 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>🔖 9.4.2 의존성 역전 원칙과 패키지</h3>\n<p>역전은 의존성의 방향뿐만 아니라 인터페이스의 소유권에도 적용된다.</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1025px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 37%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAIAAACHqfpvAAAACXBIWXMAABYlAAAWJQFJUiTwAAAA6klEQVQY032Qy26EMAxF5/9/jAVrBKzI8BCjOBmKwUlISNyKzFStKvUsLMvysax744vzPLXW6oKIEHFZlufF/oaInLNEFELI1u1bRsSPN8MwrOtKRFJKpVTf9wCAiCmlfIiZU0ovOaUEAEKI+70fhkFr7b1nZiICkF3XAUB2iMy+0y+ZmUMI3vtw4S/yPMbonM3bzGyMIfoj/+Q8T2MMInZdJ6UEACmlEGLbNkQ0xvwnxxi11lVVFUXRtu00TU3TlGVZ1/U8P6x1L9kEDxs+tc4JK6VyHcdxnmdr7XEc1lrnXAgh9/n/r7Q/AR3lkPPrF582AAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"9.9\"\n        title=\"9.9\"\n        src=\"/static/ee458d231b0407087aa63239dee7bd94/d0143/9.9.png\"\n        srcset=\"/static/ee458d231b0407087aa63239dee7bd94/5a46d/9.9.png 300w,\n/static/ee458d231b0407087aa63239dee7bd94/0a47e/9.9.png 600w,\n/static/ee458d231b0407087aa63239dee7bd94/d0143/9.9.png 1025w\"\n        sizes=\"(max-width: 1025px) 100vw, 1025px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n        decoding=\"async\"\n      />\n    </span></p>\n<ul>\n<li><code>Movie</code>를 다양한 컨텍스트에서 재사용하기 위해서는 불필요한 클래스들이 <code>Movie</code>와 함께 배포해야한 한다.</li>\n<li>불필요한 클래스들을 같은 패키지에 두는 것은 전체적인 빌드 시간을 가파르게 상승시킨다.</li>\n</ul>\n<p>Separated interface 패턴</p>\n<ul>\n<li>추상화를 별도의 독립적인 패키지가 아니라 클라이언트가 속한 패키지에 포함시켜야 한다.</li>\n<li>함게 재사용될 필요가 없는 클래스들은 별도의 독립적인 패키지에 모아햐 한다.</li>\n</ul>\n<p>의존성 역전 원칙에 따라 상위 수준의 협력 흐름을 재사용하기 위해서는 추상화가 제공하는 인터페이스의 소유권 역시 역전시켜야 한다.</p>\n<h2 id=\"-95-유연성에-대한-조언\" style=\"position:relative;\"><a href=\"#-95-%EC%9C%A0%EC%97%B0%EC%84%B1%EC%97%90-%EB%8C%80%ED%95%9C-%EC%A1%B0%EC%96%B8\" aria-label=\" 95 유연성에 대한 조언 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>📖 9.5 유연성에 대한 조언</h2>\n<h3 id=\"-951-유연한-설계는-유연성이-필요할-때만-옳다\" style=\"position:relative;\"><a href=\"#-951-%EC%9C%A0%EC%97%B0%ED%95%9C-%EC%84%A4%EA%B3%84%EB%8A%94-%EC%9C%A0%EC%97%B0%EC%84%B1%EC%9D%B4-%ED%95%84%EC%9A%94%ED%95%A0-%EB%95%8C%EB%A7%8C-%EC%98%B3%EB%8B%A4\" aria-label=\" 951 유연한 설계는 유연성이 필요할 때만 옳다 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>🔖 9.5.1 유연한 설계는 유연성이 필요할 때만 옳다</h3>\n<p>유연하고 재사용 가능한 설계가 항상 좋은 것은 아니다.</p>\n<ul>\n<li>설계의 미덕은 단순함과 명확함으로부터 나온다.</li>\n<li>아직 일어나지 않은 변경은 변경이 아니다.</li>\n<li>유연성은 항상 복잡성을 수반한다.</li>\n<li>불필요한 유연성은 불필요한 복잡성을 낳는다.</li>\n</ul>\n<p>복잡성에 대한 걱정보다 유연하고 재사용 가능한 설계의 필요성이 더 크다면 코드의 구조와 실행 구조를 다르게 만들어라.</p>\n<h3 id=\"-952-협력과-책임이-중요하다\" style=\"position:relative;\"><a href=\"#-952-%ED%98%91%EB%A0%A5%EA%B3%BC-%EC%B1%85%EC%9E%84%EC%9D%B4-%EC%A4%91%EC%9A%94%ED%95%98%EB%8B%A4\" aria-label=\" 952 협력과 책임이 중요하다 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>🔖 9.5.2 협력과 책임이 중요하다</h3>\n<p>설계를 유연하게 만들기 위해서는 먼저 역할, 책임, 협력에 초점을 맞춰야 한다.</p>\n<ul>\n<li>다양한 컨텍스트에서 협력을 재사용할 필요가 없다면 설계를 유연하게 만들 당위성도 함께 사라진다.</li>\n<li>객체들이 메시지 전송자의 관점에서 동일한 책임을 수행하는지 여부를 판단할 수 없다면 공통의 추상화를 도출할 수 없다.</li>\n<li>동일한 역할을 통해 객체들을 대체 가능하게 만들지 않았다면 협력에 참여하는 객체들을 교체할 필요가 없다.</li>\n<li>중요한 비즈니스 로직을 처리하기 위해 책임을 할당하고 협력의 균형을 맞추는 것이 객체 생성에 관한 책임을 할당하는 것보다 우선이다.</li>\n</ul>\n<p>불필요한 Singleton 패턴은 객체 생성에 관해 너무 이른 시기에 고민하고 결정할 때 도입되는 경향이 있다.</p>\n<p>이번 장에서 설명한 다양한 기법들을 적용하기 전에 역할, 책임, 협력의 모습이 선명하게 그려지지 않는다면 의존성을 관리하는 데 들이는 모든 노력이 물거품이 될 수도 있다는 사실을 명심하라.</p>","excerpt":"📖 9.1 개방-폐쇄 원칙 소프트웨어 개체(클래스, 모듈, 함수 등등)는 확장에 대해 열려 있어야 하고, 수정에 대해서는 닫혀 있어야 한다. 확장에 대해 열려 있다: 애플리케이션의 요구사항이 변경될 때 이 변경에 맞게 새로운 '동작'을 추가해서 애플리케이션의 기능을 확장할 수 있다. 수정에 대해 닫혀 있다: 기존의 '코드'를 수정하지 않고도 애플리케이션의 동작을 추가하거나 변경할 수 있다. 🔖 9.1.…","fields":{"slug":"/backend/object/chapter9/유연한_설계/"},"frontmatter":{"title":"Object - 9장 유연한 설계","thumbnail":{"childImageSharp":{"fluid":{"src":"/static/dd0e1990925e942697544e2bdcd9332e/9b73b/object.png"}}},"draft":false,"category":"Back-End","tags":["java"],"date":"October 22, 2023"}}}},"staticQueryHashes":["2374173507","2996537568","3691437124"]}