<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>ilot의 블로그</title>
    <link>https://ilot.tistory.com/</link>
    <description>_</description>
    <language>ko</language>
    <pubDate>Thu, 27 Aug 2026 09:25:18 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>ilot</managingEditor>
    <image>
      <title>ilot의 블로그</title>
      <url>https://tistory1.daumcdn.net/tistory/5461674/attach/2b0f5e2cdeca428783ace4349f7c2541</url>
      <link>https://ilot.tistory.com</link>
    </image>
    <item>
      <title>[Mybatis] Param 어노테이션 없이 여러 파라미터를 넣을 때 null 오류가 발생하는 경우</title>
      <link>https://ilot.tistory.com/20</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Mybatis 에서 한 메서드에 여러 파라미터를 넣을 경우, xml sql에서 파라미터를 구분지을 수 있게 @Param 어노테이션을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1684196600078&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Mapper
public interface FooRepository {

    List&amp;lt;BarVO&amp;gt; selectBars(@Param(&quot;name&quot;) String name, @Param(&quot;code&quot;) String code);

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 로컬 PC에서는 @Param을 생략해도 잘 동작하나, 일부 로컬 PC에서는 아래와 같은 에러가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;org.mybatis.spring.MyBatisSystemException: null&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러가 발생한 PC에서는 intellij의 build tool을 gradle이 아닌 intellij에서 제공하는 gradle을 사용하고 있었기 때문이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Intellij Settings &amp;gt; Build, Execution, Deployment &amp;gt; Build Tools &amp;gt; Gradle 에서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Build and run using, Run tests using을 Gradle로 바꿔주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-16 09.26.14.png&quot; data-origin-width=&quot;982&quot; data-origin-height=&quot;715&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PrrEi/btsf2Gsyi5Y/G7KRp3z5I41sYOCR1iHCpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PrrEi/btsf2Gsyi5Y/G7KRp3z5I41sYOCR1iHCpk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PrrEi/btsf2Gsyi5Y/G7KRp3z5I41sYOCR1iHCpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPrrEi%2Fbtsf2Gsyi5Y%2FG7KRp3z5I41sYOCR1iHCpk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;982&quot; height=&quot;715&quot; data-filename=&quot;스크린샷 2023-05-16 09.26.14.png&quot; data-origin-width=&quot;982&quot; data-origin-height=&quot;715&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 세팅을 Intellij로 바꿔주면, 빌드나 실행속도가 꽤 빨라지나, 가벼운 만큼 일부의 기능만 제공하는 모양이다.&lt;/p&gt;</description>
      <category>Mybatis</category>
      <author>ilot</author>
      <guid isPermaLink="true">https://ilot.tistory.com/20</guid>
      <comments>https://ilot.tistory.com/20#entry20comment</comments>
      <pubDate>Tue, 16 May 2023 09:29:51 +0900</pubDate>
    </item>
    <item>
      <title>[OOP] 우아한 객체지향 _ 의존성을 이용해 설계 진화시키기</title>
      <link>https://ilot.tistory.com/19</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;객체지향 스터디를 준비하던 중, &lt;i&gt;객체지향의 사실과 오해&lt;/i&gt;의 저자이신 조영호 님의 객체지향 세미나를 보게 되었다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;자료&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;영상 :&amp;nbsp;&lt;a href=&quot;https://www.youtube.com/watch?v=dJ5C4qRqAgA&quot;&gt;https://www.youtube.com/watch?v=dJ5C4qRqAgA&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=dJ5C4qRqAgA&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/AdEy8/hyQDErrMXv/tvlWIRYG2kknX8fAa0B1l1/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=114_130_168_190&quot; data-video-width=&quot;600&quot; data-video-height=&quot;338&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/dJ5C4qRqAgA&quot; width=&quot;600&quot; height=&quot;338&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;slideshare : &lt;a href=&quot;https://www.slideshare.net/baejjae93/ss-150432699&quot;&gt;https://www.slideshare.net/baejjae93/ss-150432699&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1668945050978&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;slideshare:presentation&quot; data-og-title=&quot;우아한 객체지향&quot; data-og-description=&quot;2019년 6월 우아한 Tech 세미나 우아한 객체지향&quot; data-og-host=&quot;www.slideshare.net&quot; data-og-source-url=&quot;https://www.slideshare.net/baejjae93/ss-150432699&quot; data-og-url=&quot;https://www.slideshare.net/baejjae93/ss-150432699&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b5h6xh/hyQDBBqs2b/hwEQ36ldzvdRmvPGSWMdB0/img.jpg?width=640&amp;amp;height=452&amp;amp;face=0_0_640_452,https://scrap.kakaocdn.net/dn/PM3CZ/hyQDv2fLvT/k3RtNu6QiBScBxRzgascd1/img.jpg?width=640&amp;amp;height=452&amp;amp;face=0_0_640_452,https://scrap.kakaocdn.net/dn/1spEV/hyQDAvJvTL/Z2sM2723d3pMUKVgswoqK1/img.jpg?width=600&amp;amp;height=450&amp;amp;face=0_0_600_450&quot;&gt;&lt;a href=&quot;https://www.slideshare.net/baejjae93/ss-150432699&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.slideshare.net/baejjae93/ss-150432699&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b5h6xh/hyQDBBqs2b/hwEQ36ldzvdRmvPGSWMdB0/img.jpg?width=640&amp;amp;height=452&amp;amp;face=0_0_640_452,https://scrap.kakaocdn.net/dn/PM3CZ/hyQDv2fLvT/k3RtNu6QiBScBxRzgascd1/img.jpg?width=640&amp;amp;height=452&amp;amp;face=0_0_640_452,https://scrap.kakaocdn.net/dn/1spEV/hyQDAvJvTL/Z2sM2723d3pMUKVgswoqK1/img.jpg?width=600&amp;amp;height=450&amp;amp;face=0_0_600_450');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;우아한 객체지향&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;2019년 6월 우아한 Tech 세미나 우아한 객체지향&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.slideshare.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코드
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1단계 : &lt;a href=&quot;https://github.com/eternity-oop/Woowahan-OO-01-object-reference&quot;&gt;https://github.com/eternity-oop/Woowahan-OO-01-object-reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;2단계 : &lt;a href=&quot;https://github.com/eternity-oop/Woowahan-OO-02-domain-service&quot;&gt;https://github.com/eternity-oop/Woowahan-OO-02-domain-service&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;3단계 : &lt;a href=&quot;https://github.com/eternity-oop/Woowahan-OO-03-domain-event&quot;&gt;https://github.com/eternity-oop/Woowahan-OO-03-domain-event&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;의존성이란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 세계에서 협력은 필수적이며, 객체가 협력한다는 것은 객체 간의 의존성이 존재하는 것이다. 의존성이란, 파라미터나 리턴값 또는 지역 변수 등으로 다른 객체를 참조하는 것을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션 설계 시 어떤 코드를 어떤 패키지에, 어떤 클래스에 넣을 지 많은 고민을 하게 되는데, 의존성의 경우 변경에 초점을 맞추어야 한다. 즉, 협력 관계에 있는 객체 중 하나가 변경이 되면, 다른 객체가 변경되지 않도록 고려해야 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;클래스 의존성&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) 연관 관계&lt;/h4&gt;
&lt;pre id=&quot;code_1668945446708&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class A {
  private B b;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A와 B 객체 사이에서 요청이 빈번하다면, 의도적으로 연관 관계를 맺어줄 수 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(2) 의존 관계&lt;/h4&gt;
&lt;pre id=&quot;code_1668945453890&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class A {
  public B method(B b) {
    return new B();
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(3) 상속 관계&lt;/h4&gt;
&lt;pre id=&quot;code_1668945460547&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class A extends B {

}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(4) 실체화 관계&lt;/h4&gt;
&lt;pre id=&quot;code_1668945472891&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class A implements B {

}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;패키지 의존성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;패키지에 포함된 클래스 사이의 의존성&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;637&quot; data-origin-height=&quot;170&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bepPnk/btrRBKMnyqy/W5ImUPYpt31zDmmkqhIwXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bepPnk/btrRBKMnyqy/W5ImUPYpt31zDmmkqhIwXk/img.png&quot; data-alt=&quot;패키지 의존성&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bepPnk/btrRBKMnyqy/W5ImUPYpt31zDmmkqhIwXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbepPnk%2FbtrRBKMnyqy%2FW5ImUPYpt31zDmmkqhIwXk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;637&quot; height=&quot;170&quot; data-origin-width=&quot;637&quot; data-origin-height=&quot;170&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;패키지 의존성&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;좋은 의존성 관리를 위한 규칙&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) 양방향 의존성을 피하라&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1668945596250&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class A {

  private B b;

  public void setA(B b) {
    this.b = b;
    this.b.setA(this);
  }
}

class B {

  private A a;

  public void setA(A a) {
    this.a = a;
  }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위처럼 A와 B는 서로 연관 관계가 존재하고, B가 바뀔 때 A도 바뀌고, A가 바뀔 때 B도 바뀌게 된다. 가급적이면 단방향으로 구현하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결책&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1668945928882&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class A {
  private B b;

  public void setA(B b) {
    this.b = b;
  }
}

class B {
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(2) 다중성이 적은 방향을 선택하라&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1668945948580&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class A {
  private Collections&amp;lt;B&amp;gt; bs;
}

class B {
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Collection을 다루다 발생 우려되는 문제가 많으므로, 일대다보다 다대일을 권장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결책&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1668945993085&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class A {
}

class B {
  private A a;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(3) 의존성이 필요없다면 제거하라&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(4) 패키지 사이의 의존성 사이클을 제거하라&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;예제 소개&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;본 예제는 배달의민족 앱에서 장바구니에 있는 메뉴를 주문하는 로직을 단순화한 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;도메인 컨셉&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;가게 &amp;amp; 메뉴&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;861&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MVVch/btrRD0gOXJN/KmbkRE9sPTCRFCKrYdhGR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MVVch/btrRD0gOXJN/KmbkRE9sPTCRFCKrYdhGR0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MVVch/btrRD0gOXJN/KmbkRE9sPTCRFCKrYdhGR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMVVch%2FbtrRD0gOXJN%2FKmbkRE9sPTCRFCKrYdhGR0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;861&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;861&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1010&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cm03Zi/btrRBLdqt1E/AyJr7K7k4Kkbbu32BoAXnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cm03Zi/btrRBLdqt1E/AyJr7K7k4Kkbbu32BoAXnk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cm03Zi/btrRBLdqt1E/AyJr7K7k4Kkbbu32BoAXnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcm03Zi%2FbtrRBLdqt1E%2FAyJr7K7k4Kkbbu32BoAXnk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;1010&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1010&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;주문&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;705&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHJ0RD/btrRDVmjNk9/yvZhTHA6SAT6b9v90vMmd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHJ0RD/btrRDVmjNk9/yvZhTHA6SAT6b9v90vMmd1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHJ0RD/btrRDVmjNk9/yvZhTHA6SAT6b9v90vMmd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHJ0RD%2FbtrRDVmjNk9%2FyvZhTHA6SAT6b9v90vMmd1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;705&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;705&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;991&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2tyu6/btrRJPL60bw/ky5qLXIsCnxGWn2BkEFyD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2tyu6/btrRJPL60bw/ky5qLXIsCnxGWn2BkEFyD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2tyu6/btrRJPL60bw/ky5qLXIsCnxGWn2BkEFyD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2tyu6%2FbtrRJPL60bw%2Fky5qLXIsCnxGWn2BkEFyD0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;991&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;991&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;손님이 장바구니에 1인 세트를 저장한 상태다. 단, 장바구니의 값은 손님의 로컬 저장소에만 저장된다고 가정한다. &lt;b&gt;이때 사장님이 1인 세트를 0.5인 세트로 변경한다면? 메뉴가 불일치하는 문제가 발생한다.&lt;/b&gt; 이를 위해 주문을 검증하는 로직을 만든다.&lt;/li&gt;
&lt;li&gt;주문 검증 로직
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메뉴의 이름과 주문 항목의 이름 비교&lt;/li&gt;
&lt;li&gt;옵션 그룹의 이름과 주문 옵션 그룹의 이름 비교&lt;/li&gt;
&lt;li&gt;옵션의 이름과 주문 옵션의 이름 비교&lt;/li&gt;
&lt;li&gt;옵션의 가격과 주문 옵션의 가격 비교&lt;/li&gt;
&lt;li&gt;가게가 영업 중인지 확인&lt;/li&gt;
&lt;li&gt;최소 주문 금액 이상인지 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;주문 검증 로직을 토대로 협력 설계하기&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;503&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l2bFo/btrRH52K86F/v0SWD2FBM0bS1gTeGnzgs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l2bFo/btrRH52K86F/v0SWD2FBM0bS1gTeGnzgs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l2bFo/btrRH52K86F/v0SWD2FBM0bS1gTeGnzgs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl2bFo%2FbtrRH52K86F%2Fv0SWD2FBM0bS1gTeGnzgs0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;503&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;503&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관계에는 방향성이 필요하다. 관계의 방향 == 협력의 방향 == 의존성의 방향&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;설계 개선하기_객체 참조로 인한 문제점&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;772&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l4Inv/btrRCXkmAOJ/DlcOwxgKnSQwIG4d7gU6JK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l4Inv/btrRCXkmAOJ/DlcOwxgKnSQwIG4d7gU6JK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l4Inv/btrRCXkmAOJ/DlcOwxgKnSQwIG4d7gU6JK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl4Inv%2FbtrRCXkmAOJ%2FDlcOwxgKnSQwIG4d7gU6JK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;772&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;772&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Shop과 Order 사이에 의존성 사이클이 발생한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;해결1_중간 객체를 이용한 의존성 사이클 끊기&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cNwqwj/btrRH6HmnQ2/uwL1pb9hqjRIyX2KCPPcU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cNwqwj/btrRH6HmnQ2/uwL1pb9hqjRIyX2KCPPcU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cNwqwj/btrRH6HmnQ2/uwL1pb9hqjRIyX2KCPPcU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcNwqwj%2FbtrRH6HmnQ2%2FuwL1pb9hqjRIyX2KCPPcU1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;700&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;700&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;해결2_객체 참조 끊어내기&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;객체 참조의 단점&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인이 전부 연결되어 있는 상태라면, JPA 같은 경우 연관된 모든 도메인 값을 DB로부터 가져오므로, lazy loading 이슈가 발생할 수 있다. 따라서, 한 도메인을 읽어올 때 어디까지 읽어와야 하는 지 고민을 해야 한다. 즉, 트랜잭션 경계를 적절히 지정해야 한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Primary Key만 가지게 하자&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lagCv/btrRHBUX11R/B1DR4YYfyc05ZPM4ckHbXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lagCv/btrRHBUX11R/B1DR4YYfyc05ZPM4ckHbXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lagCv/btrRHBUX11R/B1DR4YYfyc05ZPM4ckHbXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlagCv%2FbtrRHBUX11R%2FB1DR4YYfyc05ZPM4ckHbXK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;352&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Repository로 탐색해오면 되므로, 약한 결합도를 가지게 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;433&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnPug4/btrRBemDx23/PeeX1Ze4aMiGQa3AU33nvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnPug4/btrRBemDx23/PeeX1Ze4aMiGQa3AU33nvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnPug4/btrRBemDx23/PeeX1Ze4aMiGQa3AU33nvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnPug4%2FbtrRBemDx23%2FPeeX1Ze4aMiGQa3AU33nvK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;433&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;433&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;해결3_때로는 절차지향이 낫다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 Validation 로직을 각 객체에 넣게 되면, 어떤 Validation 로직이 수행되는 지 헷갈릴 수 있다. Validation 로직 같은 경우 한 눈으로 보는게 유리할 수 있기 때문에, 이런 경우 &lt;b&gt;OrderValidator&lt;/b&gt;와 같은 객체를 새로 생성하여, Validation 책임을 위임시킬 수 있다. 이로써 가독성이 좋아질 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;792&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WrCCm/btrRJPehXxw/v2rIkF7BZJJRtyT5km7h21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WrCCm/btrRJPehXxw/v2rIkF7BZJJRtyT5km7h21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WrCCm/btrRJPehXxw/v2rIkF7BZJJRtyT5km7h21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWrCCm%2FbtrRJPehXxw%2Fv2rIkF7BZJJRtyT5km7h21%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;792&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;792&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;설계 개선하기_패키지 사이클로 인한 문제점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;// 공사중&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;출처&lt;br /&gt;&lt;a href=&quot;https://jojoldu.tistory.com/425&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://jojoldu.tistory.com/425&lt;/a&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>OOP</category>
      <author>ilot</author>
      <guid isPermaLink="true">https://ilot.tistory.com/19</guid>
      <comments>https://ilot.tistory.com/19#entry19comment</comments>
      <pubDate>Sun, 20 Nov 2022 21:31:07 +0900</pubDate>
    </item>
    <item>
      <title>[Design Pattern] Factory Method Pattern (팩토리 메서드 패턴)</title>
      <link>https://ilot.tistory.com/18</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;팩토리 메서드 패턴 (Factory Method Pattern)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구체적으로 어떤 인스턴스를 만들지는 서브클래스가 정한다.&lt;/li&gt;
&lt;li&gt;인스턴스를 생성하는 책임을 구체 클래스가 아닌 인터페이스의 메서드로 감싸게 된다.&lt;/li&gt;
&lt;li&gt;다양한 구현체(Product)가 있고, 그 중에서 특정한 구현체를 만들 수 있는 다양한 팩토리(Creator)를 제공할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;322&quot; data-origin-height=&quot;193&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dwPs9E/btrQ2RSpBWi/7b9UTs5kTiJNdy57SSNjsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dwPs9E/btrQ2RSpBWi/7b9UTs5kTiJNdy57SSNjsK/img.png&quot; data-alt=&quot;팩토리 메서드 패턴&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dwPs9E/btrQ2RSpBWi/7b9UTs5kTiJNdy57SSNjsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdwPs9E%2FbtrQ2RSpBWi%2F7b9UTs5kTiJNdy57SSNjsK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;322&quot; height=&quot;193&quot; data-origin-width=&quot;322&quot; data-origin-height=&quot;193&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;팩토리 메서드 패턴&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;장점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기존에 인스턴스 생성 코드를 건드리지 않고 비슷한 류의 인스턴스 생성 코드를 만들 수 있어 OCP를 보장한다. (Creator와 Product의 느슨한 결합)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;단점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스가 많아진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;예시 (as-is)&lt;/h2&gt;
&lt;pre id=&quot;code_1668344205824&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Ship {

  private String name;

  private String color;

  private String logo;

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String getColor() {
    return color;
  }

  public void setColor(String color) {
    this.color = color;
  }

  public String getLogo() {
    return logo;
  }

  public void setLogo(String logo) {
    this.logo = logo;
  }

  @Override
  public String toString() {
    return &quot;Ship{&quot; +
        &quot;name='&quot; + name + '\'' +
        &quot;, color='&quot; + color + '\'' +
        &quot;, logo='&quot; + logo + '\'' +
        '}';
  }
}

public class ShipFactory {

  public static Ship orderShip(String name, String email) {
    // validate
    if (name == null || name.isBlank()) {
      throw new IllegalArgumentException(&quot;배 이름을 지어주세요.&quot;);
    }
    if (email == null || email.isBlank()) {
      throw new IllegalArgumentException(&quot;연락처를 남겨주세요.&quot;);
    }

    prepareFor(name);

    Ship ship = new Ship();
    ship.setName(name);

    // Customizing for specific name
    if (name.equalsIgnoreCase(&quot;whiteship&quot;)) {
      ship.setLogo(&quot;\uD83D\uDEE5️&quot;);
    } else if (name.equalsIgnoreCase(&quot;blackship&quot;)) {
      ship.setLogo(&quot;⚓&quot;);
    }

    // coloring
    if (name.equalsIgnoreCase(&quot;whiteship&quot;)) {
      ship.setColor(&quot;whiteship&quot;);
    } else if (name.equalsIgnoreCase(&quot;blackship&quot;)) {
      ship.setColor(&quot;black&quot;);
    }

    // notify
    sendEmailTo(email, ship);

    return ship;
  }

  private static void prepareFor(String name) {
    System.out.println(name + &quot; 만들 준비 중&quot;);
  }

  private static void sendEmailTo(String email, Ship ship) {
    System.out.println(ship.getName() + &quot; 다 만들었습니다.&quot;);
  }

}

public class Client {

  public static void main(String[] args) {
    Ship whiteship = ShipFactory.orderShip(&quot;Whiteship&quot;, &quot;keesun@mail.com&quot;);
    System.out.println(whiteship);

    Ship blackship = ShipFactory.orderShip(&quot;Blackship&quot;, &quot;keesun@mail.com&quot;);
    System.out.println(blackship);
  }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;orderShip은 name과 color에 따라 로직이 변경된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ship에 신규 특성이 추가되면, (Yellowship, ...) orderShip 로직이 계속 변경되어 OCP에 어긋나게 된다. 변경에 닫혀있지 않게 된다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;예시 (to-be)&lt;/h2&gt;
&lt;pre id=&quot;code_1668345195691&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Ship {

  private String name;

  private String color;

  private String logo;

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String getColor() {
    return color;
  }

  public void setColor(String color) {
    this.color = color;
  }

  public String getLogo() {
    return logo;
  }

  public void setLogo(String logo) {
    this.logo = logo;
  }

  @Override
  public String toString() {
    return &quot;Ship{&quot; +
        &quot;name='&quot; + name + '\'' +
        &quot;, color='&quot; + color + '\'' +
        &quot;, logo='&quot; + logo + '\'' +
        '}';
  }

}

public Whiteship extends Ship {

  public Whiteship() {
    setName(&quot;whiteship&quot;);
    setLogo(&quot;\uD83D\uDEE5️&quot;);
    setColor(&quot;white&quot;);
  }

}

public Blackship extends Ship {

  public Blackship() {
    setName(&quot;blackship&quot;);
    setLogo(&quot;⚓&quot;);
    setColor(&quot;black&quot;);
  }

}

public interface ShipFactory {

  default Ship orderShip(String name, String email) {
    validate(name, email);
    prepareFor(name);
    Ship ship = createShip();
    sentEmailTo(email, ship);
    return ship;
  }

  Ship createShip();

  private void validate(String name, String email) {
    // validate
    if (name == null || name.isBlank()) {
      throw new IllegalArgumentException(&quot;배 이름을 지어주세요.&quot;);
    }
    if (email == null || email.isBlank()) {
      throw new IllegalArgumentException(&quot;연락처를 남겨주세요.&quot;);
    }
  }

  private void prepareFor(String name) {
    System.out.println(name + &quot; 만들 준비 중&quot;);
  }
  
  private void sendEmailTo(String email, Ship ship) {
    System.out.println(ship.getName() + &quot; 다 만들었습니다.&quot;);
  }

}

public class WhiteshipFactory implements ShipFactory {

  @Override
  public Ship createShip() {
    return new Whiteship();
  }

}

public class BlackshipFactory implements ShipFactory {

  @Override
  public Ship createShip() {
    return new Blackship();
  }

}

public class Client {

  public static void main(String[] args) {
    Ship whiteship = new WhiteshipFactory.orderShip(&quot;Whiteship&quot;, &quot;keesun@mail.com&quot;);
    System.out.println(whiteship);

    Ship blackship = new BlackshipFactory.orderShip(&quot;Blackship&quot;, &quot;keesun@mail.com&quot;);
    System.out.println(blackship);
  }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WhiteShip이 있는 와중에, BlackShip을 추가하려고 해도 BlackshipFactory와 Blackship만 생성하면 되기 때문에 WhiteshipFactory와 Whiteship에 코드 변경을 요하지 않는다. OCP를 충족시킨 코드가 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;예시 (to-be) : Client에 DI 적용하기&lt;/h2&gt;
&lt;pre id=&quot;code_1668345653559&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// ...

public class Client {

  public static void main(String[] args) {
    Client client = new Client();
    client.print(new WhiteshipFactory(), &quot;whiteship&quot;, &quot;keesun@mail.com&quot;);
    client.print(new BlackshipFactory(), &quot;blackship&quot;, &quot;keesun@mail.com&quot;);
  }

  // shipFactory를 메서드 파라미터로 의존성 주입 (DI)
  private void print(ShipFactory shipFactory, String name, String email) {
    System.out.println(shipFactory.ordership(name, email));
  }

}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;활용&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단순한 팩토리 패턴
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;매개변수의 값에 따라 또는 메서드에 따라 각기 다른 인스턴스를 리턴하는 단순한 버전의 팩토리 패턴&lt;/li&gt;
&lt;li&gt;java.lang.Calendar 또는 java.lang.NumberFormat&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;스프링의 BeanFactory
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Object 타입의 Product를 만드는 BeanFactory라는 Creator이고, 그것에 대한 구현체가 ClassPathXmlApplicationContext, AnnotationConfigApplicationContext이다.&lt;/li&gt;
&lt;li&gt;Product는 Object이고, getBean시 가져오는 값이 ConcreteProduct가 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;출처&lt;br /&gt;&lt;a href=&quot;https://www.inflearn.com/course/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.inflearn.com/course/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4&lt;/a&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Design Pattern</category>
      <author>ilot</author>
      <guid isPermaLink="true">https://ilot.tistory.com/18</guid>
      <comments>https://ilot.tistory.com/18#entry18comment</comments>
      <pubDate>Sun, 13 Nov 2022 22:34:04 +0900</pubDate>
    </item>
    <item>
      <title>[Design Pattern] Singleton Pattern (싱글톤 패턴)</title>
      <link>https://ilot.tistory.com/17</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;싱글톤 패턴 (Singleton Pattern)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인스턴스를 오직 한개만 제공하는 클래스&lt;/li&gt;
&lt;li&gt;시스템 런타임, 환경 세팅에 대한 정보 등 인스턴스가 여러 개일 때 문제가 생길 수 있는 경우가 있다. 인스턴스를 오직 한 개만 만들어 제공하는 클래스가 필요하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;220&quot; data-origin-height=&quot;132&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cGek0z/btrQZ3zamFE/D0C0no6eF9QVIE06AsHgMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGek0z/btrQZ3zamFE/D0C0no6eF9QVIE06AsHgMK/img.png&quot; data-alt=&quot;싱글톤 패턴&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGek0z/btrQZ3zamFE/D0C0no6eF9QVIE06AsHgMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcGek0z%2FbtrQZ3zamFE%2FD0C0no6eF9QVIE06AsHgMK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;220&quot; height=&quot;132&quot; data-origin-width=&quot;220&quot; data-origin-height=&quot;132&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;싱글톤 패턴&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;예시 (as-is)&lt;/h2&gt;
&lt;pre id=&quot;code_1668251146037&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Settings {

}

public class App {
  
  public static void main(String[] args) {
    Settings settings = new Settings();
    Settings settings1 = new Settings();
    System.out.println(settings != settings1);
  }
  
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;싱글톤 패턴을 적용하려면, 위 &lt;i&gt;settings != settings1&lt;/i&gt;에서 false가 나와야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;예시 (싱글톤 패턴을 가장 단순히 구현하는 방법, thread-safe 하지 않음)&lt;/h2&gt;
&lt;pre id=&quot;code_1668251320928&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Settings {

  private static Settings instance;

  private Settings() {}
  
  public static Settings getInstance() {
    if (instance == null) { // A
      instance = new Settings(); // B
    }
    
    return instance;
  }

}

public class App {
  
  public static void main(String[] args) {
    Settings settings = Settings.getInstance();
    Settings settings1 = Settings.getInstance();
    System.out.println(settings != settings1);
  }
  
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 애플리케이션은 보통 멀티 쓰레드로 구현하게 되는데, 위 싱글톤 객체를 thread-safe하지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 쓰레드가 Settings.getInstance()로 접근했을 때, &lt;span style=&quot;color: #ee2323;&quot;&gt;한 쓰레드&lt;/span&gt;가 &lt;span style=&quot;color: #ee2323;&quot;&gt;A&lt;/span&gt;를 거쳐 &lt;span style=&quot;color: #ee2323;&quot;&gt;B&lt;/span&gt;로 진입한 뒤, &lt;span style=&quot;color: #006dd7;&quot;&gt;다른 쓰레드&lt;/span&gt;가 &lt;span style=&quot;color: #006dd7;&quot;&gt;A&lt;/span&gt;로 들어왔다고 가정해보자. 그러면 &lt;span style=&quot;color: #006dd7;&quot;&gt;다른 쓰레드&lt;/span&gt;가 &lt;span style=&quot;color: #006dd7;&quot;&gt;A&lt;/span&gt;를 판별할 때, &lt;span style=&quot;color: #ee2323;&quot;&gt;한 쓰레드&lt;/span&gt;에서 &lt;span style=&quot;color: #ee2323;&quot;&gt;new Settings()&lt;/span&gt;를 아직 거치지 못해 &lt;span style=&quot;color: #006dd7;&quot;&gt;instance는 null일 수 있다&lt;/span&gt;. 따라서, &lt;span style=&quot;color: #ee2323;&quot;&gt;한 쓰레드&lt;/span&gt;와 &lt;span style=&quot;color: #006dd7;&quot;&gt;다른 쓰레드&lt;/span&gt;의 Settings 객체가 달라질 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;예시 (멀티 쓰레드 환경에서 안전하게 구현하는 방법)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;sychronized&lt;/h3&gt;
&lt;pre id=&quot;code_1668251745848&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Settings {

  private static Settings instance;

  private Settings() {}
  
  public static synchronized Settings getInstance() {
    if (instance == null) {
      instance = new Settings();
    }
    
    return instance;
  }

}

public class App {
  
  public static void main(String[] args) {
    Settings settings = Settings.getInstance();
    Settings settings1 = Settings.getInstance();
    System.out.println(settings != settings1);
  }
  
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;java에서&amp;nbsp;지원하는&amp;nbsp;synchronized&amp;nbsp;키워드는&amp;nbsp;여러 개의&amp;nbsp;스레드가&amp;nbsp;한 개의&amp;nbsp;자원을&amp;nbsp;사용하고자&amp;nbsp;할&amp;nbsp;때,&amp;nbsp;현재&amp;nbsp;데이터를&amp;nbsp;사용하고&amp;nbsp;있는&amp;nbsp;해당&amp;nbsp;스레드를&amp;nbsp;제외하고&amp;nbsp;나머지&amp;nbsp;스레드들은&amp;nbsp;데이터에&amp;nbsp;접근&amp;nbsp;할&amp;nbsp;수&amp;nbsp;없도록&amp;nbsp;막는다. 하지만 getInstace를 한 쓰레드만 사용할 수 있기 때문에, 성능 저하가 발생할 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;이른 초기화 (eager initialization)&lt;/h3&gt;
&lt;pre id=&quot;code_1668251952754&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Settings {

  private static final Settings INSTANCE = new Settings();

  private Settings() {}
  
  public static Settings getInstance() {
    return INSTANCE;
  }

}

public class App {
  
  public static void main(String[] args) {
    Settings settings = Settings.getInstance();
    Settings settings1 = Settings.getInstance();
    System.out.println(settings != settings1);
  }
  
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자를 통해 객체를 생성하는 게 큰 자원이 소모되지 않는다면, instance를 미리 초기화할 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;double checked locking 사용하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이른 초기화 방식으로 하기에는 생성자 호출 자원이 너무 크고, synchronized 방식으로 하기에는 자원 낭비가 걱정된다면, double checked locking 방식을 사용하여 효율적인 synchronized 블록을 만들 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1668252424346&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Settings {

  private static volatile Settings instance;

  private Settings() {}
  
  public static Settings getInstance() {
    if (instance == null) { // A
      synchronized (Settings.class) { // B
        if (instance == null) { // C
          instance = new Settings(); // D
        }
      }
    }
    return instance; // E
  }

}

public class App {
  
  public static void main(String[] args) {
    Settings settings = Settings.getInstance();
    Settings settings1 = Settings.getInstance();
    System.out.println(settings != settings1);
  }
  
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 쓰레드가 Settings.getInstance()로 접근했을 때,&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;한 쓰레드&lt;/span&gt;가&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;A&lt;/span&gt;를 거쳐&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;B, C&lt;span style=&quot;color: #000000;&quot;&gt;로&lt;/span&gt; &lt;/span&gt;진입한 뒤,&amp;nbsp;&lt;span style=&quot;color: #006dd7;&quot;&gt;다른 쓰레드&lt;/span&gt;가&amp;nbsp;&lt;span style=&quot;color: #006dd7;&quot;&gt;A, B&lt;/span&gt;로 들어왔다고 가정해보자. &lt;span style=&quot;color: #ee2323;&quot;&gt;한 쓰레드&lt;/span&gt;가 &lt;span style=&quot;color: #ee2323;&quot;&gt;synchronized 블록&lt;span style=&quot;color: #000000;&quot;&gt;을&lt;/span&gt;&lt;/span&gt; 마칠때까지 &lt;span style=&quot;color: #006dd7;&quot;&gt;다른 쓰레드&lt;/span&gt;는 &lt;span style=&quot;color: #006dd7;&quot;&gt;B&lt;/span&gt;에서 wait 한다. &lt;span style=&quot;color: #ee2323;&quot;&gt;한 쓰레드&lt;/span&gt;가 &lt;span style=&quot;color: #ee2323;&quot;&gt;D&lt;/span&gt;에서 생성자를 호출하고, &lt;span style=&quot;color: #ee2323;&quot;&gt;synchronized 블록을 마치면&lt;/span&gt; &lt;span style=&quot;color: #006dd7;&quot;&gt;다른 쓰레드&lt;/span&gt;가 &lt;span style=&quot;color: #006dd7;&quot;&gt;synchronized 블록에 진입&lt;/span&gt;이 가능해지고, &lt;span style=&quot;color: #006dd7;&quot;&gt;다른 쓰레드&lt;/span&gt;는 &lt;span style=&quot;color: #006dd7;&quot;&gt;C에서 false&lt;/span&gt;가 나오기 때문에, D를 거치지 않고 &lt;span style=&quot;color: #006dd7;&quot;&gt;return문 E&lt;/span&gt;를 타고 메서드를 마친다. &lt;span style=&quot;color: #f89009;&quot;&gt;제3자 쓰레드&lt;/span&gt;는 이미 instance가 만들어져 있으므로, &lt;span style=&quot;color: #f89009;&quot;&gt;A -&amp;gt; E를 타고 instance를 반환&lt;/span&gt;할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;getInstance 호출 때마다 동기화 처리를 하지 않기 때문에, synchronized 방식에 비해 효율적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 volatile을 사용하지 않으면, 인스턴스가 두개 이상 발생할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;키워드 volatile이란, java 변수를 Main Memory에 저장하겠다는 것을 명시한다. volatile이 명시된 변수의 값을 읽을 때마다, CPU cache에 저장된 값이 아닌 Main Memory에서 읽는다. volatile이 명시된 변수의 값을 변경할 때마다, Main Memory에서도 수정이 일어난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멀티 쓰레드 애플리케이션에서의 non-volatile 변수에 대한 작업은 성능상의 이유로 CPU cahce를 사용한다. 따라서, 위 &lt;i&gt;Settings instance&lt;/i&gt;를 volatile 처리하지 않으면, 멀티 쓰레드 환경 아래 각각 쓰레드는 instance를 CPU Cache에서 읽어오게 되는데, 한 쓰레드에서 instance를 변경해도, 다른 쓰레드에서 변경한 값이 보이지 않을 수가 있다. 즉, instance가 Main Memory로부터 실시간으로 동기화 되었다는 사실을 보장할 수 없다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;static inner 클래스 사용하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 double checked locking 방식은 유용하나, volatile 키워드 때문에 java 1.5 이상에서만 동작한다. 따라서 1.5 이하 버전에서도 활용될 수 있는 static inner 클래스를 사용하도록 하자.&lt;/p&gt;
&lt;pre id=&quot;code_1668253147084&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Settings {

  private Settings() {}
  
  private static class SettingsHolder {
    private static final Settings INSTANCE = new Settings();
  }
  
  public static Settings getInstance() {
    return SettingsHolder.INSTANCE;
  }

}

public class App {
  
  public static void main(String[] args) {
    Settings settings = Settings.getInstance();
    Settings settings1 = Settings.getInstance();
    System.out.println(settings != settings1);
  }
  
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스는 Singleton 클래스가 Load 될 때에도 Load 되지 않다가 getInstance()가 호출됐을 때 비로소 JVM 메모리에 로드되고, 인스턴스를 생성하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;INSTANCE가 static이기 때문에 초기화가 이루어진다. LazyHolder 클래스가 초기화 되면서 INSTANCE 객체도 Settings의 생성자의 의해 생성도 이루어지며, 이 과정에서 static이기 때문에 하나의 인스턴스만 생성되는 것을 보장해준다. 그리고 final로 선언했기 때문에 다시 instance가 할당되는 것 또한 막을 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;static inner 클래스 사용 시 싱글톤 구현 방법을 깨뜨리는 방법&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;리플렉션 사용&lt;/h4&gt;
&lt;pre id=&quot;code_1668255104516&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Settings {

  private Settings() {}
  
  private static class SettingsHolder {
    private static final Settings INSTANCE = new Settings();
  }
  
  public static Settings getInstance() {
    return SettingsHolder.INSTANCE;
  }

}

public class App {
  
  public static void main(String[] args) {
    Settings settings = Settings.getInstance();
    
    Constructor&amp;lt;Settings&amp;gt; declaredConstructor = Settings.class.getDeclaredConstructor();
    declaredConstructor.setAccessible(true);
    Settings settings1 = declaredConstructor.newInstance();
    
    System.out.println(settings != settings1); // true
  }
  
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;직렬화와 역직렬화 사용하기&lt;/h4&gt;
&lt;pre id=&quot;code_1668255373271&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Settings implements Serializable {

  private Settings() {}
  
  private static class SettingsHolder {
    private static final Settings INSTANCE = new Settings();
  }
  
  public static Settings getInstance() {
    return SettingsHolder.INSTANCE;
  }

}

public class App {
  
  public static void main(String[] args) throws IOException {
    Settings settings = Settings.getInstance();
    Settings settings1 = null;
    
    try (ObjectOutput out = new ObjectOutputStream(new FileOutputStream(&quot;settings.obj&quot;))) {
      out.writeObject(settings); // 직렬화되어 파일로 써졌다.
    }
    
    try (ObjectInput in = new ObjectInputStream(new FileInputStream(&quot;settings.obj&quot;))) {
      settings1 = (Settings) in.readObject(); // 파일을 역직렬화 하였다.
    }
    
    System.out.println(settings != settings1); // true
  }

}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;예시 (안전하고 단순하게 구현하는 방법)&lt;/h2&gt;
&lt;pre id=&quot;code_1668255897177&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public enum Settings {

  INSTANCE;

}

public class App {
  
  public static void main(String[] args) throws IOException {
    Settings settings = Settings.INSTANCE;
    Settings settings1 = Settings.INSTANCE;
    
    System.out.println(settings != settings1); // false
  }

}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;enum은 Serializable을 구현하고 있기 때문에, 직렬화 &amp;amp; 역직렬화를 해도 기존 객체를 가져온다.&lt;/li&gt;
&lt;li&gt;리플렉션은 enum의 constructor 사용을 금하고 있다.&lt;/li&gt;
&lt;li&gt;단, JVM이 구동될 때 미리 생성된다. 그리고 상속을 쓰지 못하는 단점이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;활용&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스프링에서 빈의 스코프 중에 하나인 싱글톤 스코프&lt;/li&gt;
&lt;li&gt;다른 디자인 패턴 구현체의 일부로 쓰이기도 한다. (빌더, 퍼사드, 추상 팩토리 등)&lt;/li&gt;
&lt;li&gt;자바의 java.lang.Runtime&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1668256266403&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Runtime runtime = Runtime.getRuntime();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;출처&lt;br /&gt;&lt;a href=&quot;https://www.inflearn.com/course/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.inflearn.com/course/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://junghyungil.tistory.com/150&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://junghyungil.tistory.com/150&lt;/a&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Design Pattern</category>
      <author>ilot</author>
      <guid isPermaLink="true">https://ilot.tistory.com/17</guid>
      <comments>https://ilot.tistory.com/17#entry17comment</comments>
      <pubDate>Sat, 12 Nov 2022 21:34:40 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] 서비스는 트랜잭션, 도메인의 순서 보장 역할만 제공한다</title>
      <link>https://ilot.tistory.com/15</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;서론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링에서는 @Controller, @Service, @Repository 등의 애노테이션을 사용하여 웹 계층을 분리하고 있다. 이 중 @Service는 사실상 @Component와 기능 차이가 없지만, 스프링에게 해당 클래스가 서비스 레이어 클래스라는 것을 알리는 역할을 한다고 한다. 그렇다면 Service Layer는 무슨 역할을 하는 걸까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3 tier 아키텍처&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;737&quot; data-origin-height=&quot;151&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RrSQN/btrQKDNJLrj/UnBA3CgqfNSZCT2iQIUxHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RrSQN/btrQKDNJLrj/UnBA3CgqfNSZCT2iQIUxHk/img.png&quot; data-alt=&quot;3 tier 아키텍처&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RrSQN/btrQKDNJLrj/UnBA3CgqfNSZCT2iQIUxHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRrSQN%2FbtrQKDNJLrj%2FUnBA3CgqfNSZCT2iQIUxHk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;737&quot; height=&quot;151&quot; data-origin-width=&quot;737&quot; data-origin-height=&quot;151&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;3 tier 아키텍처&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 스프링 프로젝트는 3 tier 방식으로 구성한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;프레젠테이션 계층&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;화면에 보여주는 기술을 사용하는 영역.&lt;/li&gt;
&lt;li&gt;컨트롤러에서 사용자의 요청에 맞는 응답처리를 진행하며, HTML엔진(thymeleaf), HTML등이 담당하는 영역.&lt;/li&gt;
&lt;li&gt;Spring MVC 객체로, 컨트롤러, DispatcherServlet, 컨트롤러, 뷰, 모델이 포함된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;서비스 계층&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;순수한 비지니스 로직을 담고 있는 영역.&lt;/li&gt;
&lt;li&gt;이 영역의 설계는 고객의 요구사항과 정확히 일치해야 한다.&lt;/li&gt;
&lt;li&gt;프레젠테이션 계층과 데이터 엑세스 계층의 중간다리 역할을 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;데이터 엑세스 계층&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터를 어떤 방식으로 보관하고, 사용하는 가에 대한 설계가 들어가는 계층.&lt;/li&gt;
&lt;li&gt;일반적으로 DBMS를 많이 사용하지만, 상황에 따라서 API 호출, NoSQL, Kafka 등의 기술이 포함될 수 있다.&lt;/li&gt;
&lt;li&gt;데이터의 CRUD 연산을 수행하는 Mapper와 결과를 객체로 리턴하는 DAO을 포함한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;오브젝트 중심 아키텍처&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3 tier 아키텍처에 확장하여, Layer 간 데이터 전송 객체인 &lt;b&gt;DTO&lt;/b&gt;와 특정 특정 도메인을 개념적으로 표현한 것인 &lt;b&gt;Domain Model&lt;/b&gt;이 포함된 오브젝트 중심 아키텍처가 존재한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;390&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEE40V/btrQKaSwPEx/rOruOIRxE2vbW5gXW0P9X1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEE40V/btrQKaSwPEx/rOruOIRxE2vbW5gXW0P9X1/img.png&quot; data-alt=&quot;오브젝트 중심 아키텍처&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEE40V/btrQKaSwPEx/rOruOIRxE2vbW5gXW0P9X1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEE40V%2FbtrQKaSwPEx%2FrOruOIRxE2vbW5gXW0P9X1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;728&quot; height=&quot;390&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;390&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;오브젝트 중심 아키텍처&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Web Layer&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;흔히 사용하는 Controller와 JSP 등의 뷰 템플릿 영역이다.&lt;/li&gt;
&lt;li&gt;이외에도 filter, interceptor, ControllerAdvice 등 외부 요청과 응답에 대한 전반적인 영역이다.&lt;/li&gt;
&lt;li&gt;3 tier 아키텍처의 프레젠테이션 계층과 유사하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Service Layer&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@Service에 사용되는 서비스 영역이다.&lt;/li&gt;
&lt;li&gt;일반적으로 Controller와 DAO의 중간 영역으로 사용된다.&lt;/li&gt;
&lt;li&gt;@Transactional이 사용되어야 하는 영역이다.&lt;/li&gt;
&lt;li&gt;3 tier 아키텍처의 서비스 계층과 유사하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Repository Layer&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DB와 같이 데이터 저장소에 접근하는 영역이다.&lt;/li&gt;
&lt;li&gt;DAO(Data Access Object)영역이다.&lt;/li&gt;
&lt;li&gt;3 tier 아키텍처의 데이터 엑세스 계층과 유사하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;DTOs&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DTO(Data Transfer Object)는 계층 간에 데이터 교환을 위한 객체다.&lt;/li&gt;
&lt;li&gt;Web Layer에서 사용될 객체나 Repositroy Layer에서 결과로 넘겨주는 객체 등이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Domain Model&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;도메인이라 불리는 개발 대상을 모든 사람이 동일한 관점에서 이해할 수 있고 공유할 수 있도록 단순화시킨 것을 도메인 모델이라고 한다. (ex. 택시앱에서 배차, 탑승, 요금 등은 모두 도메인)&lt;/li&gt;
&lt;li&gt;JPA의 경우 @Entity를 사용된 영역이 도메인 모델이다.&lt;/li&gt;
&lt;li&gt;다만, 무조건 DB의 테이블과 관계가 있어야만 도메인은 아니다.&lt;/li&gt;
&lt;li&gt;VO(Value Object)처럼 값 객체들도 이영역 해당된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;서비스 차원에서 - 3 tier 아키텍처 vs 오브젝트 중심 아키텍처&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주문 취소에 대한 메서드가 있을 때, 각 아키텍처 방식으로 서비스 단에서 cancelOrder를 구현해보았다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예시 - 3 tier 아키텍처&lt;/h3&gt;
&lt;pre id=&quot;code_1667969250323&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Transactional
public Order cancelOrder(int orderId) {
  // 1) 주문정보, 결제정보, 배송정보 조회
  OrdersDto order = ordersDao.selectOrders(orderId);
  BillingDto billing = billingDao.selectBilling(orderId);
  DeliveryDto delivery = deliveryDao.selectDelivery(orderId);
  
  // 2) 배송 취소 여부 확인
  String deliveryStatus = delivery.getStatus();
  
  // 3) 배송중이라면 배송 취소
  if (&quot;IN_PROGRESS&quot;.equals(deliveryStatus)) {
    delivery.setStatus(&quot;CANCEL&quot;);
    deliveryDao.update(delivery);
  }
  
  // 4) 각 테이블에 취소상태 갱신
  order.setStatus(&quot;CANCEL&quot;);
  ordersDao.update(order);
  
  billing.setStatus(&quot;CANCEL&quot;);
  billingDao.update(billing);
  
  return order;

}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Service에서 모든 비지니스 로직을 처리하기 때문에&amp;nbsp;구현이 매우 쉽고 단순하지만 구조가 복잡해질 수록 모듈화의 복잡도도 높아지게 된다.&lt;/li&gt;
&lt;li&gt;order, billing, delivery는 단순히 정보만 담겨있고, 모든 로직은 Service 단에 존재한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;빈약한 도메인 오브젝트&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;단순히 정보만 담겨있는 오브젝트를 빈약한 (Anemic) 오브젝트라 함&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;도메인 오브젝트 기능이라 하면 도메인 오브젝트의 비즈니스 로직이라 볼 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;빈약한 도메인 오브젝트의 경우 비즈니스 로직이 전부 서비스 계층에 있기 때문에 거대 서비스 계층구조와 비슷함&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;도메인&amp;nbsp;오브젝트는&amp;nbsp;독립적으로&amp;nbsp;존재하면서&amp;nbsp;일관된&amp;nbsp;구조의&amp;nbsp;정보를&amp;nbsp;담아서&amp;nbsp;전달하는데만&amp;nbsp;사용됨&lt;/li&gt;
&lt;li&gt;SQL에&amp;nbsp;의존적인&amp;nbsp;데이터&amp;nbsp;방식보다&amp;nbsp;유연하고&amp;nbsp;간결하지만,&amp;nbsp;&lt;b&gt;서비스&amp;nbsp;계층의&amp;nbsp;메소드에&amp;nbsp;대부분의&amp;nbsp;비즈니스&amp;nbsp;로직이&amp;nbsp;있기&amp;nbsp;때문에&amp;nbsp;재사용성이&amp;nbsp;떨어지고&amp;nbsp;중복의&amp;nbsp;문제가&amp;nbsp;발생하기&amp;nbsp;쉬움&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예시 - 오브젝트 중심 아키텍처&lt;/h3&gt;
&lt;pre id=&quot;code_1667969349653&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Transactional
public Order cancelOrder(int orderId) {
  // 1) 주문정보, 결제정보, 배송정보 조회
  OrdersDto order = ordersDao.selectOrders(orderId);
  BillingDto billing = billingDao.selectBilling(orderId);
  DeliveryDto delivery = deliveryDao.selectDelivery(orderId);

  // 2)배송 취소 여부 확인 - 3)배송중이라면 배송취소
  delivery.cancel();

  // 4)각 테이블에 취소상태 갱신
  order.cancel();
  biling.cancel();

  return order;
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체에 객체가 수행해야 하는 업무를 분담시키는 것으로써&amp;nbsp;Service에서는 트랜잭션, 도메인 간의 순서보장의 역할만을 제공하고 비지니스 로직을 Domain에서 처리하는 방식이다.&lt;/li&gt;
&lt;li&gt;order, billing, delivery 각각에 cancel 기능이 담겨있어, 다른 Service에서도 재사용하기 쉬워지고, 코드 가독성이 높아졌다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;풍성한 도메인 오브젝트&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정보&amp;nbsp;저장 뿐만이 아니라, 내부의 정보를 이용하는&amp;nbsp;기능도 가지고 있는 오브젝트를 풍성한 오브젝트라 한다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;데이터와 데이터를 사용하는 로직을 모아두기 때문에&amp;nbsp;응집도가 높음&lt;/li&gt;
&lt;li&gt;어떤 비즈니스 로직은 특정 도메인 오브젝트와 깊은 관계가 있을 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;해당 로직을 도메인 오브젝트에 넣고, 서비스 계층의 비스니스 로직에서 재사용하도록 함&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;결론&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Service는 비즈니스 로직을 담는 것이 아닌, 트랜잭션 처리와 도메인 모델간의 순서 보장의 역할을 부여하는 것을 지향해야 한다. 비즈니스 로직은 도메인 모델에 넣자.&lt;/li&gt;
&lt;li&gt;이로써 얻는 이점은, 재사용성을 높이고 코드 가독성이 좋아진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;출처&lt;br /&gt;&lt;/b&gt;&lt;a href=&quot;https://ksb-dev.tistory.com/m/210&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ksb-dev.tistory.com/m/210&lt;/a&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;a href=&quot;https://incheol-jung.gitbook.io/docs/study/ddd-start/1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://incheol-jung.gitbook.io/docs/study/ddd-start/1&lt;/a&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;a href=&quot;https://hongs-coding.tistory.com/119&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://hongs-coding.tistory.com/119&lt;/a&gt;&lt;br /&gt;토비의 스프링 3.1 Vol. 1 스프링의 이해와 원리 : &lt;a href=&quot;http://www.yes24.com/Product/Goods/7516721&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://www.yes24.com/Product/Goods/7516721&lt;/a&gt;&lt;br /&gt;스프링 부트와 AWS로 혼자 구현하는 웹 서비스 : &lt;a href=&quot;http://www.yes24.com/Product/Goods/83849117&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://www.yes24.com/Product/Goods/83849117&lt;/a&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring</category>
      <author>ilot</author>
      <guid isPermaLink="true">https://ilot.tistory.com/15</guid>
      <comments>https://ilot.tistory.com/15#entry15comment</comments>
      <pubDate>Wed, 9 Nov 2022 14:00:30 +0900</pubDate>
    </item>
    <item>
      <title>객체지향의 사실과 오해</title>
      <link>https://ilot.tistory.com/9</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2732&quot; data-origin-height=&quot;1121&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWYgXx/btrPgDCm04S/lqdBqSXM2KYCZbgcrQu7i1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWYgXx/btrPgDCm04S/lqdBqSXM2KYCZbgcrQu7i1/img.jpg&quot; data-alt=&quot;1장 요약&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWYgXx/btrPgDCm04S/lqdBqSXM2KYCZbgcrQu7i1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWYgXx%2FbtrPgDCm04S%2FlqdBqSXM2KYCZbgcrQu7i1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2732&quot; height=&quot;1121&quot; data-origin-width=&quot;2732&quot; data-origin-height=&quot;1121&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1장 요약&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2732&quot; data-origin-height=&quot;1691&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ytY8k/btrPjlOr4vS/EWkuJKqAhM3rc7sN9U62Ak/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ytY8k/btrPjlOr4vS/EWkuJKqAhM3rc7sN9U62Ak/img.jpg&quot; data-alt=&quot;2장 요약&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ytY8k/btrPjlOr4vS/EWkuJKqAhM3rc7sN9U62Ak/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FytY8k%2FbtrPjlOr4vS%2FEWkuJKqAhM3rc7sN9U62Ak%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2732&quot; height=&quot;1691&quot; data-origin-width=&quot;2732&quot; data-origin-height=&quot;1691&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2장 요약&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20221104_162626512.jpg&quot; data-origin-width=&quot;2381&quot; data-origin-height=&quot;1761&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dMdUh0/btrQn8BnaVP/4JSvYWOjKuKlWhon86nsS1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dMdUh0/btrQn8BnaVP/4JSvYWOjKuKlWhon86nsS1/img.jpg&quot; data-alt=&quot;3장 요약&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dMdUh0/btrQn8BnaVP/4JSvYWOjKuKlWhon86nsS1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdMdUh0%2FbtrQn8BnaVP%2F4JSvYWOjKuKlWhon86nsS1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2381&quot; height=&quot;1761&quot; data-filename=&quot;KakaoTalk_20221104_162626512.jpg&quot; data-origin-width=&quot;2381&quot; data-origin-height=&quot;1761&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;3장 요약&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1916&quot; data-origin-height=&quot;1020&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EhIUY/btrQBKmcZye/c0k1nKpS6tF1dvhdtsMtfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EhIUY/btrQBKmcZye/c0k1nKpS6tF1dvhdtsMtfK/img.png&quot; data-alt=&quot;4장 요약&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EhIUY/btrQBKmcZye/c0k1nKpS6tF1dvhdtsMtfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEhIUY%2FbtrQBKmcZye%2Fc0k1nKpS6tF1dvhdtsMtfK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1916&quot; height=&quot;1020&quot; data-origin-width=&quot;1916&quot; data-origin-height=&quot;1020&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;4장 요약&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2124&quot; data-origin-height=&quot;1613&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dp8H55/btrQyW1DlHV/eXyJ3mfUbJWXlPjgQL6KyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dp8H55/btrQyW1DlHV/eXyJ3mfUbJWXlPjgQL6KyK/img.png&quot; data-alt=&quot;5장 요약&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dp8H55/btrQyW1DlHV/eXyJ3mfUbJWXlPjgQL6KyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdp8H55%2FbtrQyW1DlHV%2FeXyJ3mfUbJWXlPjgQL6KyK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2124&quot; height=&quot;1613&quot; data-origin-width=&quot;2124&quot; data-origin-height=&quot;1613&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;5장 요약&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1827&quot; data-origin-height=&quot;1023&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cpKpzl/btrQz55eePQ/4hYKWfhF5f4pYgZnNCULh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cpKpzl/btrQz55eePQ/4hYKWfhF5f4pYgZnNCULh1/img.png&quot; data-alt=&quot;6장 요약&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cpKpzl/btrQz55eePQ/4hYKWfhF5f4pYgZnNCULh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcpKpzl%2FbtrQz55eePQ%2F4hYKWfhF5f4pYgZnNCULh1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1827&quot; height=&quot;1023&quot; data-origin-width=&quot;1827&quot; data-origin-height=&quot;1023&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;6장 요약&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1209&quot; data-origin-height=&quot;531&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bERTPA/btrQyvQCCsO/KInBl8thRYbn42lyBDckk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bERTPA/btrQyvQCCsO/KInBl8thRYbn42lyBDckk1/img.png&quot; data-alt=&quot;7장 요약&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bERTPA/btrQyvQCCsO/KInBl8thRYbn42lyBDckk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbERTPA%2FbtrQyvQCCsO%2FKInBl8thRYbn42lyBDckk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1209&quot; height=&quot;531&quot; data-origin-width=&quot;1209&quot; data-origin-height=&quot;531&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;7장 요약&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;생각&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;대학교에서 객체지향 수업을 들을 때, 보통 절차지향과 비교한다. 절차지향은 코드를 작성한 순서대로 프로그램이 진행되고, 객체지향은 객체와 객체 간의 상호작용을 통해 프로그램이 진행된다고. 그러면서 곧바로, 현실 물체를 프로그램 코드인 객체로 변신시키는 게 객체지향의 핵심이고, 원리는 캡슐화, 상속, 추상화, 다형성이 있고, 그 뒤 곧바로 c++의 문법에 대해 배웠던 것 같다. 결국 대학교를 졸업하고 한참 뒤에야, 이 책을 읽으면서 객체지향이란 무엇인가를 곰곰이 되뇌이게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;본 책을 통해서 &lt;span&gt;간단히&lt;span&gt; 객체지향이 왜 나오게 되었는가, 객체지향을 왜 쓰는가, 객체지향 방식으로 애플리케이션을 설계하려면 어떻게 해야하는 가 등을 알게 되었다. 마치 수학 공식처럼, 단순히 객체지향의 원리를 달달 외운다고 해서, 객체지향의 본질을 깨우칠 순 없는 것 아닌가. 본디 프로그램 설계에는 유스케이스가 있었고, 이에 따라 도메인 모델을 설계하고, 이를 토대로 협력의 내용을 결정하고, 협력을 통해 발생되는 신규 메시지, 인터페이스, 객체까지. 이들의 통합적인 관리와 유연한 유지보수를 위해 객체지향이 필요했고, 그에 따라 캡슐화, 상속, 추상화, 다형성이든, SOLID든, 디자인 패턴이든 나오게 되었던 것 같다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이에 확장하여 디자인 패턴에 대해 배워보고 싶다. 디자인 패턴이 객체지향에 종속되는 것은 아니지만, 애플리케이션을 설계할 때 단순히 객체간의 상호작용이 아닌, 결국 애플리케이션의 통합적인 관리와 유연한 유지보수를 위함이다. 타 개발자가 나의 코드를 바라보았을 때, 한번에 알아먹을 수 있는 개발자가 되고 싶다는 생각이 들었다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;독서 기간 : 2022-10-01 ~ 2022-11-07&lt;br /&gt;참조 :&amp;nbsp;&lt;a href=&quot;http://www.yes24.com/Product/Goods/18249021&quot;&gt;http://www.yes24.com/Product/Goods/18249021&lt;/a&gt;&lt;/blockquote&gt;</description>
      <category>독후감</category>
      <author>ilot</author>
      <guid isPermaLink="true">https://ilot.tistory.com/9</guid>
      <comments>https://ilot.tistory.com/9#entry9comment</comments>
      <pubDate>Mon, 7 Nov 2022 17:38:52 +0900</pubDate>
    </item>
    <item>
      <title>[Design Pattern] Composite Pattern (컴포지트 패턴)</title>
      <link>https://ilot.tistory.com/14</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;출처 :&amp;nbsp;&lt;a href=&quot;https://www.inflearn.com/course/디자인-패턴&quot;&gt;https://www.inflearn.com/course/디자인-패턴&lt;/a&gt;&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;컴포지트 패턴 (Composite Pattern)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그룹 전체와 개별 객체를 동일하게 처리할 수 있는 패턴.&lt;/li&gt;
&lt;li&gt;클라이언트 입장에서는 &lt;b&gt;전체&lt;/b&gt;나 &lt;b&gt;부분&lt;/b&gt;이나 모두 동일한 컴포넌트로 인식할 수 있는 계층 구조를 만든다. (Part-Whole Hierarchy)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;474&quot; data-origin-height=&quot;299&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgz5OV/btrQuHQvRQk/GHK0sNkKV0i1oiBsIeqhnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgz5OV/btrQuHQvRQk/GHK0sNkKV0i1oiBsIeqhnk/img.png&quot; data-alt=&quot;컴포지트 패턴&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgz5OV/btrQuHQvRQk/GHK0sNkKV0i1oiBsIeqhnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcgz5OV%2FbtrQuHQvRQk%2FGHK0sNkKV0i1oiBsIeqhnk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;474&quot; height=&quot;299&quot; data-origin-width=&quot;474&quot; data-origin-height=&quot;299&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;컴포지트 패턴&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;장점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;복잡한 트리 구조를 편리하게 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;다형성과 재귀를 활용할 수 있다.&lt;/li&gt;
&lt;li&gt;클라이언트 코드를 변경하지 않고 새로운 엘리먼트 타입을 추가할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;단점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트리를 만들어야 하기 때문에 (공통된 인터페이스를 정의해야 하기 때문에) 지나치게 일반화 해야 하는 경우도 생길 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;예시 (as-is)&lt;/h2&gt;
&lt;pre id=&quot;code_1667785291512&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Item {

  private String name;
  private int price;
  
  public Item(String name, int price) {
    this.name = name;
    this.price = price;
  }
  
  public int getPrice() {
    return this.price;
  }

}

public class Bag {
  
  private List&amp;lt;Item&amp;gt; items = new ArrayList&amp;lt;&amp;gt;();
  
  public void add(Item item) {
    items.add(item);
  }
  
  public List&amp;lt;Item&amp;gt; getItems() {
    return items;
  }

}

public class Client {

  public static void main(String[] args) {
    Item doranBlade = new Item(&quot;도란 검&quot;, 450);
    Item healPotion = new Item(&quot;체력 물약&quot;, 50);
    
    Bag bag = new Bag();
    bag.add(doranBlade);
    bag.add(healPotion);
    
    Client client = new Client();
    client.printPrice(doranBlade);
    client.printPrice(bag);
    
  }
  
  // 아래 printPrice가 client에 구현하는 게 맞나?
  // 리프들에 공통적으로 구현되는 메서드를 interface로 분리하자
  private void printPrice(Item item) {
    System.out.println(item.getPrice());
  }
 
  private void printPrice(Bag bag) {
    int sum = bag.getItems().stream().mapToInt(Item::getPrice).sum();
    System.out.println(sum);
  }

}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;예시 (to-be)&lt;/h2&gt;
&lt;pre id=&quot;code_1667785589661&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Component
public interface Component {

  int getPrice();

}

// Leaf
public class Item implements Component {

  private String name;
  private int price;
  
  public Item(String name, int price) {
    this.name = name;
    this.price = price;
  }

  @Override
  public int getPrice() {
    return this.price;
  }

}

// Composite
public class Bag implements Component {
  
  private List&amp;lt;Component&amp;gt; components = new ArrayList&amp;lt;&amp;gt;();
  
  public void add(Component component) {
    components.add(component);
  }
  
  public List&amp;lt;Component&amp;gt; getComponents() {
    return components;
  }
  
  @Override
  public int getPrice() {
    return components.stream().mapToInt(Component::getPrice).sum();
  }

}

public class Client {

  public static void main(String[] args) {
    Item doranBlade = new Item(&quot;도란 검&quot;, 450);
    Item healPotion = new Item(&quot;체력 물약&quot;, 50);
    
    Bag bag = new Bag();
    bag.add(doranBlade);
    bag.add(healPotion);
    
    Client client = new Client();
    client.printPrice(doranBlade);
    client.printPrice(bag);
    
  }

  private void printPrice(Component component) {
    System.out.println(component.getPrice());
  }

}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;활용&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자바의 라이브러리 Swing에서의 &lt;b&gt;setVisible&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Design Pattern</category>
      <author>ilot</author>
      <guid isPermaLink="true">https://ilot.tistory.com/14</guid>
      <comments>https://ilot.tistory.com/14#entry14comment</comments>
      <pubDate>Mon, 7 Nov 2022 11:03:44 +0900</pubDate>
    </item>
    <item>
      <title>[Design Pattern] 전략 패턴 (Strategy Pattern)</title>
      <link>https://ilot.tistory.com/13</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;출처 : &lt;a href=&quot;https://www.inflearn.com/course/디자인-패턴&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.inflearn.com/course/디자인-패턴&lt;/a&gt;&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;전략 패턴 (Strategy Pattern)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 알고리즘을 캡슐화하고 상호 교환 가능하게 만드는 패턴.&lt;/li&gt;
&lt;li&gt;클라이언트가 직접 컨텍스트에서 사용할 알고리즘을 선택한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;u&gt;생성자에서&lt;/u&gt;, 혹은&lt;/li&gt;
&lt;li&gt;&lt;u&gt;특정 Operator에서&lt;/u&gt; 알고리즘을 선택해서 넘겨줄 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;장점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;새로운 전략을 추가하더라도 기존 코드를 변경하지 않는다. OCP를 완벽하게 지키고 있다.&lt;/li&gt;
&lt;li&gt;상속은 한 객체만 가능한데, 이 대신 위임을 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;런타임에 전략을 변경할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;단점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;복잡도가 증가한다.&lt;/li&gt;
&lt;li&gt;클라이언트 코드가 구체적인 전략을 알아야 하기 때문에, 의존성이 생긴다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;예시 (as-is)&lt;/h2&gt;
&lt;pre id=&quot;code_1667121146856&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class BlueLightRedLight {

  private int speed;
  
  public BlueLightRedLight(int speed) {
    this.speed = speed;
  }

  public void blueLight() {
    if (speed == 1) {
      System.out.println(&quot;무 궁 화    꽃  이&quot;);
    } else if (speed == 2) {
      System.out.println(&quot;무 궁 화 꽃 이&quot;);
    } else {
      System.out.println(&quot;무궁화꽃이&quot;);
    }
  }
  
  public void redLight() {
    if (speed == 1) {
      System.out.println(&quot;피 었 습 니   다.&quot;);
    } else if (speed == 2) {
      System.out.println(&quot;피 었 습 니 다.&quot;);
    } else {
      System.out.println(&quot;피었습니다.&quot;);
    }
  }

}

public class Client {

  public static void main(String[] args) {
    BlueLightRedLight blueLightRedLight = new BlueLightRedLight(2);
    blueLightRedLight.blueLight();
    blueLightRedLight.redLight();
  }
  
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;예시 (to-be : 생성자에서)&lt;/h2&gt;
&lt;pre id=&quot;code_1667121767643&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class BlueLightRedLight {

  private Speed speed;
  
  
  public BlueLightRedLight(Speed speed) {
    this.speed = speed;
  }

  public void blueLight() {
    speed.blueLight();
  }
  
  public void redLight() {
    speed.redLight();
  }

} 

public interface Speed {

  void blueLight();
  
  void redLight();

}

public class Normal implements Speed {

  @Override
  public void blueLight() {
    System.out.println(&quot;무 궁 화    꽃  이&quot;);
  }
  
  @Override
  public void redLight() {
    System.out.println(&quot;피 었 습 니   다.&quot;);
  }

}


public class Fast implements Speed {

  @Override
  public void blueLight() {
    System.out.println(&quot;무궁화꽃이&quot;);
  }
  
  @Override
  public void redLight() {
    System.out.println(&quot;피었습니다.&quot;);
  }

}

public class Client {

  public static void main(String[] args) {
    // BlueLightRedLight blueLightRedLight = new BlueLightRedLight(new Normal());
    
    // 익명 클래스로 주입 가능
    BlueLightRedLight blueLightRedLight = new BlueLightRedLight(new Speed(){
      @Override
      public void blueLight() {
        System.out.println(&quot;BLUE LIGHT&quot;);
      }
      
      @Override
      public void redLight() {
        System.out.println(&quot;RED RIGHT&quot;);
      }
    
    });
    
    blueLightRedLight.blueLight();
    blueLightRedLight.redLight();
  }
  
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;예시 (to-be : Operator에서)&lt;/h2&gt;
&lt;pre id=&quot;code_1667121823463&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class BlueLightRedLight {

  public void blueLight(Speed speed) {
    speed.blueLight();
  }
  
  public void redLight(Speed speed) {
    speed.redLight();
  }

} 

public interface Speed {

  void blueLight();
  
  void redLight();

}

public class Normal implements Speed {

  @Override
  public void blueLight() {
    System.out.println(&quot;무 궁 화    꽃  이&quot;);
  }
  
  @Override
  public void redLight() {
    System.out.println(&quot;피 었 습 니   다.&quot;);
  }

}


public class Fast implements Speed {

  @Override
  public void blueLight() {
    System.out.println(&quot;무궁화꽃이&quot;);
  }
  
  @Override
  public void redLight() {
    System.out.println(&quot;피었습니다.&quot;);
  }

}

public class Client {

  public static void main(String[] args) {
    BlueLightRedLight blueLightRedLight = new BlueLightRedLight();

    blueLightRedLight.blueLight(new Normal());
    blueLightRedLight.redLight(new Fast());
  }
  
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;활용&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Java의 Comparator&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1667122377135&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;Integer&amp;gt; numbers = new ArrayList&amp;lt;&amp;gt;();
numbers.add(10);
numbers.add(5);


// 내림차순 정렬
Collections.sort(numbers, Comparator.reverseOrder());

Collections.sort(numbers, new Comparator&amp;lt;Integer&amp;gt;() {
  @Override
  public int compare(Integer o1, Integer o2) {
    return o1 - o2;
  }
});


// 오름차순 정렬
Collections.sort(numbers);

Collections.sort(numbers, Comparator.naturalOrder());&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Spring의 Interface은 대부분 전략패턴이 적용되어 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;ApplicationContext&lt;/b&gt; : ClassPathXmlApplicationContext, FileSystemXmlApplicationContext, AnnotationConfigApplicationContext, ...&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PlatformTransactionManager&lt;/b&gt; : JdbcTransactionManager, JpaTransactionManager, ...&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Design Pattern</category>
      <author>ilot</author>
      <guid isPermaLink="true">https://ilot.tistory.com/13</guid>
      <comments>https://ilot.tistory.com/13#entry13comment</comments>
      <pubDate>Sun, 30 Oct 2022 18:35:16 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] Async</title>
      <link>https://ilot.tistory.com/12</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;참조 : &lt;a href=&quot;https://www.baeldung.com/spring-async&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.baeldung.com/spring-async&lt;/a&gt;&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 개요&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Spring에서 제공하는 비동기 작업과 애노테이션 @Async에 대해서 알아본다.&lt;/li&gt;
&lt;li&gt;@Async를 Bean의 메서드에 선언하는 것만으로 해당 메서드는 별도의 쓰레드에서 수행된다. 즉, @Async가 선언된 메서드를 호출하는 객체는 메서드가 끝날 때까지 기다리지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Async 옵션 켜기&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@Configuration과 @EnableAsync를 사용하여 Async 옵션을 켤 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1666965299319&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@EnableAsync
public class SpringAsyncConfig {
  // ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@EnableAsync의 속성 부여를 통해 다양한 설정이 가능하다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;annotation&lt;/b&gt; : &lt;i&gt;@EnableAsync&lt;/i&gt;는 Default로 스프링의 &lt;i&gt;@Async&lt;/i&gt;과 EJB 3.1의 &lt;i&gt;javax.ejb.Asynchronous&lt;/i&gt;를 탐색한다. 이 옵션을 변경하여 다른 것을 탐색하도록 할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;mode&lt;/b&gt;&amp;nbsp;:&amp;nbsp;사용할&amp;nbsp;advice의&amp;nbsp;타입을&amp;nbsp;지정한다.&amp;nbsp;(JDK&amp;nbsp;프록시&amp;nbsp;기반&amp;nbsp;혹은&amp;nbsp;AspectJ&amp;nbsp;weaving을&amp;nbsp;통해)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;proxyTargetClass&lt;/b&gt; : 사용할 프록시 타입을 지정한다. (CGLib 혹은 JDK를 통해) 이 속성은 mode가 &lt;i&gt;AdviceMode.PROXY&lt;/i&gt;로 지정되었을 때만 작용된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;order&lt;/b&gt;&amp;nbsp;:&amp;nbsp;&lt;i&gt;AsyncAnnotationBeanPostProcessor&lt;/i&gt;가&amp;nbsp;적용되어야&amp;nbsp;할&amp;nbsp;순서를&amp;nbsp;설정할&amp;nbsp;수&amp;nbsp;있다.&amp;nbsp;기본값으로,&amp;nbsp;존재하는&amp;nbsp;모든&amp;nbsp;프록시&amp;nbsp;객체를&amp;nbsp;고려하여&amp;nbsp;맨&amp;nbsp;마지막에&amp;nbsp;적용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 애노테이션 @Async&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;애노테이션 @Async에는 두가지 제한점이 있다. 애노테이션이 지정되는 순간, 프록시 객체 형태로 수행되기 떄문이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;제한점&amp;nbsp;1&amp;nbsp;:&amp;nbsp;public&amp;nbsp;메서드에서만&amp;nbsp;적용&amp;nbsp;가능하다.&lt;/li&gt;
&lt;li&gt;제한점&amp;nbsp;2&amp;nbsp;:&amp;nbsp;동일한&amp;nbsp;클래스&amp;nbsp;내에서&amp;nbsp;호출&amp;nbsp;시,&amp;nbsp;비동기&amp;nbsp;호출이&amp;nbsp;불가하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1 아무것도 반환하지 않는 메서드&lt;/h3&gt;
&lt;pre id=&quot;code_1666965450059&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Async
public void asyncMethodWithVoidReturnType() {
  System.out.println(&quot;Execute method asynchronously. &quot; + Thread.currentThread().getName());
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2 반환값이 있는 메서드&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@Async가 지정된 메서드는 &lt;i&gt;Future&lt;/i&gt;로 감싼 값을 반환할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1666965484819&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Async
public Future&amp;lt;String&amp;gt; asyncMethodWithReturnType() {
  System.out.println(&quot;Execute method asynchronously. &quot; + Thread.currentThread().getName());
  try {
    Thread.sleep(5000);
    return new AsyncResult&amp;lt;String&amp;gt;(&quot;hello world&quot;);
  } catch (InterruptedException ignored) {
  }

  return null;
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Spring은 Future를 구현한 클래스 &lt;i&gt;AsyncResult&lt;/i&gt;를 제공하여, 비동기 메서드 호출의 결과를 추적할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1666965624133&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public void testAsyncAnnotationForMethodsWithReturnType()
  throws InterruptedException, ExecutionException {

  System.out.println(&quot;Invoking an asynchronous method. &quot; + Thread.currentThread().getName());

  Future&amp;lt;String&amp;gt; future = asyncAnnotationExample.asyncMethodWithReturnType();

  while (true) {
    if (future.isDone()) {
      System.out.println(&quot;Invoking an asynchronous method. &quot; + Thread.currentThread().getName());
      break;
    }

    System.out.println(&quot;Result from asynchronous process - &quot; + future.get());
    Thread.sleep(1000);
  }

}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 비동기 메서드의 Executor&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본적으로, 스프링은 비동기 메서드를 실행할 때 &lt;i&gt;SimpleAsyncTaskExecutor&lt;/i&gt;를 사용한다. 그러나 다른 Executor를 사용하도록 설정할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.1 메서드 레벨에서 Executor 설정 변경하기&lt;/h3&gt;
&lt;pre id=&quot;code_1666965699528&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@EnableAsync
public class SpringAsyncConfig {

  @Bean(name = &quot;threadPoolTaskExecutor&quot;)
  public Executor threadPoolTaskExecutor() {
    return new ThreadPoolTaskExecutor();
  }

}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1666965708738&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Async(&quot;threadPoolTaskExecutor&quot;)
public void asyncMethodWithConfiguredExecutor() {
  System.out.println(&quot;Execute method with configured executor - &quot; + Thread.currentThread().getName());
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.2 애플리케이션 레벨에서 Executor 설정 변경하기&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Config 클래스에 &lt;i&gt;AsyncConfigurer&lt;/i&gt;를 구현하고, 오버라이드된 &lt;i&gt;getAsyncExecutor()&lt;/i&gt;에 변경하고자 하는 Executor를 반환하면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1666965758127&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@EnableAsync
public class SpringAsyncConfig implements AsyncConfigurer {

  @Override
  public Executor getAsyncExecutor() {
    return new ThreadPoolTaskExecutor();
  }

}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. Exception Handling&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;반환 타입이 &lt;i&gt;Future&lt;/i&gt;인 Async 메서드 실행 중에 Exception 발생 시, &lt;i&gt;Future.get()&lt;/i&gt;메서드가 Exception을 던지게 된다.&lt;/li&gt;
&lt;li&gt;만일 Async 메서드의 반환 타입이 void라면, Async 메서드 호출하는 곳으로 Exception이 전파되지 않는다. 이 경우에는 추가 설정을 통해 Exception을 처리해야 한다.&lt;/li&gt;
&lt;li&gt;아래와 같이, 커스텀 Exception Handler 클래스를 생성하여야 한다. &lt;i&gt;AsyncUncaughtExceptionHandler&lt;/i&gt;의 &lt;i&gt;handleUncaughtException&lt;/i&gt;에 예외 처리 로직을 넣으면 된다. &lt;/li&gt;
&lt;li&gt;클래스를 생성하여, &lt;i&gt;AsyncConfig&lt;/i&gt;의 &lt;i&gt;getAsyncUncaughtExceptionHandler()&lt;/i&gt;의 반환 값으로 넣어주면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1666965822527&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {

  @Override
  public void handleUncaughtException(Throwable throwable, Method method, Object... obj) {
    System.out.println(&quot;Exception message - &quot; + throwable.getMessage());
    System.out.println(&quot;Method name - &quot; + method.getName());
    for (Object param : obj) {
      System.out.println(&quot;Parameter value - &quot; + param);
    }
  }

}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1666965839118&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@EnableAsync
public class SpringAsyncConfig implements AsyncConfigurer {

  @Override
  public Executor getAsyncExecutor() {
    return new ThreadPoolTaskExecutor();
  }

  @Override
  public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
    return new CustomAsyncExceptionHandler();
  }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;99. 더 읽어 볼 것&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.baeldung.com/spring-events&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.baeldung.com/spring-events&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.baeldung.com/spring-security-async-principal-propagation&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.baeldung.com/spring-security-async-principal-propagation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.baeldung.com/spring-mvc-async-security&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.baeldung.com/spring-mvc-async-security&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring</category>
      <author>ilot</author>
      <guid isPermaLink="true">https://ilot.tistory.com/12</guid>
      <comments>https://ilot.tistory.com/12#entry12comment</comments>
      <pubDate>Fri, 28 Oct 2022 23:05:30 +0900</pubDate>
    </item>
    <item>
      <title>[Java] Collection의 of 사용 시 주의할 점</title>
      <link>https://ilot.tistory.com/11</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Java 9부터 사용할 수 있는 of를 통해 Map, Set, List 등의 Java Collection을 손쉽게 초기화할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. value에 null이 들어가면 안된다.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, Map.of(), Set.of(), List.of() 등을 사용할 때, value에 null을 넣게 되면 NullPointerException이 발생합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1666792298407&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class CollectionOfTest {

  @Test(expected = NullPointerException.class)
  public void mapOfTest() {
    Map&amp;lt;String, Object&amp;gt; map = Map.of(&quot;key1&quot;, null); // NullPointerException 발생
  }

  @Test(expected = NullPointerException.class)
  public void listOfTest() {
    List&amp;lt;String&amp;gt; list = List.of(&quot;a&quot;, null); // NullPointerException 발생
  }

  @Test(expected = NullPointerException.class)
  public void setOfTest() {
    Set&amp;lt;String&amp;gt; set = Set.of(&quot;a&quot;, null); // NullPointerException 발생
  }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. Map.of()에는 개수 제한이 있다&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;925&quot; data-origin-height=&quot;645&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zOO7u/btrPEjphMwR/zKAM8kREGrFTnVXKkP1Bak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zOO7u/btrPEjphMwR/zKAM8kREGrFTnVXKkP1Bak/img.png&quot; data-alt=&quot;key를 11개를 넣어보니..&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zOO7u/btrPEjphMwR/zKAM8kREGrFTnVXKkP1Bak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzOO7u%2FbtrPEjphMwR%2FzKAM8kREGrFTnVXKkP1Bak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;925&quot; height=&quot;645&quot; data-origin-width=&quot;925&quot; data-origin-height=&quot;645&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;key를 11개를 넣어보니..&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;845&quot; data-origin-height=&quot;131&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cuZSet/btrPFdhL4Yh/90ASJL5XkDUe61gf8kcLHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cuZSet/btrPFdhL4Yh/90ASJL5XkDUe61gf8kcLHk/img.png&quot; data-alt=&quot;key-value 쌍을 10개까지만 오버라이드 된 것을 확인할 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cuZSet/btrPFdhL4Yh/90ASJL5XkDUe61gf8kcLHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcuZSet%2FbtrPFdhL4Yh%2F90ASJL5XkDUe61gf8kcLHk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;845&quot; height=&quot;131&quot; data-origin-width=&quot;845&quot; data-origin-height=&quot;131&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;key-value 쌍을 10개까지만 오버라이드 된 것을 확인할 수 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Map.of()에는 개수 제한이 있으므로, 11개 이상의 Map을 초기화 하고 싶다면 Map.ofEntries()를 사용해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로, Set.of()와 List.of()는 파라미터를 가변인자로 받고 있기 때문에, 파라미터 개수 제한이 없다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;376&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rKocd/btrPCD3tYPu/PGjeVu4xzPQ6hqIc8E2eeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rKocd/btrPCD3tYPu/PGjeVu4xzPQ6hqIc8E2eeK/img.png&quot; data-alt=&quot;List.of()&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rKocd/btrPCD3tYPu/PGjeVu4xzPQ6hqIc8E2eeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrKocd%2FbtrPCD3tYPu%2FPGjeVu4xzPQ6hqIc8E2eeK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;376&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;376&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;List.of()&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;808&quot; data-origin-height=&quot;378&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rXLbo/btrPECWwrPw/v2UyOpung12NVMXnOabrc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rXLbo/btrPECWwrPw/v2UyOpung12NVMXnOabrc0/img.png&quot; data-alt=&quot;Set.of()&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rXLbo/btrPECWwrPw/v2UyOpung12NVMXnOabrc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrXLbo%2FbtrPECWwrPw%2Fv2UyOpung12NVMXnOabrc0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;808&quot; height=&quot;378&quot; data-origin-width=&quot;808&quot; data-origin-height=&quot;378&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Set.of()&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. of()와 ofEntries()는 Immutuable 객체를 반환한다.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;of와 ofEntries는 Immutable 객체를 반환하므로, 이를 반환받은 객체에 put이나 remove가 불가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1666793013667&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Test(expected = UnsupportedOperationException.class)
public void immutableTest() {
  Map&amp;lt;String, Object&amp;gt; map = Map.of(&quot;key01&quot;, &quot;a&quot;);
  map.put(&quot;key2&quot;, &quot;test&quot;); // UnsupportedOperationException 발생
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;참조 : &lt;a href=&quot;https://velog.io/@sangwoo0727/Map.of-를-통한-Map-초기화-주의할-점&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://velog.io/@sangwoo0727/Map.of-를-통한-Map-초기화-주의할-점&lt;/a&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <author>ilot</author>
      <guid isPermaLink="true">https://ilot.tistory.com/11</guid>
      <comments>https://ilot.tistory.com/11#entry11comment</comments>
      <pubDate>Wed, 26 Oct 2022 23:03:59 +0900</pubDate>
    </item>
  </channel>
</rss>