{"componentChunkName":"component---src-containers-post-index-tsx","path":"/backend/object/chapter14/일관성_있는_협력/","result":{"pageContext":{"next":{"id":"5e0a5e6c-4129-58ae-af88-f36029bc2dcf","html":"<p>상속의 용도</p>\n<ol>\n<li>타입 계층 구현</li>\n<li>코드 재사용</li>\n</ol>\n<h2 id=\"-131-타입\" style=\"position:relative;\"><a href=\"#-131-%ED%83%80%EC%9E%85\" aria-label=\" 131 타입 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>📖 13.1 타입</h2>\n<p>프로그래밍 언어 관점에서의 타입과 개념 관점에서의 타입</p>\n<h3 id=\"-1311-개념-관점의-타입\" style=\"position:relative;\"><a href=\"#-1311-%EA%B0%9C%EB%85%90-%EA%B4%80%EC%A0%90%EC%9D%98-%ED%83%80%EC%9E%85\" aria-label=\" 1311 개념 관점의 타입 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>🔖 13.1.1 개념 관점의 타입</h3>\n<p>개념 관점에서 타입이란 우리가 인지하는 세상의 사물의 종류를 의미한다.</p>\n<p>어떤 대상이 타입으로 분류될 때 그 대상을 타입의 인스턴스(instance)**라고 부른다.</p>\n<ul>\n<li>타입의 인스턴스를 <strong>객체</strong>라고 부름.</li>\n<li>심볼(symbol): 타입에 이름을 붙인 것</li>\n<li>내연(intension): 타입의 정의로서 타입에 속하는 객체들이 가지는 공통적인 속성이나 행동</li>\n<li>외연(extension): 타입에 속하는 객체들의 집합</li>\n</ul>\n<h3 id=\"-1312-프로그래밍-언어-관점의-타입\" style=\"position:relative;\"><a href=\"#-1312-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%96%B8%EC%96%B4-%EA%B4%80%EC%A0%90%EC%9D%98-%ED%83%80%EC%9E%85\" aria-label=\" 1312 프로그래밍 언어 관점의 타입 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>🔖 13.1.2 프로그래밍 언어 관점의 타입</h3>\n<p>프로그래밍 언어 관점에서 타입은 연속적인 비트에 의미와 제약을 부여하기 위해 사용하며 두 가지 목적이 있다.</p>\n<ol>\n<li>타입에 수행될 수 있는 유효한 오퍼레이션의 집합을 정의</li>\n<li>타입에 수행되는 오퍼레이션에 대해 미리 약속된 문맥을 제공</li>\n</ol>\n<p>타입은 적용 가능한 오퍼레이션의 종류와 의미를 정의함으로써 코드의 의미를 명확하게 전달하고 개발자의 실수를 방지하기 위해 사용</p>\n<h3 id=\"-1313-객체지향-패러다임-관점의-타입\" style=\"position:relative;\"><a href=\"#-1313-%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84-%EA%B4%80%EC%A0%90%EC%9D%98-%ED%83%80%EC%9E%85\" aria-label=\" 1313 객체지향 패러다임 관점의 타입 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>🔖 13.1.3 객체지향 패러다임 관점의 타입</h3>\n<ul>\n<li>개념 관점에서 타입이란 공통의 특징을 공유하는 대상들의 분류다.</li>\n<li>프로그래밍 언어 관점에서 타입이란 동일한 오퍼레이션을 적용할 수 있는 인스턴스들의 집합</li>\n</ul>\n<p>객체의 타입이란 객체가 수신할 수 있는 메시지의 종류를 정의하는 것</p>\n<ul>\n<li>객체지향 프로그래밍에서 타입을 정의하는 것은 객체의 <strong>퍼블릭 인터페이스</strong>를 정의하는 것과 동일</li>\n<li>동일한 퍼블릭 인터페이스를 제공하는 객체들은 동일한 타입으로 분류된다.</li>\n<li>객체의 타입을 결정하는 것은 내부의 속성이 아니라 객체가 외부에 제공하는 행동이다.</li>\n</ul>\n<h2 id=\"-132-타입-계층\" style=\"position:relative;\"><a href=\"#-132-%ED%83%80%EC%9E%85-%EA%B3%84%EC%B8%B5\" aria-label=\" 132 타입 계층 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>📖 13.2 타입 계층</h2>\n<h3 id=\"-1321-타입-사이의-포함관계\" style=\"position:relative;\"><a href=\"#-1321-%ED%83%80%EC%9E%85-%EC%82%AC%EC%9D%B4%EC%9D%98-%ED%8F%AC%ED%95%A8%EA%B4%80%EA%B3%84\" aria-label=\" 1321 타입 사이의 포함관계 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>🔖 13.2.1 타입 사이의 포함관계</h3>\n<p>타입이 다른 타입에 포함될 수 있기 때문에 동일한 인스턴스가 하나 이상의 타입으로 분류되는 것도 가능</p>\n<p>타입 계층을 구성하는 두 타입 관계에서 더 일반적인 타입을 **슈퍼타입(supertype)**이라고 부르고 더 특수한 타입을 **서브타입(subtype)**이라고 부른다.</p>\n<p>내연 관점</p>\n<ul>\n<li>일반화: 어떤 타입의 정의를 좀 더 보편적이고 추상적으로 만드는 과정을 의미</li>\n<li>특수화: 어떤 타입의 정의를 좀 더 구체적이고 문맥 종속적으로 만드는 과정을 의미</li>\n</ul>\n<p>외연 관점</p>\n<ul>\n<li>슈퍼셋(superset): 일반적인 타입의 인스턴스 집합은 특수한 타입의 인스턴스 집합을 포함</li>\n<li>서브셋(subset): 특수한 타입의 인스턴스 집합은 일반적인 타입의 인스턴스 집합에 포함</li>\n</ul>\n<h3 id=\"-1322-객체지향-프로그래밍과-타입-계층\" style=\"position:relative;\"><a href=\"#-1322-%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EA%B3%BC-%ED%83%80%EC%9E%85-%EA%B3%84%EC%B8%B5\" aria-label=\" 1322 객체지향 프로그래밍과 타입 계층 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>🔖 13.2.2 객체지향 프로그래밍과 타입 계층</h3>\n<ul>\n<li>슈퍼타입이란 서브타입이 정의한 퍼블릭 인터페이스를 일반화시켜 상대적으로 범용적이고 넓은 의미로 정의</li>\n<li>서브타입이란 슈퍼타입이 정의한 퍼블릭 인터페이스를 특수화시켜 상대적으로 구체적이고 좁은 의미로 정의</li>\n</ul>\n<p>서브타입의 인스턴스는 슈퍼타입의 인스턴스로 간주될 수 있다.</p>\n<h2 id=\"-133-서브클래싱과-서브타이핑\" style=\"position:relative;\"><a href=\"#-133-%EC%84%9C%EB%B8%8C%ED%81%B4%EB%9E%98%EC%8B%B1%EA%B3%BC-%EC%84%9C%EB%B8%8C%ED%83%80%EC%9D%B4%ED%95%91\" aria-label=\" 133 서브클래싱과 서브타이핑 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>📖 13.3 서브클래싱과 서브타이핑</h2>\n<h3 id=\"-1331-언제-상속을-사용해야-하는가\" style=\"position:relative;\"><a href=\"#-1331-%EC%96%B8%EC%A0%9C-%EC%83%81%EC%86%8D%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%B4%EC%95%BC-%ED%95%98%EB%8A%94%EA%B0%80\" aria-label=\" 1331 언제 상속을 사용해야 하는가 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>🔖 13.3.1 언제 상속을 사용해야 하는가?</h3>\n<p>아래 두 질문에 모두 '예'라고 답할 수 있는 경우에만 상속을 사용</p>\n<ol>\n<li>상속 관계가 is-a 관계를 모델링하는가?</li>\n<li>클라이언트 입장에서 부모 클래스의 타입으로 자식 클래스를 사용해도 무방한가?</li>\n</ol>\n<h3 id=\"-1332-is-a-관계\" style=\"position:relative;\"><a href=\"#-1332-is-a-%EA%B4%80%EA%B3%84\" aria-label=\" 1332 is a 관계 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>🔖 13.3.2 is-a 관계</h3>\n<p>어떤 타입 S가 다른 타입 T의 일종이라면 당연히 <code>타입 S는 타입 T다</code>라고 답할 수 있어야 한다.</p>\n<p>타입 계층의 의미는 행동이라는 문맥에 따라 달라질 수 있다.</p>\n<ul>\n<li>ex. 펭귄은 새다, 새는 날 수 있다.</li>\n<li>행동호환성이 더 중요</li>\n</ul>\n<h3 id=\"-1333-행동-호환성\" style=\"position:relative;\"><a href=\"#-1333-%ED%96%89%EB%8F%99-%ED%98%B8%ED%99%98%EC%84%B1\" aria-label=\" 1333 행동 호환성 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>🔖 13.3.3 행동 호환성</h3>\n<p>타입의 이름 사이에 개념적으로 어떤 연관성이 있다고 하더라도 행동에 연관성이 없다면 is-a 관계를 사용하지 말아야 한다.</p>\n<ul>\n<li>행동의 호환 여부를 판단하는 기준은 <strong>클라이언트의 관점</strong>이다.</li>\n</ul>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public void flyBird(Bird bird) {\n\n  // 인자로 전달된 모든 bird들은 날 수 있어야 한다.\n  bird.fly();\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public class Penguin extends Bird {\n\n  ...\n\n  @Override\n  public void fly() {}\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>모든 bird가 날 수 있다는 클라이언트의 기대를 만족시키지 못한다.</li>\n</ul>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public class Penguin extends Bird {\n\n  ...\n\n  @Override\n  public void fly() {\n      throw new UnsupportedOperationException();\n  }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>UnsupportedOperationException</code> 예외가 던져질 것이라고는 기대하지 않았을 것이다.</li>\n</ul>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public void flyBird(Bird bird) {\n\n  // 인자로 전달된 모든 birtd가 Penguin의 인스턴스가 아닐 경우에만 fly() 메시지를 전송한다.\n  if (!(bird instanceof Penguin)) {\n      bird.fly();\n  }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>Penguin 이외에 날 수 없는 또 다른 새가 상속 계층에 추가 될 수도 있어 결합도를 높인다.</li>\n<li>개방-폐쇄 원칙을 위반</li>\n</ul>\n<h3 id=\"-1334-클라이언트의-기대에-따라-계층-분리하기\" style=\"position:relative;\"><a href=\"#-1334-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8%EC%9D%98-%EA%B8%B0%EB%8C%80%EC%97%90-%EB%94%B0%EB%9D%BC-%EA%B3%84%EC%B8%B5-%EB%B6%84%EB%A6%AC%ED%95%98%EA%B8%B0\" aria-label=\" 1334 클라이언트의 기대에 따라 계층 분리하기 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>🔖 13.3.4 클라이언트의 기대에 따라 계층 분리하기</h3>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public class Bird {\n  ...\n}\n\npublic class FlyingBird extends Bird {\n  \n  public void fly() { ... }\n  \n  ...\n}\n\npublic class Penguin extends Bird {\n  ...\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>모든 클래스들이 행동호환성을 만족시킨다.</li>\n</ul>\n<p>이 문제를 해결하는 다른 방법은 클라이언트에 따라 인터페이스를 분리하는 것이지만 더 좋은 방법은 합성을 사용하는 것이다.</p>\n<blockquote>\n<p>자연어에 현혹되지 말고 요구사항 속에서 클라이언트가 기대하는 행동에 집중</p>\n</blockquote>\n<h3 id=\"-1335-서브클래싱과-서브타이핑\" style=\"position:relative;\"><a href=\"#-1335-%EC%84%9C%EB%B8%8C%ED%81%B4%EB%9E%98%EC%8B%B1%EA%B3%BC-%EC%84%9C%EB%B8%8C%ED%83%80%EC%9D%B4%ED%95%91\" aria-label=\" 1335 서브클래싱과 서브타이핑 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>🔖 13.3.5 서브클래싱과 서브타이핑</h3>\n<p>상속을 사용하는 두 가지 목적</p>\n<ol>\n<li>\n<p>**서브클래싱(subclassing)</p>\n<ul>\n<li>다른 클래스의 코드를 재사용할 목적으로 상속을 사용하는 경우</li>\n<li>자식 클래스와 부모 클래스의 행동이 호환되지 않기 때문에 자식 클래스의 인스턴스가 부모 클래스의 인스턴스를 대체할 수 없다.</li>\n<li>구현상속(implementation inheritance) 또는 클래스 상속(class inheritance)**이라고 부른다.</li>\n</ul>\n</li>\n<li>\n<p>**서브 타이핑(subtyping)</p>\n<ul>\n<li>타입 계층을 구성하기 위해 상속을 사용하는 경우</li>\n<li>서브타이핑에서는 자식 클래스와 부모 클래스의 행동이 호환되기 때문에 자식 클래스의 인스턴스가 부모 클래스의 인스턴스를 대체할 수 있다.</li>\n<li>이때 부모 클래스는 자식클래스의 슈퍼타입이 되고 자식 클래스는 부모 클래스의 서브타입이 된다.</li>\n<li>인터페이스 상속(interface inheritance)이라고 부른다.</li>\n</ul>\n</li>\n</ol>\n<p>어떤 타입이 다른 타입의 서브타입이 되기 위해서는 <strong>행동 호환성</strong>을 만족시켜야 한다. 자식 클래스와 부모 클래스 사이의 행동 호환성은 부모 클래스에 대한 자식 클래스의 **대체 가능성(substitutability)**을 포함한다.</p>\n<h2 id=\"-134-리스코프-치환-원칙\" style=\"position:relative;\"><a href=\"#-134-%EB%A6%AC%EC%8A%A4%EC%BD%94%ED%94%84-%EC%B9%98%ED%99%98-%EC%9B%90%EC%B9%99\" aria-label=\" 134 리스코프 치환 원칙 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>📖 13.4 리스코프 치환 원칙</h2>\n<blockquote>\n<p>서브타입은 그것의 기반 타입에 대해 대체 가능해야 한다.</p>\n</blockquote>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@AllArgsConstructor\npublic class Rectangle {\n    \n    private final int x;\n    \n    private final int y;\n    \n    @Getter\n    @Setter\n    private int width;\n    \n    @Getter\n    @Setter\n    private int height;\n    \n    public int getArea() {\n        return width * height;\n    }\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public class Square extends Rectangle {\n\n    public Square(int x, int y, int width, int height) {\n        super(x, y, width, height);\n    }\n\n    @Override\n    public void setWidth(int width) {\n        super.setWidth(width);\n        super.setHeight(width);\n    }\n\n    @Override\n    public void setHeight(int height) {\n        super.setWidth(height);\n        super.setHeight(height);\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>Square의 너비와 높이는 항상 더 나중에 설정된 height의 값으로 설정된다.</li>\n<li>Square는 Rectangle의 구현을 재사용하고 있을 뿐이다. 즉, 서브클래싱 관계다.</li>\n</ul>\n<h3 id=\"-1341-클라이언트와-대체-가능성\" style=\"position:relative;\"><a href=\"#-1341-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8%EC%99%80-%EB%8C%80%EC%B2%B4-%EA%B0%80%EB%8A%A5%EC%84%B1\" aria-label=\" 1341 클라이언트와 대체 가능성 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>🔖 13.4.1 클라이언트와 대체 가능성</h3>\n<blockquote>\n<p>클라이언트와 격리한 채로 본 모델은 의미 있게 검증하는 것이 불가능하다.</p>\n</blockquote>\n<ul>\n<li>리스코프 치환 원칙은 상속 관계에 있는 두 클래스 사이의 관계를 클라이언트와 떨어트려 놓고 판단하지 말라고 속삭인다.</li>\n</ul>\n<h3 id=\"-1342-is-a-관계-다시-살펴보기\" style=\"position:relative;\"><a href=\"#-1342-is-a-%EA%B4%80%EA%B3%84-%EB%8B%A4%EC%8B%9C-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0\" aria-label=\" 1342 is a 관계 다시 살펴보기 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>🔖 13.4.2 is-a 관계 다시 살펴보기</h3>\n<p>클라이언트 관점에서 자식 클래스의 행동이 부모 클래스의 행동과 호환되지 않고 그로 인해 대체가 불가능하다면 어휘적으로 is-a라고 말할 수 있다고 하더라도 그 관계를 is-a 관계라고 할 수 없다.</p>\n<ul>\n<li>상속이 서브타이핑을 위해 사용될 경우에만 is-a 관계</li>\n</ul>\n<h3 id=\"-1343-리스코프-치환-원칙은-유연한-설계의-기반이다\" style=\"position:relative;\"><a href=\"#-1343-%EB%A6%AC%EC%8A%A4%EC%BD%94%ED%94%84-%EC%B9%98%ED%99%98-%EC%9B%90%EC%B9%99%EC%9D%80-%EC%9C%A0%EC%97%B0%ED%95%9C-%EC%84%A4%EA%B3%84%EC%9D%98-%EA%B8%B0%EB%B0%98%EC%9D%B4%EB%8B%A4\" aria-label=\" 1343 리스코프 치환 원칙은 유연한 설계의 기반이다 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>🔖 13.4.3 리스코프 치환 원칙은 유연한 설계의 기반이다</h3>\n<p>리스코프 치환 원칙은 개방-폐쇄 원칙을 만족하는 설계를 위한 전제 조건이다.</p>\n<ul>\n<li>자식 클래스가 클라이언트의 관점에서 부모 클래스를 대체할 수 있다면 기능 확장을 위해 자식 클래스를 추가하더라도 코드를 수정할 필요가 없어진다.</li>\n</ul>\n<h3 id=\"-1344-타입-계층과-리스코프-치환-원칙\" style=\"position:relative;\"><a href=\"#-1344-%ED%83%80%EC%9E%85-%EA%B3%84%EC%B8%B5%EA%B3%BC-%EB%A6%AC%EC%8A%A4%EC%BD%94%ED%94%84-%EC%B9%98%ED%99%98-%EC%9B%90%EC%B9%99\" aria-label=\" 1344 타입 계층과 리스코프 치환 원칙 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>🔖 13.4.4 타입 계층과 리스코프 치환 원칙</h3>\n<p>클래스 상속은 타입 계층을 구현할 수 있는 다양한 방법 중 하나일 뿐이다.</p>\n<ul>\n<li>구현 방법과 무관하게 클라이언트의 관점에서 슈퍼타입에 대해 기대하는 모든 것이 서브타입에게도 적용돼야 한다.</li>\n</ul>\n<h2 id=\"-135-계약에-의한-설계와-서브타이핑\" style=\"position:relative;\"><a href=\"#-135-%EA%B3%84%EC%95%BD%EC%97%90-%EC%9D%98%ED%95%9C-%EC%84%A4%EA%B3%84%EC%99%80-%EC%84%9C%EB%B8%8C%ED%83%80%EC%9D%B4%ED%95%91\" aria-label=\" 135 계약에 의한 설계와 서브타이핑 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>📖 13.5 계약에 의한 설계와 서브타이핑</h2>\n<p>계약에 의한 설계(Design By Contract, DBC)</p>\n<ul>\n<li>클라이언트와 서버 사이의 협력을 의무와 이익으로 구성된 계약의 관점에서 표현하는 것</li>\n<li>사전조건: 클라이언트가 정상적으로 메서드를 실행하기 위해 만족시켜야 하는 조건</li>\n<li>사후조건: 메서드가 실행된 후에 서버가 클라이언트에게 보장해야 하는 조건</li>\n<li>클래스 불변식: 메서드 실행 전과 실행 후에 인스턴스가 만족시켜야 하는 것</li>\n</ul>\n<blockquote>\n<p>서브타입이 리스코프 치환 원칙을 만족시키기 위해서는 클라이언트와 슈퍼타입 간에 체결된 '계약'을 준수해야 한다.</p>\n</blockquote>\n<h3 id=\"-1351-서브타입과-계약\" style=\"position:relative;\"><a href=\"#-1351-%EC%84%9C%EB%B8%8C%ED%83%80%EC%9E%85%EA%B3%BC-%EA%B3%84%EC%95%BD\" aria-label=\" 1351 서브타입과 계약 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>🔖 13.5.1 서브타입과 계약</h3>\n<p>어떤 타입이 슈퍼타입에서 정의한 사전조건보다 더 약한 사전조건을 정의하고 있다면 그 타입은 서브타입이 될 수 있지만 더 강한 사전조건을 정의한다면 서브타입이 될 수 없다.</p>\n<p>계약에 의한 설계는 클라이언트 관점에서의 대체 가능성을 계약으로 설명할 수 있다는 사실을 잘 보여준다.</p>","excerpt":"상속의 용도 타입 계층 구현 코드 재사용 📖 13.1 타입 프로그래밍 언어 관점에서의 타입과 개념 관점에서의 타입 🔖 13.1.1 개념 관점의 타입 개념 관점에서 타입이란 우리가 인지하는 세상의 사물의 종류를 의미한다. 어떤 대상이 타입으로 분류될 때 그 대상을 타입의 인스턴스(instance)**라고 부른다. 타입의 인스턴스를 객체라고 부름. 심볼(symbol): 타입에 이름을 붙인 것 내연(intension…","fields":{"slug":"/backend/object/chapter13/서브클래싱과_서브타이핑/"},"frontmatter":{"title":"Object - 13장 서브클래싱과 서브타이핑","thumbnail":{"childImageSharp":{"fluid":{"src":"/static/dd0e1990925e942697544e2bdcd9332e/9b73b/object.png"}}},"draft":false,"category":"Back-End","tags":["java"],"date":"November 19, 2023"}},"previous":{"id":"3210e7da-a86b-584f-9d51-04ced27c803f","html":"<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<h2 id=\"-151-디자인-패텅과-설계-재사용\" style=\"position:relative;\"><a href=\"#-151-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%85%85%EA%B3%BC-%EC%84%A4%EA%B3%84-%EC%9E%AC%EC%82%AC%EC%9A%A9\" aria-label=\" 151 디자인 패텅과 설계 재사용 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>📖 15.1 디자인 패텅과 설계 재사용</h2>\n<h3 id=\"-1511-소프트웨어-패턴\" style=\"position:relative;\"><a href=\"#-1511-%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4-%ED%8C%A8%ED%84%B4\" aria-label=\" 1511 소프트웨어 패턴 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>🔖 15.1.1 소프트웨어 패턴</h3>\n<p>패턴이란❓</p>\n<ul>\n<li>패턴은 반복적으로 발생하는 문제와 해법의 쌍으로 정의</li>\n<li>패턴을 사용함으로써 이미 알려진 문제와 이에 대한 해법을 문서로 정리할 수 있으며, 이 지식을 다른 사람과 의사소통할 수 있다.</li>\n<li>패턴은 추상적인 원칙과 실제 코드 작성 사이의 간극을 메워주며 실질적인 코드 작성을 돕는다.</li>\n<li>패턴의 요점은 패턴이 실무에서 탄생했다는 점이다.</li>\n</ul>\n<blockquote>\n<p>하나의 실무 컨텍스트에서 유용하게 사용해 왔고 다른 실무 컨텍스트에서도 유용할 것이라고 예상되는 아이디어다. - 마틴 파울러</p>\n</blockquote>\n<p>🛠️ 3의 규칙</p>\n<ul>\n<li>최소 세 가지의 서로 다른 시스템에 특별한 문제 없이 적용할 수 있고 유용한 경우에만 패턴으로 간주할 수 있다.</li>\n</ul>\n<p>패턴의 이름은 높은 수준의 대화를 가능하게하는 원천이다.</p>\n<p>패턴은 홀로 존재하지 않는다.</p>\n<ul>\n<li>연관된 패턴들의 집합들이 모여 하나의 패턴 언어(패턴 시스템)를 구성한다.</li>\n</ul>\n<h3 id=\"-1512-패턴-분류\" style=\"position:relative;\"><a href=\"#-1512-%ED%8C%A8%ED%84%B4-%EB%B6%84%EB%A5%98\" aria-label=\" 1512 패턴 분류 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>🔖 15.1.2 패턴 분류</h3>\n<ul>\n<li>디자인 패턴\n<ul>\n<li>특정 정황 내에서 일반적인 설계 문제를 해결하며, 협력하는 컴포넌트들 사이에서 반복적으로 발생하는 구조를 서술</li>\n</ul>\n</li>\n<li>아키텍처 패턴\n<ul>\n<li>소프트웨어의 전체적인 구조를 결정하기 위해 사용할 수 있다.</li>\n<li>미리 정의된 서브시스템들을 제공하고, 각 서브시스템들의 책임을 정의하며, 서브시스템들 사이의 관계를 조직화하는 규칙과 가이드라인을 포함</li>\n<li>구체적인 소프트웨어 아키텍처를 위한 템플릿을 제공</li>\n</ul>\n</li>\n<li>이디엄(Idiom)\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<h3 id=\"-1513-패턴과-책임-주도-설계\" style=\"position:relative;\"><a href=\"#-1513-%ED%8C%A8%ED%84%B4%EA%B3%BC-%EC%B1%85%EC%9E%84-%EC%A3%BC%EB%8F%84-%EC%84%A4%EA%B3%84\" aria-label=\" 1513 패턴과 책임 주도 설계 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>🔖 15.1.3 패턴과 책임-주도 설계</h3>\n<p>객체지향 설계에서 가장 중요한 일은 올바른 책임을 올바른 객체에게 할당하고 객체 간의 유연한 협력관계를 구축하는 일이다.</p>\n<ul>\n<li>패턴을 따르면 특정한 상황에 적용할 수 있는 설계를 쉽고 빠르게 떠올릴 수 있다.</li>\n<li>패턴의 구성 요소는 클래스와 메서드가 아니라 '역할과 책임'이다.</li>\n<li>어떤 구현 코드가 어떤 디자인 패턴을 따른다고 이야기할 때는 역할, 책임, 협력의 관점에서 유사성을 공유한다는 것이지 특정한 구현 방식을 강제하는 것은 아니다.</li>\n</ul>\n<h3 id=\"-1514-캡슐화와-디자인-패턴\" style=\"position:relative;\"><a href=\"#-1514-%EC%BA%A1%EC%8A%90%ED%99%94%EC%99%80-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4\" aria-label=\" 1514 캡슐화와 디자인 패턴 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>🔖 15.1.4 캡슐화와 디자인 패턴</h3>\n<p>대부분의 디자인 패턴의 목적은 특정한 변경을 캡슐화함으로써 유연하고 일관성 있는 협력을 설계할 수 있는 경험을 공유하는 것</p>\n<ul>\n<li>디자인 패턴에서 중요한 것은 디자인 패턴의 구현 방법이나 구조가 아니다.</li>\n<li>어떤 디자인 패턴이 어떤 변경을 캡슐화하는지를 이해하는 것이 중요하다.</li>\n<li>디자인 패턴이 변경을 캡슐화하기 위해 어떤 방법을 사용하는지를 이해하는 것이 더 중요하다.</li>\n</ul>\n<h3 id=\"-1515-패턴은-출발점이다\" style=\"position:relative;\"><a href=\"#-1515-%ED%8C%A8%ED%84%B4%EC%9D%80-%EC%B6%9C%EB%B0%9C%EC%A0%90%EC%9D%B4%EB%8B%A4\" aria-label=\" 1515 패턴은 출발점이다 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>🔖 15.1.5 패턴은 출발점이다</h3>\n<p>패턴은 출발점이지 목적지가 아니다. 디자인 패턴이 현재의 요구사항이나 적용 기술, 프레임워크에 적합하지 않다면 패턴을 그대로 따르지 말고 목적에 맞게 패턴을 수정하라.</p>\n<ul>\n<li>해결하려는 문제가 아니라 패턴이 제시하는 구조를 맹목적으로 따르는 것은 불필요하게 복잡하고, 난해하며, 유지보수하기 어려운 시스템을 낳는다.</li>\n</ul>\n<h2 id=\"-152-프레임워크와-코드-재사용\" style=\"position:relative;\"><a href=\"#-152-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC%EC%99%80-%EC%BD%94%EB%93%9C-%EC%9E%AC%EC%82%AC%EC%9A%A9\" aria-label=\" 152 프레임워크와 코드 재사용 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>📖 15.2 프레임워크와 코드 재사용</h2>\n<h3 id=\"-1521-코드-재사용-대-설계-재사용\" style=\"position:relative;\"><a href=\"#-1521-%EC%BD%94%EB%93%9C-%EC%9E%AC%EC%82%AC%EC%9A%A9-%EB%8C%80-%EC%84%A4%EA%B3%84-%EC%9E%AC%EC%82%AC%EC%9A%A9\" aria-label=\" 1521 코드 재사용 대 설계 재사용 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>🔖 15.2.1 코드 재사용 대 설계 재사용</h3>\n<p>재사용 관점에서 설계 재사용보다 더 좋은 방법은 코드 재사용이다.</p>\n<p>프레임워크란❓</p>\n<ul>\n<li>추상 클래스나 인터페이스를 정의하고 인스턴스 사이의 상호작용을 통해 시스템 전체 혹은 일부를 구현해 놓은 재사용 가능한 설계</li>\n<li>애플리케이션 개발자가 현재의 요구사항에 맞게 머스터마이징할 수 있는 애플리케이션의 골격(skeleton)</li>\n<li>코드를 재사용함으로써 설계 아이디어를 재사용</li>\n</ul>\n<h3 id=\"-1522-상위-정책과-하위-정책으로-패키지-분리하기\" style=\"position:relative;\"><a href=\"#-1522-%EC%83%81%EC%9C%84-%EC%A0%95%EC%B1%85%EA%B3%BC-%ED%95%98%EC%9C%84-%EC%A0%95%EC%B1%85%EC%9C%BC%EB%A1%9C-%ED%8C%A8%ED%82%A4%EC%A7%80-%EB%B6%84%EB%A6%AC%ED%95%98%EA%B8%B0\" aria-label=\" 1522 상위 정책과 하위 정책으로 패키지 분리하기 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>🔖 15.2.2 상위 정책과 하위 정책으로 패키지 분리하기</h3>\n<p>상위 정책은 상대적으로 변경에 안정적이지만 세부 사항은 자주 변경된다. 그리고 상위 정책이 세부 사항에 비해 재사용될 가능성이 높다.</p>\n<ul>\n<li>상위 정책이 세부 사항보다 더 다양한 상황에서 재사용될 수 있어야 한다.\n<ul>\n<li>상위 정책이 세부 사항에 의존하게 되면 상위 정책이 필요한 모든 경우에 세부 사항도 항상 함께 존재해야 하기 때문에 상위 정책의 재사용성이 낮아진다.</li>\n<li>의존성 역전 원칙에 맞게 상위 정책과 세부 사항 모두 추상화에 의존하게 만든다.</li>\n</ul>\n</li>\n<li>변하는 것(구체적인 세부 사항)과 변하지 않는 것(상위 정책에 속하는 역할들의 협력구조)을 서로 다른 주기로 배포할 수 있도록 별도의 '배포 단위'로 분리해야 한다.\n<ul>\n<li>상위 정책을 구현하고 있는 패키지를 다른 애플리케이션에 재사용할 수 있다.</li>\n</ul>\n</li>\n</ul>\n<h3 id=\"-1523-제어-역전-원리\" style=\"position:relative;\"><a href=\"#-1523-%EC%A0%9C%EC%96%B4-%EC%97%AD%EC%A0%84-%EC%9B%90%EB%A6%AC\" aria-label=\" 1523 제어 역전 원리 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>🔖 15.2.3 제어 역전 원리</h3>\n<p>프레임워크를 사용할 경우 개별 애플리케이션에서 프레임워크로 제어 흐름의 주체가 이동한다.</p>\n<ul>\n<li>의존성을 역전시키면 제어 흐름의 주체 역시 역전된다.</li>\n<li>IoC 원리, Hollywood 원리</li>\n</ul>\n<p>프레임워크에서는 일반적인 해결책만 제공하고 애플리케이션에 따라 달라질 수 있는 특정한 동작은 비워둔다.</p>\n<ul>\n<li>완성되지 않은 채로 남겨진 동작을 훅(hook)이라고 부른다.</li>\n<li>재정의된 훅은 제어 역전 원리에 따라 프레임워크가 원하는 시점에 호출</li>\n<li>우리는 프레임워크가 적절한 시점에 실행할 것으로 예상되는 코드를 작성할 뿐이다.</li>\n</ul>\n<p>제어의 역전이 프레임워크의 핵심 개념인 동시에 코드의 재사용을 가능하게 하는 힘이라는 사실을 이해해야 한다.</p>","excerpt":"디자인 패턴 소프트웨어 설계에서 반복적으로 발생하는 문제에 대해 반복적으로 적용할 수 있는 해결 방법 설계를 재사용하는 것이 목적 프레임워크 설계와 코드를 함께 재사용하는 것이 목적 특정한 변경을 일관성 있게 다룰 수 있는 확장 가능한 코드 템플릿을 제공 📖 15.1 디자인 패텅과 설계 재사용 🔖 15.1.…","fields":{"slug":"/backend/object/chapter15/디자인_패턴과_프레임워크/"},"frontmatter":{"title":"Object - 15장 디자인 패턴과 프레임워크","thumbnail":{"childImageSharp":{"fluid":{"src":"/static/dd0e1990925e942697544e2bdcd9332e/9b73b/object.png"}}},"draft":false,"category":"Back-End","tags":["java"],"date":"December 03, 2023"}},"node":{"id":"d8be73e1-803f-536a-af27-6b27955acd94","html":"<p>객체는 협력을 위해 존재한다.</p>\n<h2 id=\"-141-핸드폰-과금-시스템-변경하기\" style=\"position:relative;\"><a href=\"#-141-%ED%95%B8%EB%93%9C%ED%8F%B0-%EA%B3%BC%EA%B8%88-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EB%B3%80%EA%B2%BD%ED%95%98%EA%B8%B0\" aria-label=\" 141 핸드폰 과금 시스템 변경하기 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>📖 14.1 핸드폰 과금 시스템 변경하기</h2>\n<h3 id=\"-1411-기본-정책-확장\" style=\"position:relative;\"><a href=\"#-1411-%EA%B8%B0%EB%B3%B8-%EC%A0%95%EC%B1%85-%ED%99%95%EC%9E%A5\" aria-label=\" 1411 기본 정책 확장 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>🔖 14.1.1 기본 정책 확장</h3>\n<p>기본 정책을 구성하는 4가지 방식</p>\n<ol>\n<li>고정요금 방식</li>\n<li>시간대별 방식</li>\n<li>요일별 방식</li>\n<li>구간별 방식</li>\n</ol>\n<h3 id=\"-1412-고정요금-방식-구현하기\" style=\"position:relative;\"><a href=\"#-1412-%EA%B3%A0%EC%A0%95%EC%9A%94%EA%B8%88-%EB%B0%A9%EC%8B%9D-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0\" aria-label=\" 1412 고정요금 방식 구현하기 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>🔖 14.1.2 고정요금 방식 구현하기</h3>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@RequiredArgsConstructor\npublic class FixedFeePolicy extends BasicRatePolicy {\n\n    private final Money amount;\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<h3 id=\"-1413-시간대별-방식-구현하기\" style=\"position:relative;\"><a href=\"#-1413-%EC%8B%9C%EA%B0%84%EB%8C%80%EB%B3%84-%EB%B0%A9%EC%8B%9D-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0\" aria-label=\" 1413 시간대별 방식 구현하기 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>🔖 14.1.3 시간대별 방식 구현하기</h3>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@Getter\n@RequiredArgsConstructor\npublic class DateTimeInterval {\n\n    private final LocalDateTime from;\n    private final LocalDateTime to;\n\n    public static DateTimeInterval of(LocalDateTime from, LocalDateTime to) {\n        return new DateTimeInterval(from, to);\n    }\n\n    public static DateTimeInterval toMidnight(LocalDateTime from) {\n        return new DateTimeInterval(\n                from,\n                LocalDateTime.of(from.toLocalDate(), LocalTime.of(23, 59, 59, 999_999_999)));\n    }\n\n    public static DateTimeInterval fromMidnight(LocalDateTime to) {\n        return new DateTimeInterval(\n                LocalDateTime.of(to.toLocalDate(), LocalTime.of(0, 0)),\n                to);\n    }\n\n    public static DateTimeInterval during(LocalDate date) {\n        return new DateTimeInterval(\n                LocalDateTime.of(date, LocalTime.of(0, 0)),\n                LocalDateTime.of(date, LocalTime.of(23, 59, 59, 999_999_999)));\n    }\n\n    public Duration duration() {\n        return Duration.between(from, to);\n    }\n    \n    public List&lt;DateTimeInterval&gt; splitByDay() {\n        if (days() &gt; 0) {\n            return splitByDay(days());\n        }\n        \n        return List.of(this);\n    }\n    \n    private long days() {\n        return Duration.between(from.toLocalDate().atStartOfDay(), to.toLocalDate().atStartOfDay()).toDays();\n    }\n    \n    private List&lt;DateTimeInterval&gt; splitByDay(long days) {\n        List&lt;DateTimeInterval&gt; result = new ArrayList&lt;&gt;();\n        \n        addFirstDay(result);\n        addMiddleDays(result, days);\n        addLastDay(result);\n        \n        return result;\n    }\n    \n    private void addFirstDay(List&lt;DateTimeInterval&gt; result) {\n        result.add(DateTimeInterval.toMidnight(from));\n    }\n    \n    private void addMiddleDays(List&lt;DateTimeInterval&gt; result, long days) {\n        for (int loop = 1; loop &lt; days; loop++) {\n             result.add(DateTimeInterval.during(from.toLocalDate().plusDays(loop)));\n        }\n    }\n    \n    private void addLastDay(List&lt;DateTimeInterval&gt; result) {\n        result.add(DateTimeInterval.fromMidnight(to));\n    }\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public class Call {\n\n    @Getter\n    private final DateTimeInterval interval;\n\n    public Call(LocalDateTime from, LocalDateTime to) {\n        this.interval = DateTimeInterval.of(from, to);\n    }\n\n    public Duration getDuration() {\n        return interval.duration();\n    }\n\n    public LocalDateTime getFrom() {\n        return interval.getFrom();\n    }\n\n    public LocalDateTime getTo() {\n        return interval.getTo();\n    }\n\n    public List&lt;DateTimeInterval&gt; splitByDay() {\n        return interval.splitByDay();\n    }\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public class TimeOfDayDiscountPolicy extends BasicRatePolicy {\n\n    private List&lt;LocalTime&gt; starts = new ArrayList&lt;&gt;();\n    private List&lt;LocalTime&gt; ends = new ArrayList&lt;&gt;();\n    private List&lt;Duration&gt; durations = new ArrayList&lt;&gt;();\n    private List&lt;Money&gt; amounts = new ArrayList&lt;&gt;();\n\n    @Override\n    protected Money calculateCallFee(Call call) {\n        Money result = Money.ZERO;\n        for (DateTimeInterval interval : call.splitByDay()) {\n            for (int loop = 0; loop &lt; starts.size(); loop++) {\n                result.plus(amounts.get(loop).times(\n                        (double) Duration.between(from(interval, starts.get(loop)), to(interval, ends.get(loop)))\n                                .getSeconds() / durations.get(loop).getSeconds()));\n            }\n        }\n        return result;\n    }\n\n    private LocalTime from(DateTimeInterval interval, LocalTime from) {\n        return interval.getFrom().toLocalTime().isBefore(from) ? from : interval.getFrom().toLocalTime();\n    }\n\n    private LocalTime to(DateTimeInterval interval, LocalTime to) {\n        return interval.getTo().toLocalTime().isAfter(to) ? to : interval.getTo().toLocalTime();\n    }\n}</code>\n        </deckgo-highlight-code>\n<h3 id=\"-1414-요일별-방식-구현하기\" style=\"position:relative;\"><a href=\"#-1414-%EC%9A%94%EC%9D%BC%EB%B3%84-%EB%B0%A9%EC%8B%9D-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0\" aria-label=\" 1414 요일별 방식 구현하기 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>🔖 14.1.4 요일별 방식 구현하기</h3>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@RequiredArgsConstructor\npublic class DayOfWeekDiscountRule {\n    \n    private final List&lt;DayOfWeek&gt; dayOfWeeks = new ArrayList&lt;&gt;();\n    private final Duration duration = Duration.ZERO;\n    private final Money amount = Money.ZERO;\n    \n    public Money calculate(DateTimeInterval interval) {\n        if (dayOfWeeks.contains(interval.getFrom().getDayOfWeek())) {\n            return amount.times((double) interval.duration().getSeconds() / duration.getSeconds());\n        }\n        \n        return Money.ZERO;\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 DayOfWeekDiscountPolicy extends BasicRatePolicy {\n\n    private final List&lt;DayOfWeekDiscountRule&gt; rules = new ArrayList&lt;&gt;();\n\n    @Override\n    protected Money calculateCallFee(Call call) {\n        Money result = Money.ZERO;\n\n        for (DateTimeInterval interval : call.getInterval().splitByDay()) {\n            for (DayOfWeekDiscountRule rule : rules) {\n                result.plus(rule.calculate(interval));\n            }\n        }\n        \n        return result;\n    }\n}</code>\n        </deckgo-highlight-code>\n<h3 id=\"-1415-구간별-방식-구현하기\" style=\"position:relative;\"><a href=\"#-1415-%EA%B5%AC%EA%B0%84%EB%B3%84-%EB%B0%A9%EC%8B%9D-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0\" aria-label=\" 1415 구간별 방식 구현하기 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>🔖 14.1.5 구간별 방식 구현하기</h3>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public class DurationDiscountRule extends FixedFeePolicy {\n\n    private final Duration from;\n    private final Duration to;\n\n    public DurationDiscountRule(Money amount, Duration seconds, Duration from, Duration to) {\n        super(amount, seconds);\n        this.from = from;\n        this.to = to;\n    }\n\n    public Money calculate(Call call) {\n        if (call.getDuration().compareTo(to) &gt; 0) {\n            return Money.ZERO;\n        }\n\n        if (call.getDuration().compareTo(from) &lt; 0) {\n            return Money.ZERO;\n        }\n        \n        return super.calculateCallFee(new Call(call.getFrom().plus(from),\n                call.getDuration().compareTo(to) &gt; 0 ? call.getFrom().plus(to) : call.getTo()));\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\">@RequiredArgsConstructor\npublic class DurationDiscountPolicy extends BasicRatePolicy {\n\n    private final List&lt;DurationDiscountRule&gt; rules = new ArrayList&lt;&gt;();\n\n    @Override\n    protected Money calculateCallFee(Call call) {\n        Money result = Money.ZERO;\n        for (DurationDiscountRule rule : rules) {\n            result.plus(rule.calculate(call));\n        }\n        return result;\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>이해하기도 힘들고 설계 개선과 새로운 기능의 추가를 방해한다.</li>\n<li>코드 재사용을 위한 상속은 해롭다.</li>\n</ul>\n<h2 id=\"-142-설계에-일관성-부여하기\" style=\"position:relative;\"><a href=\"#-142-%EC%84%A4%EA%B3%84%EC%97%90-%EC%9D%BC%EA%B4%80%EC%84%B1-%EB%B6%80%EC%97%AC%ED%95%98%EA%B8%B0\" aria-label=\" 142 설계에 일관성 부여하기 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>📖 14.2 설계에 일관성 부여하기</h2>\n<p>협력을 일관성 있게 만들기 위해 다음과 같은 기본 지침을 따르자.</p>\n<ol>\n<li>변하는 개념을 변하지 않는 개념으로부터 분리하라.</li>\n<li>변하는 개념을 캡슐화하라.</li>\n</ol>\n<h3 id=\"-1421-조건-로직-대-객체-탐색\" style=\"position:relative;\"><a href=\"#-1421-%EC%A1%B0%EA%B1%B4-%EB%A1%9C%EC%A7%81-%EB%8C%80-%EA%B0%9D%EC%B2%B4-%ED%83%90%EC%83%89\" aria-label=\" 1421 조건 로직 대 객체 탐색 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>🔖 14.2.1 조건 로직 대 객체 탐색</h3>\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 Money.ZERO;\n    }\n    protected abstract Money getDiscountAmount(Screening screening);\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@AllArgsConstructor\npublic class Movie {\n\n    /**\n     * 제목\n     */\n    private String title;\n\n    /**\n     * 상영시간\n     */\n    private Duration runningTime;\n\n    /**\n     * 기본요금\n     */\n    @Getter\n    private Money fee;\n\n    /**\n     * 할인 정책\n     */\n    private DiscountPolicy discountPolicy;\n\n    public Money calculateMovieFee(Screening screening) {\n        return fee.minus(discountPolicy.calculateDiscountAmount(screening));\n    }\n\n    public void changeDiscountPolicy(DiscountPolicy discountPolicy) {\n        this.discountPolicy = discountPolicy;\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>실제로 협력에 참여하는 주체는 구체적인 객체다.</li>\n<li>변경에 초점을 맞추고 캡슐화의 관점에서 설계를 바라보면 일관성 있는 협력 패턴을 얻을 수 있다.</li>\n</ul>\n<h3 id=\"-1422-캡슐화-다시-살펴보기\" style=\"position:relative;\"><a href=\"#-1422-%EC%BA%A1%EC%8A%90%ED%99%94-%EB%8B%A4%EC%8B%9C-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0\" aria-label=\" 1422 캡슐화 다시 살펴보기 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>🔖 14.2.2 캡슐화 다시 살펴보기</h3>\n<p>데이터 은닉</p>\n<ul>\n<li>오직 외부에 공개된 메서드를 통해서만 객체의 내부에 접근할 수 있게 제한함으로써 객체 내부의 상태 구현을 숨기는 기법</li>\n<li>해당 클래스의 메서드만이 인스턴스 변수에 접근할 수 있어야 한다.</li>\n<li>캡슐화는 데이터 은닉 이상이다.</li>\n</ul>\n<blockquote>\n<p>캡슐화란 변하는 어떤 것이든 감추는 것이다.</p>\n</blockquote>\n<ul>\n<li>데이터 캡슐화</li>\n<li>메서드 캡슐화</li>\n<li>객체 캡슐화</li>\n<li>서브타입 캡슐화</li>\n</ul>\n<p>변경을 캡슐화할 수 있는 다양한 방법이 존재하지만 협력을 일관성 있게 만들기 위해 가장 일반적으로 사용하는 방법은 서브타입 캡슐화와 객체 캡슐화를 조합하는 것이다.</p>\n<ul>\n<li>변하는 부분을 분리해서 타입 계층을 만든다.</li>\n<li>변하지 않는 부분의 일부로 타입 계층을 합성한다.</li>\n</ul>\n<h2 id=\"-143-일관성-있는-기본-정책-구현하기\" style=\"position:relative;\"><a href=\"#-143-%EC%9D%BC%EA%B4%80%EC%84%B1-%EC%9E%88%EB%8A%94-%EA%B8%B0%EB%B3%B8-%EC%A0%95%EC%B1%85-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0\" aria-label=\" 143 일관성 있는 기본 정책 구현하기 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>📖 14.3 일관성 있는 기본 정책 구현하기</h2>\n<h3 id=\"-1431-변경-분리하기\" style=\"position:relative;\"><a href=\"#-1431-%EB%B3%80%EA%B2%BD-%EB%B6%84%EB%A6%AC%ED%95%98%EA%B8%B0\" aria-label=\" 1431 변경 분리하기 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>🔖 14.3.1 변경 분리하기</h3>\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<h3 id=\"-1432-변경-캡슐화하기\" style=\"position:relative;\"><a href=\"#-1432-%EB%B3%80%EA%B2%BD-%EC%BA%A1%EC%8A%90%ED%99%94%ED%95%98%EA%B8%B0\" aria-label=\" 1432 변경 캡슐화하기 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>🔖 14.3.2 변경 캡슐화하기</h3>\n<ul>\n<li>변하는 것: 적용조건</li>\n<li>변하지 않는 것: 규칙</li>\n</ul>\n<p>규칙으로부터 적용조건을 분리해서 추상화한 후 시간대별, 요일별, 구간별 방식을 이 추상화의 서브타입으로 만든다.</p>\n<h3 id=\"-1433-협력-패턴-설계하기\" style=\"position:relative;\"><a href=\"#-1433-%ED%98%91%EB%A0%A5-%ED%8C%A8%ED%84%B4-%EC%84%A4%EA%B3%84%ED%95%98%EA%B8%B0\" aria-label=\" 1433 협력 패턴 설계하기 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>🔖 14.3.3 협력 패턴 설계하기</h3>\n<ol>\n<li>적용조건을 가장 잘 알고 있는 정보 전문가인 <code>FeeCondition</code>에게 할당</li>\n<li>단위요금을 적용해서 요금을 계산하는 두 번째 작업은 요금기준의 정보 전문가인 <code>FeeRule</code>이 담당</li>\n</ol>\n<h3 id=\"-1434-추상화-수준에서-협력-패턴-구현하기\" style=\"position:relative;\"><a href=\"#-1434-%EC%B6%94%EC%83%81%ED%99%94-%EC%88%98%EC%A4%80%EC%97%90%EC%84%9C-%ED%98%91%EB%A0%A5-%ED%8C%A8%ED%84%B4-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0\" aria-label=\" 1434 추상화 수준에서 협력 패턴 구현하기 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>🔖 14.3.4 추상화 수준에서 협력 패턴 구현하기</h3>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">public interface FeeCondition {\n    \n    List&lt;DateTimeInterval&gt; findTimeIntervals(Call call);\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@RequiredArgsConstructor\npublic class FeePerDuration {\n\n    private final Money fee;\n\n    private final Duration duration;\n\n    public Money calculate(DateTimeInterval interval) {\n        return fee.times(Math.ceil((double) interval.duration().toNanos() / duration.toNanos()));\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 FeeRule {\n\n    private final FeeCondition feeCondition;\n\n    private final FeePerDuration feePerDuration;\n\n    public Money calculateFee(Call call) {\n        return feeCondition.findTimeIntervals(call)\n                .stream()\n                .map(feePerDuration::calculate)\n                .reduce(Money.ZERO, Money::plus);\n    }\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@RequiredArgsConstructor(access = AccessLevel.PROTECTED)\npublic abstract class BasicRatePolicy implements RatePolicy {\n\n    private final List&lt;FeeRule&gt; feeRules;\n\n    @Override\n    public Money calculateFee(Phone phone) {\n        return phone.getCalls()\n                .stream()\n                .map(this::calculate)\n                .reduce(Money.ZERO, Money::plus);\n    }\n\n    private Money calculate(Call call) {\n        return feeRules.stream()\n                .map(rule -&gt; rule.calculateFee(call))\n                .reduce(Money.ZERO, Money::plus);\n    }\n\n    protected abstract Money calculateCallFee(Call call);\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>변하지 않는 요소와 추상적인 요소만으로도 요금 계산에 필요한 전체적인 협력 구조를 설명할 수 있다.</li>\n</ul>\n<h3 id=\"-1435-구체적인-협력-구현하기\" style=\"position:relative;\"><a href=\"#-1435-%EA%B5%AC%EC%B2%B4%EC%A0%81%EC%9D%B8-%ED%98%91%EB%A0%A5-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0\" aria-label=\" 1435 구체적인 협력 구현하기 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>🔖 14.3.5 구체적인 협력 구현하기</h3>\n<h4 id=\"️-시간대별-정책\" style=\"position:relative;\"><a href=\"#%EF%B8%8F-%EC%8B%9C%EA%B0%84%EB%8C%80%EB%B3%84-%EC%A0%95%EC%B1%85\" 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 TimeOfDayFeeCondition implements FeeCondition {\n\n    private final LocalTime from;\n    private final LocalTime to;\n\n    @Override\n    public List&lt;DateTimeInterval&gt; findTimeIntervals(Call call) {\n        return call.getInterval().splitByDay()\n                .stream()\n                .filter(each -&gt; from(each).isBefore(to(each)))\n                .map(each -&gt; DateTimeInterval.of(\n                        LocalDateTime.of(each.getFrom().toLocalDate(), from(each)),\n                        LocalDateTime.of(each.getTo().toLocalDate(), to(each))))\n                .collect(toList());\n    }\n\n    public LocalTime from(DateTimeInterval interval) {\n        return interval.getFrom().toLocalTime().isBefore(from) ? from : interval.getFrom().toLocalTime();\n    }\n\n    public LocalTime to(DateTimeInterval interval) {\n        return interval.getTo().toLocalTime().isAfter(to) ? to : interval.getTo().toLocalTime();\n    }\n}</code>\n        </deckgo-highlight-code>\n<h4 id=\"️-요일별-정책\" style=\"position:relative;\"><a href=\"#%EF%B8%8F-%EC%9A%94%EC%9D%BC%EB%B3%84-%EC%A0%95%EC%B1%85\" 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 DayOfWeekFeeCondition implements FeeCondition {\n\n    private final List&lt;DayOfWeek&gt; dayOfWeeks;\n\n    @Override\n    public List&lt;DateTimeInterval&gt; findTimeIntervals(Call call) {\n        return call.getInterval()\n                .splitByDay()\n                .stream()\n                .filter(each -&gt; dayOfWeeks.contains(each.getFrom().getDayOfWeek()))\n                .collect(toList());\n    }\n}</code>\n        </deckgo-highlight-code>\n<h4 id=\"️-구간별-정책\" style=\"position:relative;\"><a href=\"#%EF%B8%8F-%EA%B5%AC%EA%B0%84%EB%B3%84-%EC%A0%95%EC%B1%85\" 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 DurationFeeCondition implements FeeCondition {\n\n    private final Duration from;\n    private final Duration to;\n\n    @Override\n    public List&lt;DateTimeInterval&gt; findTimeIntervals(Call call) {\n        if (call.getInterval().duration().compareTo(from) &lt; 0) {\n            return Collections.emptyList();\n        }\n\n        return List.of(DateTimeInterval.of(\n                call.getInterval().getFrom().plus(from),\n                call.getInterval().duration().compareTo(to) &gt; 0 ?\n                        call.getInterval().getFrom().plus(to) :\n                        call.getInterval().getTo()));\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>유사한 기능에 대해 유사한 협력 패턴을 적용하는 것은 객체지향 시스템에서 <strong>개념적 무결성</strong>을 유지할 수 있는 가장 효과적인 방법이다.</li>\n</ul>\n<h3 id=\"-1436-협력-패턴에-맞추기\" style=\"position:relative;\"><a href=\"#-1436-%ED%98%91%EB%A0%A5-%ED%8C%A8%ED%84%B4%EC%97%90-%EB%A7%9E%EC%B6%94%EA%B8%B0\" aria-label=\" 1436 협력 패턴에 맞추기 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>🔖 14.3.6 협력 패턴에 맞추기</h3>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">@RequiredArgsConstructor\npublic class FixedFeeCondition implements FeeCondition {\n\n    @Override\n    public List&lt;DateTimeInterval&gt; findTimeIntervals(Call call) {\n        return Collections.singletonList(call.getInterval());\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>개념적 무결성을 무너뜨리는 것보다는 약간의 부조화를 수용하는 편이 더 낫다.</li>\n</ul>\n<h3 id=\"-1437-패턴을-찾아라\" style=\"position:relative;\"><a href=\"#-1437-%ED%8C%A8%ED%84%B4%EC%9D%84-%EC%B0%BE%EC%95%84%EB%9D%BC\" aria-label=\" 1437 패턴을 찾아라 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>🔖 14.3.7 패턴을 찾아라</h3>\n<p>애플리케이션에서 유사한 기능에 대한 변경이 지속적으로 발생하고 있다면 변경을 캡슐화할 수 있는 적절한 추상화를 찾은 후, 이 추상화에 변하지 않는 공통적인 책임을 할당하라.</p>\n<p>협력을 일관성 있게 만든다는 것은 유사한 변경을 수용할 수 있는 협력 패턴을 발견하는 것과 동일하다.</p>","excerpt":"객체는 협력을 위해 존재한다. 📖 14.1 핸드폰 과금 시스템 변경하기 🔖 14.1.1 기본 정책 확장 기본 정책을 구성하는 4가지 방식 고정요금 방식 시간대별 방식 요일별 방식 구간별 방식 🔖 14.1.2 고정요금 방식 구현하기 🔖 14.1.3 시간대별 방식 구현하기 🔖 14.1.4 요일별 방식 구현하기 🔖 14.1.…","fields":{"slug":"/backend/object/chapter14/일관성_있는_협력/"},"frontmatter":{"title":"Object - 14장 일관성 있는 협력","thumbnail":{"childImageSharp":{"fluid":{"src":"/static/dd0e1990925e942697544e2bdcd9332e/9b73b/object.png"}}},"draft":false,"category":"Back-End","tags":["java"],"date":"November 26, 2023"}}}},"staticQueryHashes":["2374173507","2996537568","3691437124"]}