<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>The Office Lover</title>
    <link>https://daniel6364.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sat, 9 May 2026 15:07:02 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Michael Gary Scott</managingEditor>
    <image>
      <title>The Office Lover</title>
      <url>https://tistory1.daumcdn.net/tistory/3486477/attach/3d1eb3d937ca474998e2822b0dfefbaa</url>
      <link>https://daniel6364.tistory.com</link>
    </image>
    <item>
      <title>제어의 역전 - Inversion of Control</title>
      <link>https://daniel6364.tistory.com/entry/%EC%A0%9C%EC%96%B4%EC%9D%98-%EC%97%AD%EC%A0%84-Inversion-of-Control</link>
      <description>&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;스프링 프레임워크의 핵심 개념 중 하나인 제어의 역전(Inversion of Control, IoC)은 객체지향 프로그래밍에서 중요한 원칙 중 하나인 &quot;의존성 역전(Dependency Inversion)&quot;을 구현하는 방식입니다.&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;pexels-fernando-arcos-211151.jpg&quot; data-origin-width=&quot;4134&quot; data-origin-height=&quot;2749&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dyFe4Z/btsqPZooPvZ/qrogtB1mETrYsJxKfrw2W1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dyFe4Z/btsqPZooPvZ/qrogtB1mETrYsJxKfrw2W1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dyFe4Z/btsqPZooPvZ/qrogtB1mETrYsJxKfrw2W1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdyFe4Z%2FbtsqPZooPvZ%2FqrogtB1mETrYsJxKfrw2W1%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; alt=&quot;제어의역전&quot; loading=&quot;lazy&quot; width=&quot;4134&quot; height=&quot;2749&quot; data-filename=&quot;pexels-fernando-arcos-211151.jpg&quot; data-origin-width=&quot;4134&quot; data-origin-height=&quot;2749&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Java 코드 예시&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. ArticleService 인터페이스&lt;/h4&gt;
&lt;pre id=&quot;code_1691719288899&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface ArticleService {
    List&amp;lt;Article&amp;gt; getAllArticles();
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. ArticleServiceImpl 클래스&lt;/h4&gt;
&lt;pre id=&quot;code_1691719295564&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class ArticleServiceImpl implements ArticleService {
    private ArticleRepository articleRepository;

    public ArticleServiceImpl() {
        this.articleRepository = new ArticleRepository(); // 직접 객체 생성
    }

    @Override
    public List&amp;lt;Article&amp;gt; getAllArticles() {
        return articleRepository.getAllArticles();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서 ArticleServiceImpl은 ArticleRepository라는 데이터베이스와 상호 작용하는 객체를 직접 생성하고 사용하고 있습니다. 이런 경우에는 ArticleServiceImpl이 ArticleRepository에 &lt;b&gt;강하게 의존&lt;/b&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;위 예제를 IOC 적용하여 살펴보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. Spring 설정 파일 (&lt;b&gt;applicationContext.xml&lt;/b&gt;)&lt;/h4&gt;
&lt;pre id=&quot;code_1691719459385&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
       xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;&amp;gt;

    &amp;lt;bean id=&quot;articleService&quot; class=&quot;com.example.ArticleServiceImpl&quot;&amp;gt;
        &amp;lt;property name=&quot;articleRepository&quot; ref=&quot;articleRepository&quot;/&amp;gt;
    &amp;lt;/bean&amp;gt;
    
    &amp;lt;bean id=&quot;articleRepository&quot; class=&quot;com.example.ArticleRepository&quot;/&amp;gt;
&amp;lt;/beans&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 설정 파일에서 articleService와 articleRepository를 빈(bean)으로 정의하고, articleService의 articleRepository 의존성을 주입하도록 설정했습니다. 이제 &lt;b&gt;스프링 컨테이너가 이 설정을 기반으로 빈을 생성하고 관리&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 사용 코드&lt;/h4&gt;
&lt;pre id=&quot;code_1691719674501&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext(&quot;applicationContext.xml&quot;);
        ArticleService articleService = context.getBean(&quot;articleService&quot;, ArticleService.class);

        List&amp;lt;Article&amp;gt; articles = articleService.getAllArticles();
        // articles를 사용하여 작업 수행
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서 ApplicationContext를 생성하고 설정 파일을 로드한 후 articleService 빈을 가져와 사용합니다. 이때 articleService는 스프링 컨테이너가 생성하고 주입한 객체입니다. 이로써 ArticleServiceImpl은 직접적으로 ArticleRepository를 생성하지 않고 스프링 컨테이너에 의해 주입되어 &lt;b&gt;느슨한 결합을 유지&lt;/b&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;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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;pexels-image-hunter-13092792.jpg&quot; data-origin-width=&quot;5760&quot; data-origin-height=&quot;3840&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVsZtx/btsqO9EeW09/EB5R2ZUVodFULUw6aIsOhk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVsZtx/btsqO9EeW09/EB5R2ZUVodFULUw6aIsOhk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVsZtx/btsqO9EeW09/EB5R2ZUVodFULUw6aIsOhk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVsZtx%2FbtsqO9EeW09%2FEB5R2ZUVodFULUw6aIsOhk%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; alt=&quot;제어의역전&quot; loading=&quot;lazy&quot; width=&quot;5760&quot; height=&quot;3840&quot; data-filename=&quot;pexels-image-hunter-13092792.jpg&quot; data-origin-width=&quot;5760&quot; data-origin-height=&quot;3840&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;제어의 역전(Inversion of Control)을 사용해야 하는 이유&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;IoC를 사용하면 객체 간의 의존성이 감소하고, 각각의 컴포넌트가 독립적으로 개발될 수 있습니다. 이로써 시스템의 유지 보수 및 확장이 쉬워지며, 컴포넌트 간의 변경이 다른 컴포넌트에 미치는 영향이 최소화됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 재사용성&lt;/h4&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;h4 data-ke-size=&quot;size20&quot;&gt;3. 테스트 용이성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의존성을 주입하여 가짜(mock) 객체를 주입하거나 테스트용 객체를 쉽게 사용할 수 있습니다. 이로써 단위 테스트난 통합 테스트를 더 쉽게 수행할 수 있으며, 코드의 품질과 안정성을 향상실킬 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4. 유연성과 확장성&lt;/h4&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;h4 data-ke-size=&quot;size20&quot;&gt;5. 중앙화된 관리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IoC 컨테이너는 객체의 생명주기를 관리하므로 객체의 생성, 소멸, 의존성 주입 등을 중앙에서 관리할 수 있습니다. 이로써 코드의 중복을 줄이고 관리하기 쉬운 코드를 작성할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;6. 코드 가독성 및 유지 보수성&lt;/h4&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;h4 data-ke-size=&quot;size20&quot;&gt;7. 다양한 환경에 대한 지원&lt;/h4&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결론&amp;nbsp;&lt;/h3&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Backend</category>
      <category>InversionOfControl</category>
      <category>IOC</category>
      <category>스프링프레임워크</category>
      <category>제어의역전</category>
      <author>Michael Gary Scott</author>
      <guid isPermaLink="true">https://daniel6364.tistory.com/17</guid>
      <comments>https://daniel6364.tistory.com/entry/%EC%A0%9C%EC%96%B4%EC%9D%98-%EC%97%AD%EC%A0%84-Inversion-of-Control#entry17comment</comments>
      <pubDate>Fri, 11 Aug 2023 11:21:23 +0900</pubDate>
    </item>
    <item>
      <title>의존 역전 원칙 - dependency inversion principle</title>
      <link>https://daniel6364.tistory.com/entry/%EC%9D%98%EC%A1%B4-%EC%97%AD%EC%A0%84-%EC%9B%90%EC%B9%99-dependency-inversion-principle</link>
      <description>&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://daniel6364.tistory.com/entry/%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99-single-responsibility-principle-SRP&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2023.07.27 - [Design Patterns] - 단일 책임 원칙 - single responsibility principle, SRP&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1691632136366&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;단일 책임 원칙 - single responsibility principle, SRP&quot; data-og-description=&quot;소개 객체지향 프로그래밍은 유지보수성과 재사용성으르 높이기 위해 다양한 설계 원칙을 제공합니다. 이 중에서도 '단일 책임 원칙'은 클래스나 모듈이 하나의 책임만을 가져야 한다는 원칙으&quot; data-og-host=&quot;daniel6364.tistory.com&quot; data-og-source-url=&quot;https://daniel6364.tistory.com/entry/%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99-single-responsibility-principle-SRP&quot; data-og-url=&quot;https://daniel6364.tistory.com/entry/%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99-single-responsibility-principle-SRP&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/FvyRF/hyTBznMjHz/inT01cFtxM5EM38lkAP3Zk/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/cf1ZoA/hyTCIpTU1n/BEWvEzYrvwVOOgufraknF1/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/cIP8uY/hyTCzT1nxk/om7zRKd21VNu05UDKcfL0K/img.jpg?width=6016&amp;amp;height=4016&amp;amp;face=2904_1682_3110_1907&quot;&gt;&lt;a href=&quot;https://daniel6364.tistory.com/entry/%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99-single-responsibility-principle-SRP&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://daniel6364.tistory.com/entry/%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99-single-responsibility-principle-SRP&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/FvyRF/hyTBznMjHz/inT01cFtxM5EM38lkAP3Zk/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/cf1ZoA/hyTCIpTU1n/BEWvEzYrvwVOOgufraknF1/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/cIP8uY/hyTCzT1nxk/om7zRKd21VNu05UDKcfL0K/img.jpg?width=6016&amp;amp;height=4016&amp;amp;face=2904_1682_3110_1907');&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;단일 책임 원칙 - single responsibility principle, SRP&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;소개 객체지향 프로그래밍은 유지보수성과 재사용성으르 높이기 위해 다양한 설계 원칙을 제공합니다. 이 중에서도 '단일 책임 원칙'은 클래스나 모듈이 하나의 책임만을 가져야 한다는 원칙으&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;daniel6364.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://daniel6364.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EA%B0%9C%EB%B0%A9-%ED%8F%90%EC%87%84-%EC%9B%90%EC%B9%99&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2023.06.08 - [Design Patterns] - 디자인 패턴 - 개방 폐쇄 원칙&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1691632147182&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;디자인 패턴 - 개방 폐쇄 원칙&quot; data-og-description=&quot;확장할 때는 개방, 수정할 때는 폐쇄 개방 폐쇄 원칙은 코드의 확장성 문제로 볼 수 있다. 추후 변경되는 요구 사항에 대응할 때 코드가 확장할 때는 개방, 수정할 때는 폐쇄될 수 있다면 해당 코&quot; data-og-host=&quot;daniel6364.tistory.com&quot; data-og-source-url=&quot;https://daniel6364.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EA%B0%9C%EB%B0%A9-%ED%8F%90%EC%87%84-%EC%9B%90%EC%B9%99&quot; data-og-url=&quot;https://daniel6364.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EA%B0%9C%EB%B0%A9-%ED%8F%90%EC%87%84-%EC%9B%90%EC%B9%99&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Ga9UK/hyTBveD78v/wtpxK71BSAs6zpseB5r9Pk/img.jpg?width=800&amp;amp;height=534&amp;amp;face=0_0_800_534,https://scrap.kakaocdn.net/dn/2PevK/hyTCHqZlg0/uBgnRzDKOyLwdBEXYXzpAK/img.jpg?width=800&amp;amp;height=534&amp;amp;face=0_0_800_534,https://scrap.kakaocdn.net/dn/dcabzo/hyTCIDrdrr/V3gMGBYWpYvx5VnKBiQdL1/img.jpg?width=5184&amp;amp;height=3456&amp;amp;face=0_0_5184_3456&quot;&gt;&lt;a href=&quot;https://daniel6364.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EA%B0%9C%EB%B0%A9-%ED%8F%90%EC%87%84-%EC%9B%90%EC%B9%99&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://daniel6364.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EA%B0%9C%EB%B0%A9-%ED%8F%90%EC%87%84-%EC%9B%90%EC%B9%99&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Ga9UK/hyTBveD78v/wtpxK71BSAs6zpseB5r9Pk/img.jpg?width=800&amp;amp;height=534&amp;amp;face=0_0_800_534,https://scrap.kakaocdn.net/dn/2PevK/hyTCHqZlg0/uBgnRzDKOyLwdBEXYXzpAK/img.jpg?width=800&amp;amp;height=534&amp;amp;face=0_0_800_534,https://scrap.kakaocdn.net/dn/dcabzo/hyTCIDrdrr/V3gMGBYWpYvx5VnKBiQdL1/img.jpg?width=5184&amp;amp;height=3456&amp;amp;face=0_0_5184_3456');&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;확장할 때는 개방, 수정할 때는 폐쇄 개방 폐쇄 원칙은 코드의 확장성 문제로 볼 수 있다. 추후 변경되는 요구 사항에 대응할 때 코드가 확장할 때는 개방, 수정할 때는 폐쇄될 수 있다면 해당 코&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;daniel6364.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;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;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;pexels-radarsky-15345028.jpg&quot; data-origin-width=&quot;6240&quot; data-origin-height=&quot;4160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfE0lE/btsqKDryYak/kzwKpXab3KCGsIOTjJfe81/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfE0lE/btsqKDryYak/kzwKpXab3KCGsIOTjJfe81/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfE0lE/btsqKDryYak/kzwKpXab3KCGsIOTjJfe81/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfE0lE%2FbtsqKDryYak%2FkzwKpXab3KCGsIOTjJfe81%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; alt=&quot;역전의존원칙&quot; loading=&quot;lazy&quot; width=&quot;6240&quot; height=&quot;4160&quot; data-filename=&quot;pexels-radarsky-15345028.jpg&quot; data-origin-width=&quot;6240&quot; data-origin-height=&quot;4160&quot;/&gt;&lt;/span&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;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 의존성 주입(Dependency Injection)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;의존성(Dependency)은 한 클래스나 모듈이 다른 클래스나 모듈에 의존하는 것을 의미합니다. 이것은 한 요소의 변경이 다른 요소에 영향을 미칠 수 있다는 것을 나타냅니다.&lt;/li&gt;
&lt;li&gt;의존성 주입(Dependency Injection)은 특정한 프로그래밍 기술로써 이해하거나 적용하기 쉽고 매우 유용합니다.&lt;/li&gt;
&lt;li&gt;의존성 주입을 한 문장으로 요약하면 &lt;b&gt;new 예약어를 사용하여 클래스 내부에 종속되는 클래스의 객체를 생성하는 대신, 외부에서 종속 클래스의 객체를 생성한 후 생성자, 함수의 매개변수 등을 통해 클래스에 주입&lt;/b&gt;하는 것을 의미합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 의존 역전(Dependency Inversion)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;의존 역전(Dependency Inversion)은 상위 모듈이 하위 모듈에 의존하지 않도록 하며, 두 모듈 모두 추상화에 의존하도록 설계하는 원칙입니다. 즉, 상세한 구현이 아니라 추상화에 의존함으로써 모듈 간의 결합도를 낮추고 유연성을 높입니다.&lt;/li&gt;
&lt;li&gt;상위 모듈과 하위 모듈의 구분은 간단히 말하자면 호출자는 상위 모듈에 속하고, 수신자는 하위 모듈에 속합니다.&lt;/li&gt;
&lt;li&gt;Tomcat을 예로 들어보면 Tomcat은 자바 웹 애플리케이션을 실행하기 위한 컨테이너입니다. 웹 애플리케이션 코드는 Tomcat 컨테이너에 배포만 하면 별도의 작업이 필요 없이 Tomcat 컨테이너에서 호출하고 실행할 수 있습니다. 여기서 상위 모듈이 Tomcat이고 하위 모듈이 웹 애플리케이션에 해당됩니다. 둘 사이에는 직접적인 의존성이 없고 동일한 추상인 서블릿 사양에 의존합니다.&amp;nbsp;&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;[비효율적인 초기 코드 설계 예시]&lt;/p&gt;
&lt;pre id=&quot;code_1691631245842&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class MessageSender {
    public void sendMessage(String message) {
        // 메시지 전송 로직
    }
}

class MessageReceiver {
    public String receiveMessage() {
        // 메시지 수신 로직
    }
}

class Application {
    private MessageSender sender;
    private MessageReceiver receiver;

    public Application() {
        sender = new MessageSender();
        receiver = new MessageReceiver();
    }

    public void run() {
        String message = receiver.receiveMessage();
        sender.sendMessage(message);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시에서는 Application 클래스가 MessageSender와 MessageReceiver에 의존하고 있습니다. 이는 의존성이 상세한 구현에 직접적으로 연결되어 있어 유연성이 떨어집니다.&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;p data-ke-size=&quot;size16&quot;&gt;[의존 역전을 적용한 코드 설계 예시]&lt;/p&gt;
&lt;pre id=&quot;code_1691631386557&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface MessageService {
    void sendMessage(String message);
    String receiveMessage();
}

class MessageSender implements MessageService {
    @Override
    public void sendMessage(String message) {
        // 메시지 전송 로직
    }

    @Override
    public String receiveMessage() {
        throw new UnsupportedOperationException(&quot;Sender cannot receive messages&quot;);
    }
}

class MessageReceiver implements MessageService {
    @Override
    public void sendMessage(String message) {
        throw new UnsupportedOperationException(&quot;Receiver cannot send messages&quot;);
    }

    @Override
    public String receiveMessage() {
        // 메시지 수신 로직
    }
}

class Application {
    private MessageService service;

    public Application(MessageService service) {
        this.service = service;
    }

    public void run() {
        String message = service.receiveMessage();
        service.sendMessage(message);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시는 Application 클래스가 MessageService 인터페이스에만 의존하도록 변경되었습니다. 이를 통해 상위 모듈(Application)과 하위 모듈(MessageSender, MessageReceiver) 간의 결합도가 줄어들었습니다.&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;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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;pexels-andres-ayrton-6551415.jpg&quot; data-origin-width=&quot;6000&quot; data-origin-height=&quot;4000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcz7bJ/btsqKAnQQp6/IVx01uO1W9krLYj3Vxhbq0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcz7bJ/btsqKAnQQp6/IVx01uO1W9krLYj3Vxhbq0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcz7bJ/btsqKAnQQp6/IVx01uO1W9krLYj3Vxhbq0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbcz7bJ%2FbtsqKAnQQp6%2FIVx01uO1W9krLYj3Vxhbq0%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; alt=&quot;역전의존원칙&quot; loading=&quot;lazy&quot; width=&quot;6000&quot; height=&quot;4000&quot; data-filename=&quot;pexels-andres-ayrton-6551415.jpg&quot; data-origin-width=&quot;6000&quot; data-origin-height=&quot;4000&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;의존 역전 원칙을 따르는 것은 소프트웨어의 유지보수성과 확장성을 높이는 데에 큰 도움을 줍니다.&amp;nbsp;&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Design Patterns</category>
      <category>Dependency Inversion Principle</category>
      <category>DIP</category>
      <category>SOLID원칙</category>
      <category>디자인패턴</category>
      <category>설계원칙</category>
      <category>의존역전원칙</category>
      <author>Michael Gary Scott</author>
      <guid isPermaLink="true">https://daniel6364.tistory.com/16</guid>
      <comments>https://daniel6364.tistory.com/entry/%EC%9D%98%EC%A1%B4-%EC%97%AD%EC%A0%84-%EC%9B%90%EC%B9%99-dependency-inversion-principle#entry16comment</comments>
      <pubDate>Thu, 10 Aug 2023 10:50:52 +0900</pubDate>
    </item>
    <item>
      <title>Commit과 Rollback</title>
      <link>https://daniel6364.tistory.com/entry/Commit%EA%B3%BC-Rollback</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;소개&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RDBMS에서 중요한 두 가지 개념인 Commit과 Rollback에 대해 쉽게 이해할 수 있도록 설명드리겠습니다. 앞서 RDBMS의 개념을 먼저 보고 오시면 더 쉽게 이해가 되실 수 있으니 참고 바랍니다.&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://daniel6364.tistory.com/entry/PostgreSQL-RDBMS&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2023.07.24 - [DataBase] - PostgreSQL - RDBMS&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1690785723792&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;PostgreSQL - RDBMS&quot; data-og-description=&quot;PostgreSQL의 주요 특징 - RDMBS : Relational Database Management System 1. 오픈소스 2. 객체-관계형 데이터베이스 : PostgreSQL은 기본적으로 관계형 데이터베이스 시스템이지만, 확장 기능으로 객체-관계형 데이&quot; data-og-host=&quot;daniel6364.tistory.com&quot; data-og-source-url=&quot;https://daniel6364.tistory.com/entry/PostgreSQL-RDBMS&quot; data-og-url=&quot;https://daniel6364.tistory.com/entry/PostgreSQL-RDBMS&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bKMVTC/hyTvlu7hxQ/ruRb5PnWZdUlM4J06ATN5k/img.jpg?width=800&amp;amp;height=534&amp;amp;face=0_0_800_534,https://scrap.kakaocdn.net/dn/69qg1/hyTtiNz6fa/w2ot6nc8NcnN2GcwWn5ixk/img.jpg?width=800&amp;amp;height=534&amp;amp;face=0_0_800_534,https://scrap.kakaocdn.net/dn/bWEW4R/hyTtvsCIzo/LlgSe1mVltxV1GDb1n7mxK/img.jpg?width=6016&amp;amp;height=4016&amp;amp;face=0_0_6016_4016&quot;&gt;&lt;a href=&quot;https://daniel6364.tistory.com/entry/PostgreSQL-RDBMS&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://daniel6364.tistory.com/entry/PostgreSQL-RDBMS&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bKMVTC/hyTvlu7hxQ/ruRb5PnWZdUlM4J06ATN5k/img.jpg?width=800&amp;amp;height=534&amp;amp;face=0_0_800_534,https://scrap.kakaocdn.net/dn/69qg1/hyTtiNz6fa/w2ot6nc8NcnN2GcwWn5ixk/img.jpg?width=800&amp;amp;height=534&amp;amp;face=0_0_800_534,https://scrap.kakaocdn.net/dn/bWEW4R/hyTtvsCIzo/LlgSe1mVltxV1GDb1n7mxK/img.jpg?width=6016&amp;amp;height=4016&amp;amp;face=0_0_6016_4016');&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;PostgreSQL - RDBMS&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;PostgreSQL의 주요 특징 - RDMBS : Relational Database Management System 1. 오픈소스 2. 객체-관계형 데이터베이스 : PostgreSQL은 기본적으로 관계형 데이터베이스 시스템이지만, 확장 기능으로 객체-관계형 데이&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;daniel6364.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Commit이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Commit은 데이터베이스에 변경된 내용을 영구적으로 저장하는 작업을 의미합니다. 데이터를 추가하거나 수정하거나 삭제한 후에, 그 변경 사항들을 확정짓는 작업입니다.&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;Rollback이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Rollback은 이미 수행한 변경 작업을 취소하는 작업입니다. 어떤 이유로 인해 작업이 실패하거나 잘못된 결과가 나왔을 때, 이전 상태로 되돌리는 역할을 합니다.&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;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;pexels-karolina-grabowska-6333908.jpg&quot; data-origin-width=&quot;6720&quot; data-origin-height=&quot;4480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/63v02/btsppIHVYF0/tJgbRVg9hAMBYlazQibYHK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/63v02/btsppIHVYF0/tJgbRVg9hAMBYlazQibYHK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/63v02/btsppIHVYF0/tJgbRVg9hAMBYlazQibYHK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F63v02%2FbtsppIHVYF0%2FtJgbRVg9hAMBYlazQibYHK%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; alt=&quot;Commit과 Rollback&quot; loading=&quot;lazy&quot; width=&quot;6720&quot; height=&quot;4480&quot; data-filename=&quot;pexels-karolina-grabowska-6333908.jpg&quot; data-origin-width=&quot;6720&quot; data-origin-height=&quot;4480&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Commit과 Rollback의 사용 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 RDBMS에서는 트랜잭션(Transaction)이라는 개념을 사용하여 Commit과 Rollback을 관리합니다. 트랜잭션은 데이터베이스 작업을 하나로 묶은 것을 의미합니다. 모든 작업이 정상적으로 처리되면 Commit을 실행하여 변경사항을 반영하는 개념이고, 작업 중 오류가 발생하거나 취소해야 할 경우 Rollback을 실행합니다.&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;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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;pexels-peter-olexa-14299950.jpg&quot; data-origin-width=&quot;4886&quot; data-origin-height=&quot;3257&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dpLWWp/btsplMRLMiP/zpb9ctwku0V4BAq0XIdmE0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dpLWWp/btsplMRLMiP/zpb9ctwku0V4BAq0XIdmE0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dpLWWp/btsplMRLMiP/zpb9ctwku0V4BAq0XIdmE0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdpLWWp%2FbtsplMRLMiP%2Fzpb9ctwku0V4BAq0XIdmE0%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; alt=&quot;Commit과 Rollback&quot; loading=&quot;lazy&quot; width=&quot;4886&quot; height=&quot;3257&quot; data-filename=&quot;pexels-peter-olexa-14299950.jpg&quot; data-origin-width=&quot;4886&quot; data-origin-height=&quot;3257&quot;/&gt;&lt;/span&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;[Commit]&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고객 A와 고객 B가 각각 은행 계좌를 가지고 있습니다. 잔고는 다음과 같습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;고객명&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;계좌번호&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;잔고&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;고객 A&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;1001&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;100,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;고객 B&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;1002&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;50,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, 고객 A가 고객 B에게 20,000원을 이체하려고 합니다.&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;고객 A의 이체 작업은 하나의 트랜잭션으로 시작됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;트랜잭션 시작&lt;/li&gt;
&lt;li&gt;출금 : 1001계좌의 잔고에서 20,000원 차감
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1001 계좌 잔고 = 80,000원&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;입금 : 1002계좌의 잔고에서 20,000원 증가
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1002 계좌 잔고 = 70,000원&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;트랜잭션 종료&lt;/li&gt;
&lt;li&gt;Commit;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;[Rollback]&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이번에는 고객 C가 은행 계좌를 새로 개설했습니다.&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;고객명&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;계좌번호&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;잔고&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;고객 C&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;1003&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;50,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;하지만, 실수로 5,000원을 입금한다는 걸 50,000원을 잘못 입금했습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;고객 C의 이체 작업은 하나의 트랜잭션으로 시작됩니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션 시작&lt;/li&gt;
&lt;li&gt;입금 : 1003계좌의 잔고에서 50,000원 증가
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1003 계좌 잔고 = 50,000원&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Rollback; - &lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;(입금 작업에 문제가 있어 트랜잭션 롤백)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1003 계좌 잔고 = 0원&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;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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;pexels-ann-h-11141843.jpg&quot; data-origin-width=&quot;5227&quot; data-origin-height=&quot;3484&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OPO8S/btspsGbWLJa/EXonfOmDE5Hsck8tbsDdK0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OPO8S/btspsGbWLJa/EXonfOmDE5Hsck8tbsDdK0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OPO8S/btspsGbWLJa/EXonfOmDE5Hsck8tbsDdK0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOPO8S%2FbtspsGbWLJa%2FEXonfOmDE5Hsck8tbsDdK0%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; alt=&quot;Commit과 Rollback&quot; loading=&quot;lazy&quot; width=&quot;5227&quot; height=&quot;3484&quot; data-filename=&quot;pexels-ann-h-11141843.jpg&quot; data-origin-width=&quot;5227&quot; data-origin-height=&quot;3484&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Rollback은 언제 실행될까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Rollback은 트랜잭션 상태와 실행 결과에 따라 다양한 시점에서 실행될 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;트랜잭션 내에서의 Rollback&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;트랜잭션 실행 도중에 문제가 발생하여 중단해야 할 경우 Rollback이 발생합니다. 트랜잭션 내에서 Rollback이 실행되면, 트랜잭션 이전 상태로 되돌아가고 해당 트랜잭션에 속한 모든 변경 사항이 취소됩니다. 이후에 Commit을 하지 않고 트랜잭션을 종료하면 변경사항이 영구적으로 적용되지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;고객 A가 10,000원을 인출하는 작업을 하는 트랜잭션에서 중간에 오류가 발생하면 트랜잭션을 중단하고 &lt;br /&gt;Rollback을 실행하여 이전 상태로 돌아감&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;트랜잭션 종료 이후의 Rollback&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;트랜잭션이 정상적으로 종료되었지만, 나중에 해당 트랜잭션에 오류가 발견되었거나 잘못된 결과가 확인된 경우에 Rollback을 실행하여 이전 상태로 데이터베이스를 되돌릴 수 있습니다. 이때, Rollback은 이전에 Commit을 실행한 시점 이후의 변경 사항까지만 취소합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;고객 A가 인터넷 개인정보 수정에서 자신의 주소 변경을 완료하였으나, 나중에 해당 주소가 잘못 입력되었다는 사실을 확인하고 이전 주소로 Rollback을 실행하여 데이터를 수정함&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;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 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;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;script type=&quot;text/javascript&quot; src=&quot;//wcs.naver.net/wcslog.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
if(!wcs_add) var wcs_add = {};
wcs_add[&quot;wa&quot;] = &quot;194a7af0aa57bb0&quot;;
if(window.wcs) {
  wcs_do();
}
&lt;/script&gt;</description>
      <category>DataBase</category>
      <category>commit</category>
      <category>Database</category>
      <category>RDBMS</category>
      <category>ROLLBACK</category>
      <category>데이터베이스</category>
      <author>Michael Gary Scott</author>
      <guid isPermaLink="true">https://daniel6364.tistory.com/15</guid>
      <comments>https://daniel6364.tistory.com/entry/Commit%EA%B3%BC-Rollback#entry15comment</comments>
      <pubDate>Mon, 31 Jul 2023 16:36:52 +0900</pubDate>
    </item>
    <item>
      <title>PostgreSQL Joins</title>
      <link>https://daniel6364.tistory.com/entry/PostgreSQL-Joins</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;소개&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;조인(JOIN)은 두 개 이상의 데이블을 연결하여 필요한 데이터를 효과적으로 가져오는 데 사용되는 기능입니다. 일반적으로는 데이터베이스에는 여러 개의 테이블이 있고, 이러한 테이블들은 서로 연관되어 있습니다. 조인(JOIN)을 사용하여 이러한 테이블들을 결합하면 하나의 쿼리로 더 많은 정보를 얻을 수 있습니다.&amp;nbsp;&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;PostgreSQL 조인(JOIN)은 관련 테이블 간의 공통 칼럼값을 기반으로 하나 이상의 테이블에서 칼럼들을 결합하여 원하는 값을 가져오는 데 사용합니다.&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;일반적으로 첫 번째 테이블의 기본 키(Primary Key)와 두 번째 테이블의 외래 키(Foreign Key)를 결합하는데 사용합니다.&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;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;예제 테이블 설정&lt;/h3&gt;
&lt;pre id=&quot;code_1690767390908&quot; class=&quot;sql&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE TABLE basket_a (
    a INT PRIMARY KEY,
    fruit_a VARCHAR (100) NOT NULL
);

CREATE TABLE basket_b (
    b INT PRIMARY KEY,
    fruit_b VARCHAR (100) NOT NULL
);

INSERT INTO basket_a (a, fruit_a)
VALUES
    (1, 'Apple'),
    (2, 'Orange'),
    (3, 'Banana'),
    (4, 'Cucumber');

INSERT INTO basket_b (b, fruit_b)
VALUES
    (1, 'Orange'),
    (2, 'Apple'),
    (3, 'Watermelon'),
    (4, 'Pear');&lt;/code&gt;&lt;/pre&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;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;pexels-monstera-5384623.jpg&quot; data-origin-width=&quot;6720&quot; data-origin-height=&quot;4480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLV78N/btspsG3H2pP/3d7KII8F4jWYnznX9iL5o0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLV78N/btspsG3H2pP/3d7KII8F4jWYnznX9iL5o0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLV78N/btspsG3H2pP/3d7KII8F4jWYnznX9iL5o0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLV78N%2FbtspsG3H2pP%2F3d7KII8F4jWYnznX9iL5o0%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; alt=&quot;PostgreSQL Joins&quot; loading=&quot;lazy&quot; width=&quot;6720&quot; height=&quot;4480&quot; data-filename=&quot;pexels-monstera-5384623.jpg&quot; data-origin-width=&quot;6720&quot; data-origin-height=&quot;4480&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;PostgreSQL이 지원하는 Join 문법의 종류&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&amp;nbsp;inner join&lt;/li&gt;
&lt;li&gt;&amp;nbsp;left join&lt;/li&gt;
&lt;li&gt;&amp;nbsp;right join&lt;/li&gt;
&lt;li&gt;&amp;nbsp;full outer join&lt;/li&gt;
&lt;li&gt;&amp;nbsp;cross join&lt;/li&gt;
&lt;li&gt;&amp;nbsp;natural join&lt;/li&gt;
&lt;li&gt;&amp;nbsp;self join&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 위 1~4번에 해당되는 JOIN 문법만 알아보겠습니다.&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;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;h3 data-ke-size=&quot;size23&quot;&gt;각 Join 문법별 설명&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatRight&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;373&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bI29BT/btspmVNRbCl/LUvO0jZNA2mBZMgAX8KhUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bI29BT/btspmVNRbCl/LUvO0jZNA2mBZMgAX8KhUK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bI29BT/btspmVNRbCl/LUvO0jZNA2mBZMgAX8KhUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbI29BT%2FbtspmVNRbCl%2FLUvO0jZNA2mBZMgAX8KhUK%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; alt=&quot;PostgreSQL Joins&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;373&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;373&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. INNER JOIN&amp;nbsp;&lt;/h4&gt;
&lt;pre id=&quot;code_1690766947188&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT
    a,
    fruit_a,
    b,
    fruit_b
FROM
    basket_a
INNER JOIN basket_b
    ON fruit_a = fruit_b;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;INNER JOIN은 두 테이블 간의 일치하는 값을 가져옵니다. 조인 기준 컬럼의 값이 두 테이블에 모두 존재하는 경우에만 결과로 반환됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;431&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmqdEt/btspCl525xL/4WwrVFTc3YC27xktvFZhYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmqdEt/btspCl525xL/4WwrVFTc3YC27xktvFZhYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmqdEt/btspCl525xL/4WwrVFTc3YC27xktvFZhYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmqdEt%2FbtspCl525xL%2F4WwrVFTc3YC27xktvFZhYK%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; alt=&quot;PostgreSQL Joins&quot; loading=&quot;lazy&quot; width=&quot;431&quot; height=&quot;252&quot; data-origin-width=&quot;431&quot; data-origin-height=&quot;252&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;&amp;nbsp;&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;h4 data-ke-size=&quot;size20&quot;&gt;2. LEFT JOIN (or LEFT OUTER JOIN)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatRight&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;0002.png&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;373&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRYiYb/btspCmjg41o/9KmACrcfPzVG9DZ6B7Irhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRYiYb/btspCmjg41o/9KmACrcfPzVG9DZ6B7Irhk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRYiYb/btspCmjg41o/9KmACrcfPzVG9DZ6B7Irhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRYiYb%2FbtspCmjg41o%2F9KmACrcfPzVG9DZ6B7Irhk%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; alt=&quot;PostgreSQL Joins&quot; loading=&quot;lazy&quot; width=&quot;359&quot; height=&quot;254&quot; data-filename=&quot;0002.png&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;373&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1690770890231&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT
    a,
    fruit_a,
    b,
    fruit_b
FROM
    basket_a
LEFT JOIN basket_b 
   ON fruit_a = fruit_b;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LEFT JOIN은 왼쪽 테이블(basket_a)의 모든 레코드를 가져오고, 오른쪽 테이블(basket_b)과 조인 기준 칼럼의 값이 일치하는 경우 오른쪽 테이블의 해당 레코드를 가져옵니다. 오른쪽 테이블에 일치하는 값이 없어도 왼쪽 테이블의 모든 레코드는 결과에 포함됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;433&quot; data-origin-height=&quot;249&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Geo2p/btspsVGWY9T/PqRTBY0o06NCZh8NMnW8K0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Geo2p/btspsVGWY9T/PqRTBY0o06NCZh8NMnW8K0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Geo2p/btspsVGWY9T/PqRTBY0o06NCZh8NMnW8K0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGeo2p%2FbtspsVGWY9T%2FPqRTBY0o06NCZh8NMnW8K0%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; alt=&quot;PostgreSQL Joins&quot; loading=&quot;lazy&quot; width=&quot;433&quot; height=&quot;249&quot; data-origin-width=&quot;433&quot; data-origin-height=&quot;249&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오른쪽 테이블에 일치하는 값이 없는 왼쪽 테이블의 값만 조회하려면 WHERE 조건절을 아래와 같이 사용할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatRight&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;0003.png&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;407&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2DouN/btspBBgGEt2/1KkUj6MIXbwGwwUkPMfY90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2DouN/btspBBgGEt2/1KkUj6MIXbwGwwUkPMfY90/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2DouN/btspBBgGEt2/1KkUj6MIXbwGwwUkPMfY90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2DouN%2FbtspBBgGEt2%2F1KkUj6MIXbwGwwUkPMfY90%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;365&quot; height=&quot;281&quot; data-filename=&quot;0003.png&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;407&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1690779419785&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT
    a,
    fruit_a,
    b,
    fruit_b
FROM
    basket_a
LEFT JOIN basket_b 
    ON fruit_a = fruit_b
WHERE b IS NULL;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;433&quot; data-origin-height=&quot;249&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qicRq/btspl8URJ4w/PrF6CWwv47dtETdNIYqkD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qicRq/btspl8URJ4w/PrF6CWwv47dtETdNIYqkD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qicRq/btspl8URJ4w/PrF6CWwv47dtETdNIYqkD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqicRq%2Fbtspl8URJ4w%2FPrF6CWwv47dtETdNIYqkD1%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; alt=&quot;PostgreSQL Joins&quot; loading=&quot;lazy&quot; width=&quot;433&quot; height=&quot;249&quot; data-origin-width=&quot;433&quot; data-origin-height=&quot;249&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;&amp;nbsp;&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. RIGHT JOIN (or RIGHT OUTER JOIN)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatRight&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;0004.png&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;368&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qYZDY/btspjW1xX32/TMPOVRH55gvazDemjLqZQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qYZDY/btspjW1xX32/TMPOVRH55gvazDemjLqZQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qYZDY/btspjW1xX32/TMPOVRH55gvazDemjLqZQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqYZDY%2FbtspjW1xX32%2FTMPOVRH55gvazDemjLqZQ0%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; alt=&quot;PostgreSQL Joins&quot; loading=&quot;lazy&quot; width=&quot;332&quot; height=&quot;231&quot; data-filename=&quot;0004.png&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;368&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1690780853361&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT
    a,
    fruit_a,
    b,
    fruit_b
FROM
    basket_a
RIGHT JOIN basket_b ON fruit_a = fruit_b;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LEFT JOIN의 반대 버전이 RIGHT JOIN입니다. 오른쪽 테이블(basket_b)의 모든 레코드를 가져오고, 왼쪽 테이블(basket_a)과 조인 기준 칼럼의 값이 일치하는 경우 왼쪽 테이블의 해당 레코드를 가져옵니다. 왼쪽 테이블에 일치하는 값이 없어도 오른쪽 테이블의 모든 레코드는 결과에 포함됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;433&quot; data-origin-height=&quot;249&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buDLYs/btspFmQ5VsG/tcl9tikXvoztoWjWqGAI1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buDLYs/btspFmQ5VsG/tcl9tikXvoztoWjWqGAI1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buDLYs/btspFmQ5VsG/tcl9tikXvoztoWjWqGAI1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuDLYs%2FbtspFmQ5VsG%2Ftcl9tikXvoztoWjWqGAI1k%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;433&quot; height=&quot;249&quot; data-origin-width=&quot;433&quot; data-origin-height=&quot;249&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;왼쪽 테이블에 일치하는 값이 없는 오른쪽 테이블의 값만 조회하려면 WHERE 조건절을 아래와 같이 사용할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatRight&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;0005.png&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;407&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eheCCs/btspxqsW01G/N2KoJEmEOQKVkiBEf10SkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eheCCs/btspxqsW01G/N2KoJEmEOQKVkiBEf10SkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eheCCs/btspxqsW01G/N2KoJEmEOQKVkiBEf10SkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeheCCs%2FbtspxqsW01G%2FN2KoJEmEOQKVkiBEf10SkK%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; alt=&quot;PostgreSQL Joins&quot; loading=&quot;lazy&quot; width=&quot;363&quot; height=&quot;280&quot; data-filename=&quot;0005.png&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;407&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1690781304156&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT
    a,
    fruit_a,
    b,
    fruit_b
FROM
    basket_a
RIGHT JOIN basket_b 
   ON fruit_a = fruit_b
WHERE a IS NULL;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;433&quot; data-origin-height=&quot;249&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KK53w/btspjW1A2Oa/oYlsakkKBwOnFbz5F5t7s1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KK53w/btspjW1A2Oa/oYlsakkKBwOnFbz5F5t7s1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KK53w/btspjW1A2Oa/oYlsakkKBwOnFbz5F5t7s1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKK53w%2FbtspjW1A2Oa%2FoYlsakkKBwOnFbz5F5t7s1%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; alt=&quot;PostgreSQL Joins&quot; loading=&quot;lazy&quot; width=&quot;433&quot; height=&quot;249&quot; data-origin-width=&quot;433&quot; data-origin-height=&quot;249&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&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;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;h4 data-ke-size=&quot;size20&quot;&gt;4. FULL OUTER JOIN (or FULL JOIN)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatRight&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;0006.png&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;367&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pzTfu/btsplbKXvdR/3RkEA3ERS6meKAo7xCsm7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pzTfu/btsplbKXvdR/3RkEA3ERS6meKAo7xCsm7K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pzTfu/btsplbKXvdR/3RkEA3ERS6meKAo7xCsm7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpzTfu%2FbtsplbKXvdR%2F3RkEA3ERS6meKAo7xCsm7K%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; alt=&quot;PostgreSQL Joins&quot; loading=&quot;lazy&quot; width=&quot;366&quot; height=&quot;254&quot; data-filename=&quot;0006.png&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;367&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1690781834353&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT
    a,
    fruit_a,
    b,
    fruit_b
FROM
    basket_a
FULL OUTER JOIN basket_b 
    ON fruit_a = fruit_b;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FULL JOIN은 LEFT JOIN과 RIGHT JOIN의 결과 모두를 합한 것입니다. 두 테이블 간의 모든 레코드를 가져오고, 조인 기준 컬럼의 값이 일치하는 경우에 해당 레코드를 가져오며, 한쪽 테이블에만 일치하는 값이 있는 경우에도 해당 레코드를 가져옵니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;433&quot; data-origin-height=&quot;249&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/djKEt2/btspsUH2hxw/j6Q5P02mibs92oVedo2BUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/djKEt2/btspsUH2hxw/j6Q5P02mibs92oVedo2BUK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/djKEt2/btspsUH2hxw/j6Q5P02mibs92oVedo2BUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdjKEt2%2FbtspsUH2hxw%2Fj6Q5P02mibs92oVedo2BUK%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;433&quot; height=&quot;249&quot; data-origin-width=&quot;433&quot; data-origin-height=&quot;249&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WHERE 조건절을 이용하여 각 테이블에만 해당되는 값만을 반환할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatRight&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;0007.png&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;388&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tpIHJ/btspk8OhF4B/qSCwY7SRibzQ1eiSu8nLK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tpIHJ/btspk8OhF4B/qSCwY7SRibzQ1eiSu8nLK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tpIHJ/btspk8OhF4B/qSCwY7SRibzQ1eiSu8nLK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtpIHJ%2Fbtspk8OhF4B%2FqSCwY7SRibzQ1eiSu8nLK1%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;381&quot; height=&quot;280&quot; data-filename=&quot;0007.png&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;388&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1690782139891&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT
    a,
    fruit_a,
    b,
    fruit_b
FROM
    basket_a
FULL JOIN basket_b 
   ON fruit_a = fruit_b
WHERE a IS NULL OR b IS NULL;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;433&quot; data-origin-height=&quot;249&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Es06s/btspFMvljFj/jkodtvHSLyXclWpowBhy40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Es06s/btspFMvljFj/jkodtvHSLyXclWpowBhy40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Es06s/btspFMvljFj/jkodtvHSLyXclWpowBhy40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEs06s%2FbtspFMvljFj%2FjkodtvHSLyXclWpowBhy40%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; alt=&quot;PostgreSQL Joins&quot; loading=&quot;lazy&quot; width=&quot;433&quot; height=&quot;249&quot; data-origin-width=&quot;433&quot; data-origin-height=&quot;249&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;&amp;nbsp;&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&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-filename=&quot;0008.png&quot; data-origin-width=&quot;938&quot; data-origin-height=&quot;567&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vYSSY/btspFLiS3jh/0BujyUxlW7PaE336ohWAY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vYSSY/btspFLiS3jh/0BujyUxlW7PaE336ohWAY0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vYSSY/btspFLiS3jh/0BujyUxlW7PaE336ohWAY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvYSSY%2FbtspFLiS3jh%2F0BujyUxlW7PaE336ohWAY0%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; alt=&quot;PostgreSQL Joins&quot; loading=&quot;lazy&quot; width=&quot;938&quot; height=&quot;567&quot; data-filename=&quot;0008.png&quot; data-origin-width=&quot;938&quot; data-origin-height=&quot;567&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;&amp;nbsp;&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;출처&lt;/i&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;a href=&quot;https://www.postgresqltutorial.com/postgresql-tutorial/postgresql-joins/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.postgresqltutorial.com/postgresql-tutorial/postgresql-joins/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1690764091420&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;PostgreSQL Joins: A Visual Explanation of PostgreSQL Joins&quot; data-og-description=&quot;Summary: in this tutorial, you will learn about various kinds of PostgreSQL joins including inner join, left join, right join, and full outer join. PostgreSQL join is used to combine columns from one (self-join) or more tables based on the values of the co&quot; data-og-host=&quot;www.postgresqltutorial.com&quot; data-og-source-url=&quot;https://www.postgresqltutorial.com/postgresql-tutorial/postgresql-joins/&quot; data-og-url=&quot;https://www.postgresqltutorial.com/postgresql-tutorial/postgresql-joins/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.postgresqltutorial.com/postgresql-tutorial/postgresql-joins/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.postgresqltutorial.com/postgresql-tutorial/postgresql-joins/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&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;PostgreSQL Joins: A Visual Explanation of PostgreSQL Joins&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Summary: in this tutorial, you will learn about various kinds of PostgreSQL joins including inner join, left join, right join, and full outer join. PostgreSQL join is used to combine columns from one (self-join) or more tables based on the values of the co&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.postgresqltutorial.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;//wcs.naver.net/wcslog.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
if(!wcs_add) var wcs_add = {};
wcs_add[&quot;wa&quot;] = &quot;194a7af0aa57bb0&quot;;
if(window.wcs) {
  wcs_do();
}
&lt;/script&gt;</description>
      <category>DataBase</category>
      <category>join</category>
      <category>postgresql</category>
      <category>RDBMS</category>
      <category>tablejoin</category>
      <category>데이터베이스</category>
      <category>조인쿼리</category>
      <category>테이블조인</category>
      <author>Michael Gary Scott</author>
      <guid isPermaLink="true">https://daniel6364.tistory.com/14</guid>
      <comments>https://daniel6364.tistory.com/entry/PostgreSQL-Joins#entry14comment</comments>
      <pubDate>Mon, 31 Jul 2023 15:12:40 +0900</pubDate>
    </item>
    <item>
      <title>인터페이스 분리 원칙 - interface segregation principle, ISP</title>
      <link>https://daniel6364.tistory.com/entry/%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%EB%B6%84%EB%A6%AC-%EC%9B%90%EC%B9%99-interface-segregation-principle-ISP</link>
      <description>&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;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;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://daniel6364.tistory.com/entry/%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EB%A5%BC-%EC%9D%B4%ED%95%B4%ED%95%98%EB%8A%94-%EB%8B%A4%EC%96%91%ED%95%9C-%EB%B0%A9%EB%B2%95&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2023.06.05 - [Design Patterns] - 인터페이스를 이해하는 다양한 방법&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1690504183404&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;인터페이스를 이해하는 다양한 방법&quot; data-og-description=&quot;인터페이스의 정의 인터페이스는 속성을 포함할 수 없다. 인터페이스는 메서드를 선언할 수 있으나, 실제 코드 구현을 포함할 수 없다. 클래스가 인터페이스를 구현할 때는 인터페이스에 선언&quot; data-og-host=&quot;daniel6364.tistory.com&quot; data-og-source-url=&quot;https://daniel6364.tistory.com/entry/%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EB%A5%BC-%EC%9D%B4%ED%95%B4%ED%95%98%EB%8A%94-%EB%8B%A4%EC%96%91%ED%95%9C-%EB%B0%A9%EB%B2%95&quot; data-og-url=&quot;https://daniel6364.tistory.com/entry/%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EB%A5%BC-%EC%9D%B4%ED%95%B4%ED%95%98%EB%8A%94-%EB%8B%A4%EC%96%91%ED%95%9C-%EB%B0%A9%EB%B2%95&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/uxnAO/hyTttztaDk/kYUtc94tTvKGKBF3LPgCR0/img.jpg?width=800&amp;amp;height=531&amp;amp;face=0_0_800_531,https://scrap.kakaocdn.net/dn/bzFLwe/hyTtwpqrve/5QoSKo1ck25aazLj0Wn680/img.jpg?width=800&amp;amp;height=531&amp;amp;face=0_0_800_531,https://scrap.kakaocdn.net/dn/b2UB0g/hyTrRvcTsG/bQlUSnEjHzJmBRPm9v6KS1/img.jpg?width=5740&amp;amp;height=3827&amp;amp;face=0_0_5740_3827&quot;&gt;&lt;a href=&quot;https://daniel6364.tistory.com/entry/%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EB%A5%BC-%EC%9D%B4%ED%95%B4%ED%95%98%EB%8A%94-%EB%8B%A4%EC%96%91%ED%95%9C-%EB%B0%A9%EB%B2%95&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://daniel6364.tistory.com/entry/%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EB%A5%BC-%EC%9D%B4%ED%95%B4%ED%95%98%EB%8A%94-%EB%8B%A4%EC%96%91%ED%95%9C-%EB%B0%A9%EB%B2%95&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/uxnAO/hyTttztaDk/kYUtc94tTvKGKBF3LPgCR0/img.jpg?width=800&amp;amp;height=531&amp;amp;face=0_0_800_531,https://scrap.kakaocdn.net/dn/bzFLwe/hyTtwpqrve/5QoSKo1ck25aazLj0Wn680/img.jpg?width=800&amp;amp;height=531&amp;amp;face=0_0_800_531,https://scrap.kakaocdn.net/dn/b2UB0g/hyTrRvcTsG/bQlUSnEjHzJmBRPm9v6KS1/img.jpg?width=5740&amp;amp;height=3827&amp;amp;face=0_0_5740_3827');&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;인터페이스의 정의 인터페이스는 속성을 포함할 수 없다. 인터페이스는 메서드를 선언할 수 있으나, 실제 코드 구현을 포함할 수 없다. 클래스가 인터페이스를 구현할 때는 인터페이스에 선언&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;daniel6364.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;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;br /&gt;(클라이언트 = 인터페이스 호출자, 사용자)&lt;/li&gt;
&lt;li&gt;인터페이스 분리 원칙(ISP)은 인터페이스를 작은 단위로 분리하여 클라이언트가 필요로 하는 기능만을 제공하도록 함으로써 &lt;b&gt;결합도를 낮추고 유연한 코드를 작성&lt;/b&gt;하는데 도움을 줍니다.&lt;/li&gt;
&lt;li&gt;인터페이스 분리 원칙(ISP)에서 이야기하는 인터페이스는 크게 세 가지 중 하나릉 의미합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;API나 기능의 집합&lt;/li&gt;
&lt;li&gt;단일 API 또는 기능&lt;/li&gt;
&lt;li&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;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;pexels-cole-may-11263242.jpg&quot; data-origin-width=&quot;4405&quot; data-origin-height=&quot;2478&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OxJ1v/btspepamW4S/KS9Q9kiUr96O6WKBPGSydK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OxJ1v/btspepamW4S/KS9Q9kiUr96O6WKBPGSydK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OxJ1v/btspepamW4S/KS9Q9kiUr96O6WKBPGSydK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOxJ1v%2FbtspepamW4S%2FKS9Q9kiUr96O6WKBPGSydK%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; alt=&quot;인터페이스분리원칙&quot; loading=&quot;lazy&quot; width=&quot;4405&quot; height=&quot;2478&quot; data-filename=&quot;pexels-cole-may-11263242.jpg&quot; data-origin-width=&quot;4405&quot; data-origin-height=&quot;2478&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;인터페이스 분리 원칙(ISP)을 적용하는 방법&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 클라이언트에 특화된 인터페이스 설계하기&lt;/h4&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;p data-ke-size=&quot;size16&quot;&gt;[예시]&lt;/p&gt;
&lt;pre id=&quot;code_1690505140221&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 이동 수단을 위한 기본 인터페이스
interface Movable {
    void move();
}

// 자동차를 위한 인터페이스
interface Car extends Movable {
    void honk();
}

// 비행기를 위한 인터페이스
interface Airplane extends Movable {
    void fly();
}

// 자동차 구현 클래스
class Sedan implements Car {
    @Override
    public void move() {
        System.out.println(&quot;Sedan is moving on the road.&quot;);
    }

    @Override
    public void honk() {
        System.out.println(&quot;Sedan is honking.&quot;);
    }
}

// 비행기 구현 클래스
class Boeing747 implements Airplane {
    @Override
    public void move() {
        System.out.println(&quot;Boeing 747 is moving on the runway.&quot;);
    }

    @Override
    public void fly() {
        System.out.println(&quot;Boeing 747 is flying in the sky.&quot;);
    }
}

// 클라이언트 코드
public class Client {
    public static void main(String[] args) {
        Car sedanCar = new Sedan();
        Airplane boeing747Airplane = new Boeing747();

        // 자동차 기능 사용
        sedanCar.move();
        sedanCar.honk();

        // 비행기 기능 사용
        boeing747Airplane.move();
        boeing747Airplane.fly();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시를 살펴보면 인터페이스를 적절하게 분리하여 클라이언트에 특화된 기능을 제공하고 있습니다. Car 인터페이스는 자동차와 관련된 기능을 가지고 있고, Airplane 인터페이스는 비행기와 관련된 기능을 제공합니다. 모두 Movable 인터페이스를 상속받아 이동 기능을 공통으로 가지고 있습니다.&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;클라이언트 코드인 Client 클래스에서는 Sedan과 Boeing747 객체를 생성하여 각가의 인터페이스를 통해 클라이언트에 특화된 기능을 사용할 수 있습니다.&amp;nbsp;&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;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;h4 data-ke-size=&quot;size20&quot;&gt;2. 다중 구현 고려하기&lt;/h4&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;p data-ke-size=&quot;size16&quot;&gt;[예시]&lt;/p&gt;
&lt;pre id=&quot;code_1690506252324&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 이동 수단을 위한 인터페이스
interface Movable {
    void move();
}

// 차량을 위한 인터페이스
interface Vehicle extends Movable {
    void honk();
}

// 비행기를 위한 인터페이스
interface Airplane extends Movable {
    void fly();
}

// 배를 위한 인터페이스
interface Ship extends Movable {
    void sail();
}

// 자동차 구현 클래스
class Car implements Vehicle {
    @Override
    public void move() {
        System.out.println(&quot;Car is moving on the road.&quot;);
    }

    @Override
    public void honk() {
        System.out.println(&quot;Car is honking.&quot;);
    }
}

// 비행기 구현 클래스
class Airplane implements Airplane {
    @Override
    public void move() {
        System.out.println(&quot;Airplane is moving on the runway.&quot;);
    }

    @Override
    public void fly() {
        System.out.println(&quot;Airplane is flying in the sky.&quot;);
    }
}

// 배 구현 클래스
class CargoShip implements Ship {
    @Override
    public void move() {
        System.out.println(&quot;Cargo ship is moving on the sea.&quot;);
    }

    @Override
    public void sail() {
        System.out.println(&quot;Cargo ship is sailing on the sea.&quot;);
    }
}

// 클라이언트 코드
public class Client {
    public static void main(String[] args) {
        Vehicle car = new Car();
        Airplane airplane = new Airplane();
        Ship cargoShip = new CargoShip();

        // 다양한 이동 수단 사용
        car.move();
        car.honk();

        airplane.move();
        airplane.fly();

        cargoShip.move();
        cargoShip.sail();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 예시에서 Vehicle, Airplane, Ship 인터페이스는 각각 다른 이동 수단들을 위한 인터페이스입니다. Car, Airplane, CargoShip 클래스들은 각각 Vehicle, Airplane, Ship 인터페이스를 구현하며, 해당 인터페이스에서 제공하는 기능들을 구현합니다.&amp;nbsp;&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;Client 클래스에서는 각각의 수단을 생성, 해당 인터페이스를 통해 다양한 이동 기능을 사용할 수 있습니다. 이렇게 다중 구현 가능성을 고려하여 인터페이스를 설계함으로써, 각각의 클래스들이 같은 인터페이스를 사용할 수 있고, 자신에게 필요한 기능만을 구현할 수 있습니다. 이는 유연하고 확장 가능한 시스템을 구축하는데 도움이 됩니다.&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;h4 data-ke-size=&quot;size20&quot;&gt;3. 인터페이스 간 의존성 최소화하기&lt;/h4&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 data-ke-size=&quot;size16&quot;&gt;[예시]&lt;/p&gt;
&lt;pre id=&quot;code_1690506816624&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 이동 수단을 위한 기본 인터페이스
interface Movable {
    void move();
}

// 자동차를 위한 인터페이스
interface Car {
    void honk();
}

// 비행기를 위한 인터페이스
interface Airplane {
    void fly();
}

// 자동차 구현 클래스
class Sedan implements Movable, Car {
    @Override
    public void move() {
        System.out.println(&quot;Sedan is moving on the road.&quot;);
    }

    @Override
    public void honk() {
        System.out.println(&quot;Sedan is honking.&quot;);
    }
}

// 비행기 구현 클래스
class Boeing747 implements Movable, Airplane {
    @Override
    public void move() {
        System.out.println(&quot;Boeing 747 is moving on the runway.&quot;);
    }

    @Override
    public void fly() {
        System.out.println(&quot;Boeing 747 is flying in the sky.&quot;);
    }
}

// 클라이언트 코드
public class Client {
    public static void main(String[] args) {
        Movable sedanCar = new Sedan();
        Movable boeing747Airplane = new Boeing747();

        // 자동차 기능 사용
        sedanCar.move();
        Car sedanAsCar = (Car) sedanCar; // Movable을 Car로 다운캐스팅
        sedanAsCar.honk();

        // 비행기 기능 사용
        boeing747Airplane.move();
        Airplane boeing747AsAirplane = (Airplane) boeing747Airplane; // Movable을 Airplane으로 다운캐스팅
        boeing747AsAirplane.fly();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 예시처럼 Movable 인터페이스는 Car, Airplane 인터페이스와 의존성이 없도록 설계되었습니다. 각 인터페이스는 독립적으로 사용될 수 있고, 구현 클래스들은 필요한 인터페이스를 모두 구현합니다.&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;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;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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;pexels-kindel-media-7715090.jpg&quot; data-origin-width=&quot;4920&quot; data-origin-height=&quot;3690&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FQmxH/btso9f7yxFR/ja66bUP1tKf80O6QzSmjmK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FQmxH/btso9f7yxFR/ja66bUP1tKf80O6QzSmjmK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FQmxH/btso9f7yxFR/ja66bUP1tKf80O6QzSmjmK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFQmxH%2Fbtso9f7yxFR%2Fja66bUP1tKf80O6QzSmjmK%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; alt=&quot;인터페이스분리원칙&quot; loading=&quot;lazy&quot; width=&quot;4920&quot; height=&quot;3690&quot; data-filename=&quot;pexels-kindel-media-7715090.jpg&quot; data-origin-width=&quot;4920&quot; data-origin-height=&quot;3690&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;인터페이스 분리 원칙(ISP) 위반 예시&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 대표적인 예시 중 하나는 Square-Rectangle Problem입니다. 이는 정사각혀(Square)과 직사각형(Rectangle) 사이의 상속 관계에서 발생합니다.&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;보통 정사각형은 직사각형의 특별한 형태로 간주하여 Square 클래스가 Rectangle 클래스를 상속받도록 설계하는 경우를 말합니다.&amp;nbsp;&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;하지만 이러한 설계는 리스코프 치환 원칙(LSP)을 위반하게 됩니다.&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;a href=&quot;https://daniel6364.tistory.com/entry/%EB%A6%AC%EC%8A%A4%EC%BD%94%ED%94%84-%EC%B9%98%ED%99%98-%EC%9B%90%EC%B9%99-Liskov-Substitution-Principle-LSP&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2023.07.27 - [Design Patterns] - 리스코프 치환 원칙 - Liskov Substitution Principle, LSP&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1690507223073&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;리스코프 치환 원칙 - Liskov Substitution Principle, LSP&quot; data-og-description=&quot;소개 리스코프 치환 원칙은 매우 느슨한 설계 원칙이기 때문에 정상적인 상황에서 우리가 작성하는 코드는 이 설계 원칙을 위반하지 않습니다. 리스코프 치환 원칙(Liskov Substitution Principle, LSP)은&quot; data-og-host=&quot;daniel6364.tistory.com&quot; data-og-source-url=&quot;https://daniel6364.tistory.com/entry/%EB%A6%AC%EC%8A%A4%EC%BD%94%ED%94%84-%EC%B9%98%ED%99%98-%EC%9B%90%EC%B9%99-Liskov-Substitution-Principle-LSP&quot; data-og-url=&quot;https://daniel6364.tistory.com/entry/%EB%A6%AC%EC%8A%A4%EC%BD%94%ED%94%84-%EC%B9%98%ED%99%98-%EC%9B%90%EC%B9%99-Liskov-Substitution-Principle-LSP&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bkA4B9/hyTtrn8JZv/0x9MOxCk0UQcqP8fUgzhYK/img.jpg?width=800&amp;amp;height=541&amp;amp;face=0_0_800_541,https://scrap.kakaocdn.net/dn/b8EiZr/hyTrU6yVAx/9Vpl4kjGHdLmSVA7lYJsE0/img.jpg?width=800&amp;amp;height=541&amp;amp;face=0_0_800_541,https://scrap.kakaocdn.net/dn/nnRTh/hyTrIyg6yk/o22yrO2OH2sKqHKXxSm2Ek/img.jpg?width=6000&amp;amp;height=4000&amp;amp;face=0_0_6000_4000&quot;&gt;&lt;a href=&quot;https://daniel6364.tistory.com/entry/%EB%A6%AC%EC%8A%A4%EC%BD%94%ED%94%84-%EC%B9%98%ED%99%98-%EC%9B%90%EC%B9%99-Liskov-Substitution-Principle-LSP&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://daniel6364.tistory.com/entry/%EB%A6%AC%EC%8A%A4%EC%BD%94%ED%94%84-%EC%B9%98%ED%99%98-%EC%9B%90%EC%B9%99-Liskov-Substitution-Principle-LSP&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bkA4B9/hyTtrn8JZv/0x9MOxCk0UQcqP8fUgzhYK/img.jpg?width=800&amp;amp;height=541&amp;amp;face=0_0_800_541,https://scrap.kakaocdn.net/dn/b8EiZr/hyTrU6yVAx/9Vpl4kjGHdLmSVA7lYJsE0/img.jpg?width=800&amp;amp;height=541&amp;amp;face=0_0_800_541,https://scrap.kakaocdn.net/dn/nnRTh/hyTrIyg6yk/o22yrO2OH2sKqHKXxSm2Ek/img.jpg?width=6000&amp;amp;height=4000&amp;amp;face=0_0_6000_4000');&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;리스코프 치환 원칙 - Liskov Substitution Principle, LSP&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;소개 리스코프 치환 원칙은 매우 느슨한 설계 원칙이기 때문에 정상적인 상황에서 우리가 작성하는 코드는 이 설계 원칙을 위반하지 않습니다. 리스코프 치환 원칙(Liskov Substitution Principle, LSP)은&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;daniel6364.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;pre id=&quot;code_1690507453299&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 이동 수단을 위한 인터페이스 (ISP 위반)
interface Movable {
    void move();
    void fly(); // 자동차에 필요 없는 기능이 포함되어 있음
}

// 자동차 클래스
class Car implements Movable {
    @Override
    public void move() {
        System.out.println(&quot;Car is moving on the road.&quot;);
    }

    @Override
    public void fly() {
        // 자동차에는 비행 기능이 필요 없으므로 빈 메서드로 구현
    }
}

// 비행기 클래스
class Airplane implements Movable {
    @Override
    public void move() {
        System.out.println(&quot;Airplane is moving on the runway.&quot;);
    }

    @Override
    public void fly() {
        System.out.println(&quot;Airplane is flying in the sky.&quot;);
    }
}

// 클라이언트 코드
public class Client {
    public static void main(String[] args) {
        Movable car = new Car();
        Movable airplane = new Airplane();

        // 자동차와 비행기 모두 이동과 비행 기능을 사용하려고 함
        car.move();
        car.fly(); // 실제로 비행하지 않는데도 불필요한 메서드를 호출하고 있음

        airplane.move();
        airplane.fly();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 예시에서 Movable 인터페이스는 move() 메서드와 fly() 메서드를 함께 포함하고 있습니다. 하지만 Client 클래스에서 자동차 생성 후에 불필요한 메서드인 fly() 메서드를 빈 메서드로 구현하고 있습니다.&amp;nbsp;&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;이러한 상황에서는 자동차와 비행기를 각각 별도의 인터페이스로 분리하여 인터페이스 분리 원칙(ISP)을 준수하는 것이 바랍직합니다.&amp;nbsp;&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;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;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;pexels-ann-h-6980525.jpg&quot; data-origin-width=&quot;6000&quot; data-origin-height=&quot;4000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xx4mN/btspflr0dNN/HNkLKdBvVCgpsKxkYYCKs1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xx4mN/btspflr0dNN/HNkLKdBvVCgpsKxkYYCKs1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xx4mN/btspflr0dNN/HNkLKdBvVCgpsKxkYYCKs1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fxx4mN%2Fbtspflr0dNN%2FHNkLKdBvVCgpsKxkYYCKs1%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; alt=&quot;인터페이스분리원칙&quot; loading=&quot;lazy&quot; width=&quot;6000&quot; height=&quot;4000&quot; data-filename=&quot;pexels-ann-h-6980525.jpg&quot; data-origin-width=&quot;6000&quot; data-origin-height=&quot;4000&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;인터페이스 분리 원칙(ISP)은 클라이언트가 필요로 하는 기능만을 포함하도록 작은 인터페이스를 설계함으로써 불필요한 의존성을 제거하고 유연하고 재사용 가능한 코드를 작성하는데 도움을 줍니다.&lt;/li&gt;
&lt;li&gt;인터페이스 분리 원칙(ISP)을 지키면 유지보수성이 높은 프로그래밍을 할 수 있으며, 더 나아가 SOLID 원칙 전체를 따르는 객체지향 프로그래밍의 원칙적인 설계를 구현할 수 있습니다.&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;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;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;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://daniel6364.tistory.com/entry/%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99-single-responsibility-principle-SRP&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2023.07.27 - [Design Patterns] - 단일 책임 원칙 - single responsibility principle, SRP&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1690509514158&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;단일 책임 원칙 - single responsibility principle, SRP&quot; data-og-description=&quot;소개 객체지향 프로그래밍은 유지보수성과 재사용성으르 높이기 위해 다양한 설계 원칙을 제공합니다. 이 중에서도 '단일 책임 원칙'은 클래스나 모듈이 하나의 책임만을 가져야 한다는 원칙으&quot; data-og-host=&quot;daniel6364.tistory.com&quot; data-og-source-url=&quot;https://daniel6364.tistory.com/entry/%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99-single-responsibility-principle-SRP&quot; data-og-url=&quot;https://daniel6364.tistory.com/entry/%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99-single-responsibility-principle-SRP&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bRFm8S/hyTrOkYDhg/Mr404OYYFxrHhBcXAX9tc0/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/3XM7U/hyTrTGBgZH/AFiYlo624cCJbeT1YEGpAK/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450&quot;&gt;&lt;a href=&quot;https://daniel6364.tistory.com/entry/%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99-single-responsibility-principle-SRP&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://daniel6364.tistory.com/entry/%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99-single-responsibility-principle-SRP&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bRFm8S/hyTrOkYDhg/Mr404OYYFxrHhBcXAX9tc0/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/3XM7U/hyTrTGBgZH/AFiYlo624cCJbeT1YEGpAK/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_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;단일 책임 원칙 - single responsibility principle, SRP&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;소개 객체지향 프로그래밍은 유지보수성과 재사용성으르 높이기 위해 다양한 설계 원칙을 제공합니다. 이 중에서도 '단일 책임 원칙'은 클래스나 모듈이 하나의 책임만을 가져야 한다는 원칙으&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;daniel6364.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;a href=&quot;https://daniel6364.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EA%B0%9C%EB%B0%A9-%ED%8F%90%EC%87%84-%EC%9B%90%EC%B9%99&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2023.06.08 - [Design Patterns] - 디자인 패턴 - 개방 폐쇄 원칙&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1690509529214&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;디자인 패턴 - 개방 폐쇄 원칙&quot; data-og-description=&quot;확장할 때는 개방, 수정할 때는 폐쇄 개방 폐쇄 원칙은 코드의 확장성 문제로 볼 수 있다. 추후 변경되는 요구 사항에 대응할 때 코드가 확장할 때는 개방, 수정할 때는 폐쇄될 수 있다면 해당 코&quot; data-og-host=&quot;daniel6364.tistory.com&quot; data-og-source-url=&quot;https://daniel6364.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EA%B0%9C%EB%B0%A9-%ED%8F%90%EC%87%84-%EC%9B%90%EC%B9%99&quot; data-og-url=&quot;https://daniel6364.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EA%B0%9C%EB%B0%A9-%ED%8F%90%EC%87%84-%EC%9B%90%EC%B9%99&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/kbtO3/hyTtmf5iPS/oyvmyv1v84b9yrj5NfggIk/img.jpg?width=800&amp;amp;height=534&amp;amp;face=0_0_800_534,https://scrap.kakaocdn.net/dn/crsVCT/hyTtodTJoN/5lO2hfa8C2Ieq4nKwrObD1/img.jpg?width=800&amp;amp;height=534&amp;amp;face=0_0_800_534,https://scrap.kakaocdn.net/dn/Grja9/hyTtn67Zrr/D4y2TD3hYEkFObkAkFU1k1/img.jpg?width=5184&amp;amp;height=3456&amp;amp;face=0_0_5184_3456&quot;&gt;&lt;a href=&quot;https://daniel6364.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EA%B0%9C%EB%B0%A9-%ED%8F%90%EC%87%84-%EC%9B%90%EC%B9%99&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://daniel6364.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EA%B0%9C%EB%B0%A9-%ED%8F%90%EC%87%84-%EC%9B%90%EC%B9%99&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/kbtO3/hyTtmf5iPS/oyvmyv1v84b9yrj5NfggIk/img.jpg?width=800&amp;amp;height=534&amp;amp;face=0_0_800_534,https://scrap.kakaocdn.net/dn/crsVCT/hyTtodTJoN/5lO2hfa8C2Ieq4nKwrObD1/img.jpg?width=800&amp;amp;height=534&amp;amp;face=0_0_800_534,https://scrap.kakaocdn.net/dn/Grja9/hyTtn67Zrr/D4y2TD3hYEkFObkAkFU1k1/img.jpg?width=5184&amp;amp;height=3456&amp;amp;face=0_0_5184_3456');&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;확장할 때는 개방, 수정할 때는 폐쇄 개방 폐쇄 원칙은 코드의 확장성 문제로 볼 수 있다. 추후 변경되는 요구 사항에 대응할 때 코드가 확장할 때는 개방, 수정할 때는 폐쇄될 수 있다면 해당 코&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;daniel6364.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;참고 서적 : 디자인패턴의 아름다움&lt;/span&gt;&lt;/p&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;//wcs.naver.net/wcslog.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
if(!wcs_add) var wcs_add = {};
wcs_add[&quot;wa&quot;] = &quot;194a7af0aa57bb0&quot;;
if(window.wcs) {
  wcs_do();
}
&lt;/script&gt;</description>
      <category>Design Patterns</category>
      <category>Interface</category>
      <category>ISP</category>
      <category>SOLID원칙</category>
      <category>디자인패턴</category>
      <category>설계원칙</category>
      <category>인터페이스분리원칙</category>
      <author>Michael Gary Scott</author>
      <guid isPermaLink="true">https://daniel6364.tistory.com/13</guid>
      <comments>https://daniel6364.tistory.com/entry/%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%EB%B6%84%EB%A6%AC-%EC%9B%90%EC%B9%99-interface-segregation-principle-ISP#entry13comment</comments>
      <pubDate>Fri, 28 Jul 2023 10:59:05 +0900</pubDate>
    </item>
    <item>
      <title>리스코프 치환 원칙 - Liskov Substitution Principle, LSP</title>
      <link>https://daniel6364.tistory.com/entry/%EB%A6%AC%EC%8A%A4%EC%BD%94%ED%94%84-%EC%B9%98%ED%99%98-%EC%9B%90%EC%B9%99-Liskov-Substitution-Principle-LSP</link>
      <description>&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;b&gt;매우 느슨한 설계 원칙&lt;/b&gt;이기 때문에 정상적인 상황에서 우리가 작성하는 코드는 이 설계 원칙을 위반하지 않습니다.&lt;/li&gt;
&lt;li&gt;리스코프 치환 원칙(Liskov Substitution Principle, LSP)은 상속 관계에 있는 클래스들 사이의 &lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;안정성&lt;/b&gt;&lt;/span&gt;과 &lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;유연성&lt;/b&gt;&lt;/span&gt;을 보장하는 핵심적인 원칙입니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&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;pexels-neosiam-590750.jpg&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;2030&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/I4wRg/btso6j3eUx3/f9UkbiaoeMXo3JyODvvClk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/I4wRg/btso6j3eUx3/f9UkbiaoeMXo3JyODvvClk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/I4wRg/btso6j3eUx3/f9UkbiaoeMXo3JyODvvClk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FI4wRg%2Fbtso6j3eUx3%2Ff9UkbiaoeMXo3JyODvvClk%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; alt=&quot;리스코프치환원칙&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;2030&quot; data-filename=&quot;pexels-neosiam-590750.jpg&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;2030&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;&amp;nbsp;&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;리스코프 치환 원칙이란?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;파생 클래스는 기초 클래스의 인스턴스를 대체하여도 프로그램의 정확성을 보장해야 한다&quot;라는 원칙입니다.
&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;/li&gt;
&lt;li&gt;다른 설명으로는 &quot;만약 S가 T의 하위 유형인 경우, T 유형의 객체는 프로그램을 중단하지 않고도 S 유형의 객체로 대체될 수 있다&quot;라고 설명합니다.
&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;/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;/ul&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;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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;pexels-rodolpho-zanardo-1259327.jpg&quot; data-origin-width=&quot;5184&quot; data-origin-height=&quot;3456&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZZEx3/btspcu3L3G9/S0YXvHwGjQeGUcgQ4Rm3m1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZZEx3/btspcu3L3G9/S0YXvHwGjQeGUcgQ4Rm3m1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZZEx3/btspcu3L3G9/S0YXvHwGjQeGUcgQ4Rm3m1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZZEx3%2Fbtspcu3L3G9%2FS0YXvHwGjQeGUcgQ4Rm3m1%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; alt=&quot;리스코프치환원칙&quot; loading=&quot;lazy&quot; width=&quot;5184&quot; height=&quot;3456&quot; data-filename=&quot;pexels-rodolpho-zanardo-1259327.jpg&quot; data-origin-width=&quot;5184&quot; data-origin-height=&quot;3456&quot;/&gt;&lt;/span&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;&amp;nbsp;상속 관계에 있는 파생 클래스는 기초 클래스의 모든 특징을 포함해야 합니다. 이로 인해 기초 클래스의 인스턴스를 파생 클래스의 인스턴스로 대체할 때에도 기존 코드가 정상적으로 동작해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 기초 클래스의 규약을 따름&lt;/h4&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;p data-ke-size=&quot;size16&quot;&gt;[리스코프 치환 원칙(LSP)을 준수 예시]&lt;/p&gt;
&lt;pre id=&quot;code_1690435247151&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Rectangle {
    protected int width;
    protected int height;

    public Rectangle(int width, int height) {
        this.width = width;
        this.height = height;
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getArea() {
        return width * height;
    }
}

class Square extends Rectangle {
    public Square(int sideLength) {
        super(sideLength, sideLength);
    }

    // 사각형과 정사각형을 같은 인터페이스로 다룰 수 있도록 오버라이드
    @Override
    public void setWidth(int width) {
        super.setWidth(width);
        super.setHeight(width);
    }

    @Override
    public void setHeight(int height) {
        super.setWidth(height);
        super.setHeight(height);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;위 예시에서 Square 클래스는 Rectangle 클래스를 상속받아 정사각형을 구현하고 있습니다. 이렇게 상속 관계에서 기초 클래스의 규약을 준수하면서도 새로운 기능을 확장함으로써 &lt;b&gt;리스코프 치환 원칙(LSP)&lt;/b&gt;을 준수합니다. 따라서 사각형과 정사각형을 같은 인터페이스로 다룰 수 있으며, 코드의 &lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;유지보수성&lt;/b&gt;&lt;/span&gt;과 &lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;확장성&lt;/b&gt;&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;&amp;nbsp;하지만, 위에서 보여준 예시는 사실상 객체지향의 특성인 다형성을 이용한 것으로 보일수도 있다. 만일 그렇다면 다형성과 리스코프 치환 원칙은 같은 것이라고 봐도 무방한 것일까? 리스코프 치환 원칙의 정의를 기준으로 살펴보면, 리스코프 치환 원칙과 다형성은 보기에는 비슷하지만, 실제로는 완전히 다른 의미를 말한다.&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;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;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;pexels-ann-h-3482441.jpg&quot; data-origin-width=&quot;6000&quot; data-origin-height=&quot;4000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bs9jet/btso6SLfnln/JohEMO8HwvbhOVnkAy2xK0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bs9jet/btso6SLfnln/JohEMO8HwvbhOVnkAy2xK0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bs9jet/btso6SLfnln/JohEMO8HwvbhOVnkAy2xK0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbs9jet%2Fbtso6SLfnln%2FJohEMO8HwvbhOVnkAy2xK0%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; alt=&quot;리스코프치환원칙&quot; loading=&quot;lazy&quot; width=&quot;6000&quot; height=&quot;4000&quot; data-filename=&quot;pexels-ann-h-3482441.jpg&quot; data-origin-width=&quot;6000&quot; data-origin-height=&quot;4000&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;다형성(Polymorphism)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;같은 메서드를 사용하여 다양한 객체 타입에 대해 동작할 수 있는 능력을 나타냅니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;주로 &lt;b&gt;오버라이딩&lt;/b&gt;(Overriding)과 &lt;b&gt;오버로딩&lt;/b&gt;(Overloading)을 통해 구현됩니다.&lt;/li&gt;
&lt;li&gt;다형성을 통해 코드의 &lt;b&gt;재사용성&lt;/b&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;다형성(Polymorphism)과 리스코프 치환 원칙(Liskov Substitution Principle, LSP)의 차이점&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 다형성(Polymorphism)&lt;/h4&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;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 리스코프 치환 원칙(Liskov Substitution Principle, LSP)&lt;/h4&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;리스코프 치환 원칙(LSP)은 상속 관계에서 &lt;b&gt;안정성&lt;/b&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;따라서 다형성은 메서드 호출 시점에서 객체의 타입에 따라 동작을 결정하는 개념이며, 리스코프 치환 원칙은 상속 관계에서 파생 클래스가 기초 클래스의 대체 가능한 특성을 가져야 한다는 원칙입니다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[리스코프 치환 원칙(LSP) 위반 예시]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 아래 예시는 새와 펭귄은 모두 비행할 수 있지만 펭귄은 수영도 할 수 있습니다. 이때, 새와 펭귄을 상속 관계로 표현하면 다음과 같은 수 있음을 보여줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1690439764460&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Bird {
    public void fly() {
        // 새의 비행 기능
    }
}

class Penguin extends Bird {
    @Override
    public void fly() {
        // 펭귄은 비행할 수 없으므로 비행 기능을 재정의
        throw new UnsupportedOperationException(&quot;펭귄은 비행할 수 없습니다.&quot;);
    }

    public void swim() {
        // 펭귄의 수영 기능
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;하지만, 위의 예시에서 Penguin 클래스는 Bird 클래스를 상속받았지만, fly() 메서드를 재정의하여 퓅귄은 비행할 수 없다는 예외를 발생시킵니다. 이렇게 상속 관계에서 기초 클래스(Bird)의 규약을 위반하는 경우, 리스코프 치환 원칙(LSP)을 위반하게 됩니다. 이를 준수하기 위해서는 상속 관계에서 기초 클래스의 규약을 준수하면서도 새로운 기능을 확장하는 설계가 필요합니다.&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;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;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://daniel6364.tistory.com/entry/%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99-single-responsibility-principle-SRP&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2023.07.27 - [Design Patterns] - 단일 책임 원칙 - single responsibility principle, SRP&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1690440777043&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;단일 책임 원칙 - single responsibility principle, SRP&quot; data-og-description=&quot;소개 객체지향 프로그래밍은 유지보수성과 재사용성으르 높이기 위해 다양한 설계 원칙을 제공합니다. 이 중에서도 '단일 책임 원칙'은 클래스나 모듈이 하나의 책임만을 가져야 한다는 원칙으&quot; data-og-host=&quot;daniel6364.tistory.com&quot; data-og-source-url=&quot;https://daniel6364.tistory.com/entry/%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99-single-responsibility-principle-SRP&quot; data-og-url=&quot;https://daniel6364.tistory.com/entry/%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99-single-responsibility-principle-SRP&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bgn8qJ/hyTqxYsxDJ/UE6StWzmZZnSNfqvmO8sOK/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/DR6hh/hyTrXOLJHf/pYhs4zBg3Qng64NmYEzxF0/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450&quot;&gt;&lt;a href=&quot;https://daniel6364.tistory.com/entry/%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99-single-responsibility-principle-SRP&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://daniel6364.tistory.com/entry/%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99-single-responsibility-principle-SRP&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bgn8qJ/hyTqxYsxDJ/UE6StWzmZZnSNfqvmO8sOK/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/DR6hh/hyTrXOLJHf/pYhs4zBg3Qng64NmYEzxF0/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_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;단일 책임 원칙 - single responsibility principle, SRP&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;소개 객체지향 프로그래밍은 유지보수성과 재사용성으르 높이기 위해 다양한 설계 원칙을 제공합니다. 이 중에서도 '단일 책임 원칙'은 클래스나 모듈이 하나의 책임만을 가져야 한다는 원칙으&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;daniel6364.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://daniel6364.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EA%B0%9C%EB%B0%A9-%ED%8F%90%EC%87%84-%EC%9B%90%EC%B9%99&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2023.06.08 - [Design Patterns] - 디자인 패턴 - 개방 폐쇄 원칙&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1690440787715&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;디자인 패턴 - 개방 폐쇄 원칙&quot; data-og-description=&quot;확장할 때는 개방, 수정할 때는 폐쇄 개방 폐쇄 원칙은 코드의 확장성 문제로 볼 수 있다. 추후 변경되는 요구 사항에 대응할 때 코드가 확장할 때는 개방, 수정할 때는 폐쇄될 수 있다면 해당 코&quot; data-og-host=&quot;daniel6364.tistory.com&quot; data-og-source-url=&quot;https://daniel6364.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EA%B0%9C%EB%B0%A9-%ED%8F%90%EC%87%84-%EC%9B%90%EC%B9%99&quot; data-og-url=&quot;https://daniel6364.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EA%B0%9C%EB%B0%A9-%ED%8F%90%EC%87%84-%EC%9B%90%EC%B9%99&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bqXloF/hyTqoNZHA6/hCzzskAXJEsp3oEfiaIc8K/img.jpg?width=800&amp;amp;height=534&amp;amp;face=0_0_800_534,https://scrap.kakaocdn.net/dn/QY3Zu/hyTrTr4kX7/P3TLqblMzxQtyPNjB6Vnkk/img.jpg?width=800&amp;amp;height=534&amp;amp;face=0_0_800_534&quot;&gt;&lt;a href=&quot;https://daniel6364.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EA%B0%9C%EB%B0%A9-%ED%8F%90%EC%87%84-%EC%9B%90%EC%B9%99&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://daniel6364.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EA%B0%9C%EB%B0%A9-%ED%8F%90%EC%87%84-%EC%9B%90%EC%B9%99&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bqXloF/hyTqoNZHA6/hCzzskAXJEsp3oEfiaIc8K/img.jpg?width=800&amp;amp;height=534&amp;amp;face=0_0_800_534,https://scrap.kakaocdn.net/dn/QY3Zu/hyTrTr4kX7/P3TLqblMzxQtyPNjB6Vnkk/img.jpg?width=800&amp;amp;height=534&amp;amp;face=0_0_800_534');&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;확장할 때는 개방, 수정할 때는 폐쇄 개방 폐쇄 원칙은 코드의 확장성 문제로 볼 수 있다. 추후 변경되는 요구 사항에 대응할 때 코드가 확장할 때는 개방, 수정할 때는 폐쇄될 수 있다면 해당 코&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;daniel6364.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 서적 : 디자인패턴의 아름다움&lt;/p&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;//wcs.naver.net/wcslog.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
if(!wcs_add) var wcs_add = {};
wcs_add[&quot;wa&quot;] = &quot;194a7af0aa57bb0&quot;;
if(window.wcs) {
  wcs_do();
}
&lt;/script&gt;</description>
      <category>Design Patterns</category>
      <category>liskov</category>
      <category>lsp</category>
      <category>SOLID원칙</category>
      <category>디자인패턴</category>
      <category>리스코프</category>
      <category>리스코프치환원칙</category>
      <category>설계원칙</category>
      <author>Michael Gary Scott</author>
      <guid isPermaLink="true">https://daniel6364.tistory.com/12</guid>
      <comments>https://daniel6364.tistory.com/entry/%EB%A6%AC%EC%8A%A4%EC%BD%94%ED%94%84-%EC%B9%98%ED%99%98-%EC%9B%90%EC%B9%99-Liskov-Substitution-Principle-LSP#entry12comment</comments>
      <pubDate>Thu, 27 Jul 2023 15:57:05 +0900</pubDate>
    </item>
    <item>
      <title>단일 책임 원칙 - single responsibility principle, SRP</title>
      <link>https://daniel6364.tistory.com/entry/%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99-single-responsibility-principle-SRP</link>
      <description>&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;pexels-alex-agrico-17289863.jpg&quot; data-origin-width=&quot;4896&quot; data-origin-height=&quot;2760&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Qsqgd/btso6qU3Ihk/CwKLg9hB0xTcgJKW4eUyaK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Qsqgd/btso6qU3Ihk/CwKLg9hB0xTcgJKW4eUyaK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Qsqgd/btso6qU3Ihk/CwKLg9hB0xTcgJKW4eUyaK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQsqgd%2Fbtso6qU3Ihk%2FCwKLg9hB0xTcgJKW4eUyaK%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; alt=&quot;단일책임원칙&quot; loading=&quot;lazy&quot; width=&quot;4896&quot; height=&quot;2760&quot; data-filename=&quot;pexels-alex-agrico-17289863.jpg&quot; data-origin-width=&quot;4896&quot; data-origin-height=&quot;2760&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;정의 : 한 클래스는 하나의 책임을 가져야 한다.&lt;/li&gt;
&lt;li&gt;거대하고 포괄적인 클래스를 설계하는 대신, 작은 단위와 단일 기능을 가진 클래스를 설계해야 합니다.&amp;nbsp;&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;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;pexels-lukas-684385.jpg&quot; data-origin-width=&quot;4928&quot; data-origin-height=&quot;3264&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbQBwR/btso12neqnf/Ri0mSVsVcqVyOWaZlw1wwk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbQBwR/btso12neqnf/Ri0mSVsVcqVyOWaZlw1wwk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbQBwR/btso12neqnf/Ri0mSVsVcqVyOWaZlw1wwk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbQBwR%2Fbtso12neqnf%2FRi0mSVsVcqVyOWaZlw1wwk%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; alt=&quot;단일책임원칙&quot; loading=&quot;lazy&quot; width=&quot;4928&quot; height=&quot;3264&quot; data-filename=&quot;pexels-lukas-684385.jpg&quot; data-origin-width=&quot;4928&quot; data-origin-height=&quot;3264&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;유지보수성과 가독성이 크게 향상됩니다. 클래스가 단일 책임만을 가지기 때문에 해당 책임과 관련된 코드만 수정하면 되기 때문입니다.&lt;/li&gt;
&lt;li&gt;이로 인해 코드의 변경이 다른 부분에 미치는 영향을 최소화할 수 있습니다. 또한, 코드를 작은 단위로 분리하면 개별 클래스의 크기가 작아져 코드 이해도가 올라갑니다.&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;h3 data-ke-size=&quot;size23&quot;&gt;단일 책임 원칙(SRP) 적용 방법과 예시&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단일 책임 원칙을 적용하기 위해서는 먼저 클래스의 역할을 명확히 구분해야 합니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;예를 들어, 사용자 정보를 저장하고 로그인 기능을 처리하는 클래스가 있다고 가정한다면, 이 클래스는 사용자 정보 관리와 로그인 인증 두 가지 책임을 가지고 있습니다. 이를 단일 책임 원칙을 따르도록 리팩터링 하기 위해 두 가지 책임을 각각 다른 클래스로 분리합니다.&amp;nbsp;&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;h4 data-ke-size=&quot;size20&quot;&gt;[단일 책임 원칙(SRP) 미적용 클래스]&lt;/h4&gt;
&lt;pre id=&quot;code_1690420114071&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class UserManagement {
    public void saveUser(User user) {
        // 사용자 정보를 저장하는 로직
    }

    public boolean authenticateUser(String username, String password) {
        // 로그인 인증을 처리하는 로직
        return false;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서 UserManagement 클래스는 사용자 정보를 저장과 로그인 인증 두 가지 책임을 가지고 있습니다. 단일 책임 원칙을 적용하여 각각의 책임을 분리해 보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;[단일 책임 원칙(SRP) 적용 클래스]&lt;/h4&gt;
&lt;pre id=&quot;code_1690420212718&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class UserManager {
    public void saveUser(User user) {
        // 사용자 정보를 저장하는 로직
    }
}

public class UserAuthenticator {
    public boolean authenticateUser(String username, String password) {
        // 로그인 인증을 처리하는 로직
        return false;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서 UserManager 클래스는 사용자 정보를 저장하는 책임만 가지고 있도록 수정되었고, UserAuthenticator 클래스는 로그인 인증 기능을 담당하는 책임을 갖도록 분리되었습니다. 이렇게 수정해 주게 되면 각 클래스는 하나의 책임에만 집중하게 되며, 코드의 구조가 명확해졌습니다.&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;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;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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;pexels-mikhail-nilov-8730787.jpg&quot; data-origin-width=&quot;6016&quot; data-origin-height=&quot;4016&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfVdab/btspcwT6zbD/pnimmwapb3p9fhH6iiYdyK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfVdab/btspcwT6zbD/pnimmwapb3p9fhH6iiYdyK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfVdab/btspcwT6zbD/pnimmwapb3p9fhH6iiYdyK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfVdab%2FbtspcwT6zbD%2Fpnimmwapb3p9fhH6iiYdyK%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; alt=&quot;단일책임원칙&quot; loading=&quot;lazy&quot; width=&quot;6016&quot; height=&quot;4016&quot; data-filename=&quot;pexels-mikhail-nilov-8730787.jpg&quot; data-origin-width=&quot;6016&quot; data-origin-height=&quot;4016&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;클래스에 단일 책임의 여부를 판단하는 방법&lt;/h3&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;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;h4 data-ke-size=&quot;size20&quot;&gt;클래스의 이름 확인&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비즈니스적으로 정확하게 지정하기 어렵거나 Manager, Context처럼 일반적인 단어가 아니면 클래스의 이름을 정의하기 어려울 경우, 클래스 책임 정의가 충분히 명확하지 않음을 의미합니다. 클래스의 이름이나 주석이 모호하거나 다양한 책임을 나타내는 경우 단일 책임 원칙을 위반할 수 있다고 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;클래스의 크기 검토&lt;/h4&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;h4 data-ke-size=&quot;size20&quot;&gt;클래스 메서드 분석&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스의 메서드를 검토하여 어떤 작업을 수행하는지 확인합니다. 하나의 메서드가 여러 가지 작업을 처리하거나 private 메서드가 너무 많은 경우 이 private 메서드를 새로운 클래스로 분리하고 더 많은 클래스에서 사용할 수 있도록 public 메서드로 설정하여 코드의 재사용성을 향상할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;클래스의 의존성 분석&lt;/h4&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;h4 data-ke-size=&quot;size20&quot;&gt;코드리뷰&lt;/h4&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;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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;pexels-cottonbro-studio-4835429.jpg&quot; data-origin-width=&quot;3500&quot; data-origin-height=&quot;2333&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFZusq/btso6p9FbxF/FUjslZmSY0fg2bT0sV0jik/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFZusq/btso6p9FbxF/FUjslZmSY0fg2bT0sV0jik/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFZusq/btso6p9FbxF/FUjslZmSY0fg2bT0sV0jik/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFZusq%2Fbtso6p9FbxF%2FFUjslZmSY0fg2bT0sV0jik%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; alt=&quot;단일책임원칙&quot; loading=&quot;lazy&quot; width=&quot;3500&quot; height=&quot;2333&quot; data-filename=&quot;pexels-cottonbro-studio-4835429.jpg&quot; data-origin-width=&quot;3500&quot; data-origin-height=&quot;2333&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;단일 책임 원칙(SRP)을 위반하면 코드의 복잡성이 증가하고 유지보수가 어려워집니다. 하나의 클래스에 많은 책임을 집어넣으면 코드가 길고 복잡해지며, 변경이 발생할 때마다 다른 책임과 관련 없는 코드까지 영향을 받을 수 있습니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;단일 책임 원칙(SRP)을 따르면 클래스의 응집도가 높아지고, 이를 통해 인터페이스 분리 원칙(Interface Segregation Principle - ISP)과 의존성 역전 원칙(Dependency Inversion Principle - DIP)을 더욱 수월하게 적용할 수 있습니다.&lt;/li&gt;
&lt;li&gt;개발자들은 단일 책임 원칙(SRP)을 염두에 두고 코드를 설계하고 리팩터링 하여 좀 더 유지보수가 쉬운 코드를 작성하는데 노력해야 합니다.&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://daniel6364.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%ED%8C%A9%ED%86%A0%EB%A6%AC-%ED%8C%A8%ED%84%B4factory-pattern&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2023.06.05 - [Design Patterns] - 디자인 패턴 - 팩토리 패턴(factory pattern)&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1690424939288&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;디자인 패턴 - 팩토리 패턴(factory pattern)&quot; data-og-description=&quot;팩토리 패턴(factory pattern)이란? 객체를 생성하기 위한 인터페이스를 정의하는데, 어떤 클래스의 인스턴스를 만들지는 서브클래스에서 결정하게 한다 즉, 팩토리 메서드 패턴을 이용하면 클래스&quot; data-og-host=&quot;daniel6364.tistory.com&quot; data-og-source-url=&quot;https://daniel6364.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%ED%8C%A9%ED%86%A0%EB%A6%AC-%ED%8C%A8%ED%84%B4factory-pattern&quot; data-og-url=&quot;https://daniel6364.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%ED%8C%A9%ED%86%A0%EB%A6%AC-%ED%8C%A8%ED%84%B4factory-pattern&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/L8Bx3/hyTrTS8t1h/IHqLsnfqWZaqhzrhBOnkV0/img.jpg?width=800&amp;amp;height=534&amp;amp;face=0_0_800_534,https://scrap.kakaocdn.net/dn/b26TGz/hyTqzBYIhL/zypJD4OyWtFE9d8yeT5kRK/img.jpg?width=800&amp;amp;height=534&amp;amp;face=0_0_800_534&quot;&gt;&lt;a href=&quot;https://daniel6364.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%ED%8C%A9%ED%86%A0%EB%A6%AC-%ED%8C%A8%ED%84%B4factory-pattern&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://daniel6364.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%ED%8C%A9%ED%86%A0%EB%A6%AC-%ED%8C%A8%ED%84%B4factory-pattern&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/L8Bx3/hyTrTS8t1h/IHqLsnfqWZaqhzrhBOnkV0/img.jpg?width=800&amp;amp;height=534&amp;amp;face=0_0_800_534,https://scrap.kakaocdn.net/dn/b26TGz/hyTqzBYIhL/zypJD4OyWtFE9d8yeT5kRK/img.jpg?width=800&amp;amp;height=534&amp;amp;face=0_0_800_534');&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;디자인 패턴 - 팩토리 패턴(factory pattern)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;팩토리 패턴(factory pattern)이란? 객체를 생성하기 위한 인터페이스를 정의하는데, 어떤 클래스의 인스턴스를 만들지는 서브클래스에서 결정하게 한다 즉, 팩토리 메서드 패턴을 이용하면 클래스&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;daniel6364.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고서적&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&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;script type=&quot;text/javascript&quot; src=&quot;//wcs.naver.net/wcslog.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
if(!wcs_add) var wcs_add = {};
wcs_add[&quot;wa&quot;] = &quot;194a7af0aa57bb0&quot;;
if(window.wcs) {
  wcs_do();
}
&lt;/script&gt;</description>
      <category>Design Patterns</category>
      <category>Single</category>
      <category>SOLID</category>
      <category>SOLID원칙</category>
      <category>SRP</category>
      <category>단일책임원칙</category>
      <category>디자인패턴</category>
      <category>설계원칙</category>
      <author>Michael Gary Scott</author>
      <guid isPermaLink="true">https://daniel6364.tistory.com/11</guid>
      <comments>https://daniel6364.tistory.com/entry/%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99-single-responsibility-principle-SRP#entry11comment</comments>
      <pubDate>Thu, 27 Jul 2023 11:23:50 +0900</pubDate>
    </item>
    <item>
      <title>PostgreSQL - RDBMS</title>
      <link>https://daniel6364.tistory.com/entry/PostgreSQL-RDBMS</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;pexels-anete-lusina-4792746.jpg&quot; data-origin-width=&quot;6016&quot; data-origin-height=&quot;4016&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brPZdC/btsoIMwJohi/rSK4qWhEmIk6ruouRuMnvk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brPZdC/btsoIMwJohi/rSK4qWhEmIk6ruouRuMnvk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brPZdC/btsoIMwJohi/rSK4qWhEmIk6ruouRuMnvk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrPZdC%2FbtsoIMwJohi%2FrSK4qWhEmIk6ruouRuMnvk%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; alt=&quot;postgresql rdbms&quot; loading=&quot;lazy&quot; width=&quot;6016&quot; height=&quot;4016&quot; data-filename=&quot;pexels-anete-lusina-4792746.jpg&quot; data-origin-width=&quot;6016&quot; data-origin-height=&quot;4016&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;PostgreSQL의 주요 특징&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- RDMBS : Relational Database Management System&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;1. 오픈소스&amp;nbsp;&lt;/b&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;b&gt;2. 객체-관계형 데이터베이스&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;: PostgreSQL은 기본적으로 관계형 데이터베이스 시스템이지만, 확장 기능으로 객체-관계형 데이터베이스의 특징을 지원합니다. 이런 특징을 토대로 복잡한 데이터 구조를 모델링하고 관리하는 데 용이합니다.&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;3. ACID 준수&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;: ACID(원자성, 일관성, 고립성, 지속성) 원칙을 준수하여 데이터의 안정성과 무결성을 보장합니다. 이로 인해 데이터베이스 트랜잭션의 신뢰성이 높습니다.&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;4. 확정성&lt;/b&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;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. 다양한 데이터 타입&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;: 정수, 문자열, 날짜 및 시간, 배열, Json, UUID 등 다양한 데이터 타입을 지원합니다.&amp;nbsp;&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;6.&lt;/b&gt; 이 밖에 &lt;b&gt;다양한 기능과 확장 모듈&lt;/b&gt;을 지원하며, 표준 SQL 문법을 따르고, 대부분의 &lt;b&gt;SQL 호환&lt;/b&gt; 데이터베이스와 쉽게 호환됩니다. 마지막으로 데이터 &lt;b&gt;보안&lt;/b&gt;을 중요시하며, 접근 제어, 암호화, SSL 연결 등 다양한 보안 기능을 제공하여 데이터의 안전성을 유지합니다.&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;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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;객체-관계형 데이터베이스의 주요 특징&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체-관계형 데이터베이스(OODBMS, Object-Oriented Database Management System)는 전통적인 관계형 데이터베이스 모델에 객체 지향 프로그래밍의 개념과 기능을 결합하여 데이터를 모델링하고 다룰 수 있게 한 것을 의미합니다.&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;2-1. 객체 지향 데이터 모델링 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;객체 지향 프로그래밍과 유사한 방식으로 데이터를 모델링합니다. 데이터베이스 내의 데이터 요소들(테이블, 행 등)을 객체로 취급, 이들 사이의 관계를 객체 간의 관계로 표현합니다.&amp;nbsp;&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;2-2. 상속 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;테이블 간에 상속 관계를 지원합니다. 이는 하나의 테이블이 다른 테이블의 속성과 기능을 상속받을 수 있음을 의미합니다. 이를 통해 데이터 모델을 계층적으로 구성할 수 있으며, 데이터베이스 스키마의 유연성과 재사용성을 높여줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1690160128309&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE TABLE person (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100),
    age INT
);

CREATE TABLE employee (
    employee_id SERIAL PRIMARY KEY,
    department VARCHAR(100),
    salary DECIMAL(10, 2),
    position VARCHAR(50)
) INHERITS (person);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시에서 employee 테이블은 person 테이블을 상속받도록 생성했습니다. 이로 인해 employee 테이블은 person 테이블의 모든 속성을 가지면서 추가로 department, salary, position 속성을 가지게 됩니다. 이를 통해 직원 데이터를 따로 관리하면서 공통된 속성을 효과적으로 활용할 수 있습니다.&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;2-3. 사용자 정의 데이터 타입&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;PostgreSQL은 사용자가 직접 새로운 데이터 타입을 정의하고 사용할 수 있는 기능을 제공합니다. 이로 인해 데이터를 더 효율적으로 표현하고, 비즈니스 도메인에 특화된 데이터 타입을 만들 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1690160372548&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE TYPE address AS (
    street VARCHAR(200),
    city VARCHAR(100),
    zip_code VARCHAR(10),
    country VARCHAR(100)
);

CREATE TABLE customer (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100),
    customer_address address
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시에서 사용자 정의 데이터 타입 address를 생성하고, 이를 customer 테이블의 customer_address 필드에 사용합니다. 이로써 주소 정보를 하나의 필드로 묶어서 사용할 수 있으며, 코드의 가독성을 높이고 데이터 구조를 단순화할 수 있습니다.&amp;nbsp;&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;2-4. 객체 지향 쿼리 언어&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;PostgreSQL은 객체 지향 쿼리 언어를 지원하여 객체 간의 관계를 효율적으로 조회하고 조작할 수 있습니다. 객체 지향적인 방식으로 쿼리를 작성하여 데이터를 더 직관적으로 다룰 수 있습니다. PostgreSQL에서는 객체 지향 쿼리 언어인 &quot;Object-Relational SQL(ORSQL)&quot;을 사용하여 객체 지향적인 쿼리를 작성할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1690160735088&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- user_table

id | name       | age | email
---|------------|-----|-----------------------
1  | John Smith | 30  | john.smith@example.com
2  | Alice Lee  | 25  | alice.lee@example.com
3  | Bob Johnson| 35  | bob.johnson@example.com&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java에서 주로 사용되는 ORM(Object-Relational Mapping) 라이브러리인 Hibernate를 활용하여 PostgreSQL 데이터베이스와 상호 작용하는 아래 예시를 참고 바랍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1690160848323&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import javax.persistence.*;

@Entity
@Table(name = &quot;user_table&quot;)
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private int age;
    private String email;

    // Getters and Setters
    // ...

    // Constructors
    // ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시는 JPA(Java Persistence API) 어노테이션을 사용하여 데이터베이스 테이블과 매핑됩니다. '@Entity' 어노테이션은 해당 클래스가 JPA 엔티티임을 나타내며, '@Table' 어노테이션은 해당 엔티티가 어떤 데이터베이스 테이블과 매핑되는지 지정합니다. '@Id', '@GeneratedValue' 어노테이션은 기본 키(primary key) 필드와 자동 생성되는 값임을 나타냅니다.&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;아래는 Hibernate를 사용하여 객체 지향 쿼리입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1690161036943&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class Main {

    public static void main(String[] args) {
        // Hibernate SessionFactory 초기화
        SessionFactory sessionFactory = new Configuration()
                .configure(&quot;hibernate.cfg.xml&quot;)
                .addAnnotatedClass(User.class)
                .buildSessionFactory();

        // Hibernate Session 얻기
        try (Session session = sessionFactory.getCurrentSession()) {
            session.beginTransaction();

            // 모든 사용자를 조회하는 쿼리
            List&amp;lt;User&amp;gt; users = session.createQuery(&quot;from User&quot;, User.class).getResultList();

            // 특정 사용자 이름으로 조회하는 쿼리
            Query&amp;lt;User&amp;gt; query = session.createQuery(&quot;from User where name = :name&quot;, User.class);
            query.setParameter(&quot;name&quot;, &quot;John Smith&quot;);
            User user = query.getSingleResult();

            // 특정 나이 이상의 사용자들을 조회하는 쿼리
            Query&amp;lt;User&amp;gt; ageQuery = session.createQuery(&quot;from User where age &amp;gt;= :age&quot;, User.class);
            ageQuery.setParameter(&quot;age&quot;, 30);
            List&amp;lt;User&amp;gt; usersAboveAge = ageQuery.getResultList();

            session.getTransaction().commit();

            // 사용자 객체를 활용하여 데이터 조작
            // ...
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            sessionFactory.close();
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hibernate는 JPA의 구현제로서, 'session.createQuery()' 메서드를 사용하여 객체 지향 쿼리를 작성하고 실행할 수 있습니다. 또한, Hibernate는 데이터베이스와 객체 사이의 매핑을 자동으로 처리해 주므로 데이터베이스의 데이터를 자바 객체로 매핑하는 작업을 간소화해 줍니다.&amp;nbsp;&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;span style=&quot;color: #333333; text-align: start;&quot;&gt;위 예시를&lt;span&gt; &amp;nbsp;&lt;/span&gt;&lt;/span&gt;JPA Repository를 사용하면 Hibernate를 직접 사용하는 대신 Spring Data JPA를 활용하여 더 간단하게 객체 지향 쿼리를 작성할 수 있습니다. JPA Repository로 변경한 예시는 다음과 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1690161274197&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository&amp;lt;User, Long&amp;gt; {
    // 사용자 이름으로 조회하는 메서드
    List&amp;lt;User&amp;gt; findByName(String name);

    // 특정 나이 이상의 사용자들을 조회하는 메서드
    List&amp;lt;User&amp;gt; findByAgeGreaterThanEqual(int age);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시처럼 JPA Repository를 정의합니다. 'UserRepository' 인터페이스는 'JpaRepository'를 상속받고 있습니다. 이를 통해 사용자(User) 엔티티와 기본 키(primary key) 타입(Long)을 지정합니다. 그리고 해당 인터페이스 내에는 사용자 이름으로 조회하는 'findByName' 메서드와 특정 나이 이상의 사용자들을 조회하는 'findByAgeGreaterThanEqual' 메서드를 선언하였습니다. 이러한 메서드 선언만으로 Spring Data JPA가 해당 쿼리를 자동으로 생성해 줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1690161432261&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class Main {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Main.class, args);
        UserRepository userRepository = context.getBean(UserRepository.class);

        // 모든 사용자를 조회하는 쿼리
        List&amp;lt;User&amp;gt; users = userRepository.findAll();

        // 특정 사용자 이름으로 조회하는 쿼리
        List&amp;lt;User&amp;gt; usersWithName = userRepository.findByName(&quot;John Smith&quot;);

        // 특정 나이 이상의 사용자들을 조회하는 쿼리
        List&amp;lt;User&amp;gt; usersAboveAge = userRepository.findByAgeGreaterThanEqual(30);

        // 사용자 객체를 활용하여 데이터 조작
        // ...
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Boot 애플리케이션으로 선언하고, 'UserRepository'를 주입받아 객체 지향 쿼리를 실행하고 있습니다.&amp;nbsp;&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;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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;객체-관계형 데이터베이스와 관계형 데이터베이스의 주요 차이점&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 데이터 모델링 방식&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;RDBMS : &lt;/b&gt;관계형 데이터베이스는 데이터를 테이블의 형태로 모델링합니다. 테이블은 행(row)과 열(column)의 집합으로 구성되며, 각 행은 고유한 기본키(primary key)로 식별됩니다. 테이블 간의 관계는 외래키(foreign key)를 사용하여 표현됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;OODBMS :&amp;nbsp;&lt;/b&gt;객체-관계형 데이터베이스는 객체 지향 프로그래밍과 유사한 방식으로 데이터를 모델링합니다. 데이터베이스 내의 데이터 요소들은 객체로 표현되며, 객체는 속성(attribute)과 메서드(method)를 가질 수 있습니다. 상속, 다형성과 같은 객체 지향의 특징이 데이터베이스에도 적용될 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 데이터 쿼리와 조작&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;RDMBS :&amp;nbsp;&lt;/b&gt;SQL(Structured Query Language)을 사용하여 데이터를 조회하고 조작합니다. SQL은 표준화된 쿼리 언어로, 데이터베이스에 접근하고 조작하는데 사용됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;OODBMS : &lt;/b&gt;객체-관계형 데이터베이스는 객체 지향 쿼리 언어를 사용하여 데이터를 다룹니다. 객체의 속성과 메서드를 활용하여 데이터를 쿼리하고 조작할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. 무결성 제약 조건&amp;nbsp;&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;RDMBS : &lt;/b&gt;테이블 간의 관계를 외래키를 사용하여 정의하고, 무결성 제약 조건을 통해 데이터의 일관성과 무결성을 유지합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;OODBMS : &lt;/b&gt;객체 간의 관계를 객체 참조(reference)를 통해 정의하고, 객체 식별자(identifier)를 사용하여 무결성을 유지합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4. 상속과 다형성&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;RDMBS :&lt;span&gt; &lt;/span&gt;&lt;/b&gt;테이블 간의 상속을 직접적으로 지원하지 않습니다. 다형성 구현을 위해 JOIN과 같은 방법을 사용할 수 있으나, 직접적인 상속 개념은 없습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;OODBMS : &lt;/b&gt;테이블 간의 상속 관계를 지원합니다. 객체의 다형성을 지원하여, 여러 객체가 하나의 인터페이스를 구현하거나 상속 관계를 가질 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 사용자 장의 데이터 타입&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;RDMBS :&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;기본적으로 정해진 데이터 타입을 제공합니다. 사용자가 직접 데이터 타입을 정의하는 것은 어려운 경우가 많습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;OODBMS :&lt;span&gt;&amp;nbsp;&lt;/span&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;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;script type=&quot;text/javascript&quot; src=&quot;//wcs.naver.net/wcslog.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
if(!wcs_add) var wcs_add = {};
wcs_add[&quot;wa&quot;] = &quot;194a7af0aa57bb0&quot;;
if(window.wcs) {
  wcs_do();
}
&lt;/script&gt;</description>
      <category>DataBase</category>
      <category>oodbms</category>
      <category>postgresql</category>
      <category>postgresql특징</category>
      <category>RDBMS</category>
      <category>데이터베이스</category>
      <author>Michael Gary Scott</author>
      <guid isPermaLink="true">https://daniel6364.tistory.com/10</guid>
      <comments>https://daniel6364.tistory.com/entry/PostgreSQL-RDBMS#entry10comment</comments>
      <pubDate>Mon, 24 Jul 2023 11:20:25 +0900</pubDate>
    </item>
    <item>
      <title>Java IO와 NIO</title>
      <link>https://daniel6364.tistory.com/entry/Java-IO%EC%99%80-NIO</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;pexels-antonio-avanti-17072947.jpg&quot; data-origin-width=&quot;8192&quot; data-origin-height=&quot;5462&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmBhtt/btsovvhM0Xl/Sk4faLkaExkKWhGrIchs70/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmBhtt/btsovvhM0Xl/Sk4faLkaExkKWhGrIchs70/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmBhtt/btsovvhM0Xl/Sk4faLkaExkKWhGrIchs70/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmBhtt%2FbtsovvhM0Xl%2FSk4faLkaExkKWhGrIchs70%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; alt=&quot;Java IO와 NIO&quot; loading=&quot;lazy&quot; width=&quot;8192&quot; height=&quot;5462&quot; data-filename=&quot;pexels-antonio-avanti-17072947.jpg&quot; data-origin-width=&quot;8192&quot; data-origin-height=&quot;5462&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;h3 data-ke-size=&quot;size23&quot;&gt;IO (Input / Output)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바의 IO는 Input과 Output을 처리하는 방법입니다. InputStream과 OutputStream 클래스 계열을 사용하여 데이터를 읽고 쓰는 작업을 수행합니다.&amp;nbsp;&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;IO는 스트림(stream) 개념을 기반으로 하며, 한 번에 하나의 데이터를 읽고 쓰는 방식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 대표적인 IO클래스 입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;FileInputStream&lt;/li&gt;
&lt;li&gt;FileOuputStream&lt;/li&gt;
&lt;li&gt;BufferedReader&lt;/li&gt;
&lt;li&gt;BufferedWriter&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IO는 단순하고 직관적인 인터페이스를 제공하지만, 대량의 데이터를 처리할 때는 비효율적일 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1689917591071&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;

public class IOExample {
    public static void main(String[] args) {
        try {
            // 파일에서 데이터 읽기
            FileInputStream fileInputStream = new FileInputStream(&quot;input.txt&quot;);
            InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

            String line;
            while ((line = bufferedReader.readLine()) != null) {
                System.out.println(line);
            }

            bufferedReader.close();

            // 파일에 데이터 쓰기
            FileOutputStream fileOutputStream = new FileOutputStream(&quot;output.txt&quot;);
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);
            BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);

            bufferedWriter.write(&quot;Hello, World!&quot;);
            bufferedWriter.newLine();
            bufferedWriter.write(&quot;This is an example of IO.&quot;);

            bufferedWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 예시에서 'input.txt' 파일에서 데이터를 읽어와서 출력하고, 'output.txt' 파일에 데이터를 씁니다. FileInputStream과 FileOutputStream은 파일에서 바이트 단위로 데이터를 읽고 쓰는 데 사용되며, InputStreamReader와 OutputStreamWriter는 문자 단위로 데이터를 읽고 쓰는데 사용됩니다. BufferedReader와 BufferedWriter는 버퍼를 사용하여 효율적인 입출력을 지원합니다.&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;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;h3 data-ke-size=&quot;size23&quot;&gt;NIO (Non-blocking IO)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NIO는 자바 1.4부터 도입된 비동기적인 입출력 방식입니다. NOI는 IO보다 더욱 유연하고 빠른 입출력 처리를 제공합니다. NIO는 채널(channel)과 버퍼(buffer)라는 개념을 중심으로 동작합니다.&amp;nbsp;&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NIO는 Selector 클래스를 사용하여 하나의 스레드로 여러 채널을 모니터링하고, 데이터를 읽거나 쓸 준비가 된 채널만 처리할 수 있습니다. 이는 비동기적인 입출력 처리를 가능하게 합니다. 아래는 대표적인 NIO클래스입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ByteBuffer&lt;/li&gt;
&lt;li&gt;Selector&lt;/li&gt;
&lt;li&gt;Channel&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NIO는 대량의 데이터 처리 및 네트워크 프로그래밍에 특히 유용합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1689917609858&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.*;

public class NIOExample {
    public static void main(String[] args) {
        try {
            // 파일에서 데이터 읽기
            Path path = Paths.get(&quot;input.txt&quot;);
            FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ);
            ByteBuffer buffer = ByteBuffer.allocate(1024);

            int bytesRead = fileChannel.read(buffer);
            while (bytesRead != -1) {
                buffer.flip(); // 버퍼를 읽기 위해 준비

                while (buffer.hasRemaining()) {
                    System.out.print((char) buffer.get()); // 데이터 출력
                }

                buffer.clear(); // 버퍼 비우기
                bytesRead = fileChannel.read(buffer);
            }

            fileChannel.close();

            // 파일에 데이터 쓰기
            Path outputPath = Paths.get(&quot;output.txt&quot;);
            FileChannel outputChannel = FileChannel.open(outputPath, StandardOpenOption.CREATE, StandardOpenOption.WRITE);

            String data = &quot;Hello, World! This is an example of NIO.&quot;;
            byte[] byteArray = data.getBytes();
            ByteBuffer outputBuffer = ByteBuffer.wrap(byteArray);

            outputChannel.write(outputBuffer);

            outputChannel.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 예시에서 'input.txt' 파일에서 데이터를 읽어와서 출력하고, 'output.txt' 파일에 데이터를 씁니다. FileChannel은 NIO에서 파일을 읽고 쓰는 데 사용되며, ByteBuffer는 데이터를 저장하고 처리하는 버퍼 역할을 합니다. FIilChannel의 'read()' 메서드를 사용하여 데이터를 읽고, 'write()' 메서드를 사용하여 데이터를 씁니다. NIO에서는 버퍼를 사용하여 데이터를 효율적으로 처리할 수 있습니다.&amp;nbsp;&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;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://daniel6364.tistory.com/entry/Java-blocking%EA%B3%BC-non-blocking&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2023.07.21 - [Backend] - Java blocking과 non-blocking&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1689919160134&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Java blocking과 non-blocking&quot; data-og-description=&quot;Blocking I/O (블로킹 입출력) Blocking I/O는 입출력 작업 중에 해당 작업이 완료될 때까지 스레드가 블로킹되는 방식입니다. 즉, 입출력 작업이 완료되기 전까지 해당 스레드는 다른 작업을 수행할 수&quot; data-og-host=&quot;daniel6364.tistory.com&quot; data-og-source-url=&quot;https://daniel6364.tistory.com/entry/Java-blocking%EA%B3%BC-non-blocking&quot; data-og-url=&quot;https://daniel6364.tistory.com/entry/Java-blocking%EA%B3%BC-non-blocking&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/baxMMT/hyTnHzhb8p/kNKdY8F7JLVMXdzdkcM0vK/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/bCN9CL/hyTnUSSOP5/AV8kBZ6DtHr9KeTpWB2Kj0/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/g0DFy/hyTnVROYEm/qqodU53XCkcTkuwvoWgLx0/img.jpg?width=3024&amp;amp;height=4032&amp;amp;face=0_0_3024_4032&quot;&gt;&lt;a href=&quot;https://daniel6364.tistory.com/entry/Java-blocking%EA%B3%BC-non-blocking&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://daniel6364.tistory.com/entry/Java-blocking%EA%B3%BC-non-blocking&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/baxMMT/hyTnHzhb8p/kNKdY8F7JLVMXdzdkcM0vK/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/bCN9CL/hyTnUSSOP5/AV8kBZ6DtHr9KeTpWB2Kj0/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/g0DFy/hyTnVROYEm/qqodU53XCkcTkuwvoWgLx0/img.jpg?width=3024&amp;amp;height=4032&amp;amp;face=0_0_3024_4032');&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;Java blocking과 non-blocking&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Blocking I/O (블로킹 입출력) Blocking I/O는 입출력 작업 중에 해당 작업이 완료될 때까지 스레드가 블로킹되는 방식입니다. 즉, 입출력 작업이 완료되기 전까지 해당 스레드는 다른 작업을 수행할 수&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;daniel6364.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;//wcs.naver.net/wcslog.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
if(!wcs_add) var wcs_add = {};
wcs_add[&quot;wa&quot;] = &quot;194a7af0aa57bb0&quot;;
if(window.wcs) {
  wcs_do();
}
&lt;/script&gt;</description>
      <category>Backend</category>
      <category>io</category>
      <category>NIO</category>
      <category>자바</category>
      <author>Michael Gary Scott</author>
      <guid isPermaLink="true">https://daniel6364.tistory.com/9</guid>
      <comments>https://daniel6364.tistory.com/entry/Java-IO%EC%99%80-NIO#entry9comment</comments>
      <pubDate>Fri, 21 Jul 2023 14:59:38 +0900</pubDate>
    </item>
    <item>
      <title>Java blocking과 non-blocking</title>
      <link>https://daniel6364.tistory.com/entry/Java-blocking%EA%B3%BC-non-blocking</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;pexels-maxim-shklyaev-2914194.jpg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NW0YZ/btsou1Pfwng/Qj6sHYGl8N9v22TAWqpRi0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NW0YZ/btsou1Pfwng/Qj6sHYGl8N9v22TAWqpRi0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NW0YZ/btsou1Pfwng/Qj6sHYGl8N9v22TAWqpRi0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNW0YZ%2Fbtsou1Pfwng%2FQj6sHYGl8N9v22TAWqpRi0%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; alt=&quot;Java blocking과 non-blocking&quot; loading=&quot;lazy&quot; width=&quot;380&quot; height=&quot;507&quot; data-filename=&quot;pexels-maxim-shklyaev-2914194.jpg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Blocking I/O (블로킹 입출력)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Blocking I/O는 입출력 작업 중에 해당 작업이 완료될 때까지 스레드가 블로킹되는 방식입니다. 즉, 입출력 작업이 완료되기 전까지 해당 스레드는 다른 작업을 수행할 수 없으며 대기 상태에 있게 됩니다. 입출력 작업은 데이터를 읽어오거나 쓰는 동안 스레드가 멈추기 때문에 해당 작업이 오래 걸리는 경우, 다른 작업들의 처리도 지연될 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1689918268624&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;

public class BlockingIOExample {
    public static void main(String[] args) {
        try {
            FileInputStream fileInputStream = new FileInputStream(&quot;input.txt&quot;);
            byte[] data = new byte[1024];
            int bytesRead = fileInputStream.read(data); // 데이터를 읽기 위해 블로킹됨
            System.out.println(&quot;Read &quot; + bytesRead + &quot; bytes: &quot; + new String(data));
            fileInputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시에서 'read()' 메서드가 데이터를 읽을 때까지 스레드가 블로킹되어 대기합니다.&amp;nbsp;&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;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;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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Non-blocking I/O (논블로킹 입출력)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Non-blocking I/O는 입출력 작업 중에 스레드가 블로킹되지 않고 계속 다른 작업을 수행할 수 있는 방식입니다. 입출력 작업을 수행하는 동안 스레드는 블로킹되지 않으며, 입출력 작업의 완료 여부를 확인하고, 필요에 따라 추가적인 작업을 수행할 수 있습니다. 이는 입출력 작업이 오래 걸리더라도 다른 작업들의 처리가 블로킹되지 않으므로, 더 효율적인 다중 작업 처리가 가능합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1689918276193&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.*;

public class NonBlockingIOExample {
    public static void main(String[] args) {
        try {
            Path path = Paths.get(&quot;input.txt&quot;);
            FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ);
            ByteBuffer buffer = ByteBuffer.allocate(1024);

            int bytesRead = fileChannel.read(buffer); // 블로킹되지 않고 읽기를 시도함

            if (bytesRead != -1) {
                buffer.flip();
                byte[] data = new byte[buffer.remaining()];
                buffer.get(data);
                System.out.println(&quot;Read &quot; + bytesRead + &quot; bytes: &quot; + new String(data));
            }

            fileChannel.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시에서 'read()' 메서드가 블로킹되지 않고 일기를 시도하면, 데이터를 읽기 전까지 다른 작업을 수행할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;'fileChannel.read(buffer)'는 블로킹되지 않고 데이터 읽기를 시도&lt;/li&gt;
&lt;li&gt;데이터가 바로 읽혀지지 않을 수도 있음&lt;/li&gt;
&lt;li&gt;하지만 이 메서드는 블로킹되지 않으므로 즉시 다음 코드를 실행&lt;/li&gt;
&lt;li&gt;데이터가 준비되면 'bytesRead'에 읽은 바이트 수가 저장&lt;/li&gt;
&lt;li&gt;이후 'if (bytesRead != -1)' 조건문을 통해 데이터를 정상적으로 읽었을 때만 처리&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 'fileChannerl.close()' 메서드는 'bytesRead' 변수와 상관없이 'read()' 메서드를 호출하더라도 먼저 실행될 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;//wcs.naver.net/wcslog.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
if(!wcs_add) var wcs_add = {};
wcs_add[&quot;wa&quot;] = &quot;194a7af0aa57bb0&quot;;
if(window.wcs) {
  wcs_do();
}
&lt;/script&gt;</description>
      <category>Backend</category>
      <category>blockingIO</category>
      <category>Java</category>
      <category>nonblockingIO</category>
      <category>동기처리</category>
      <category>비동기처리</category>
      <author>Michael Gary Scott</author>
      <guid isPermaLink="true">https://daniel6364.tistory.com/8</guid>
      <comments>https://daniel6364.tistory.com/entry/Java-blocking%EA%B3%BC-non-blocking#entry8comment</comments>
      <pubDate>Fri, 21 Jul 2023 14:58:20 +0900</pubDate>
    </item>
    <item>
      <title>Java Spring Framework - @Transactional</title>
      <link>https://daniel6364.tistory.com/entry/Java-Spring-Framework-Transactional</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Transactional은 스프링 프레임워크에서 트랜잭션 관리를 선언적으로 처리하는 데 사용되는 어노테이션입니다. 이를 사용하여 트랜잭션의 시작과 종료, 속성 설정, 롤백 처리 등을 자동화할 수 있습니다.&amp;nbsp;&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;pexels-kevin-ku-577585.jpg&quot; data-origin-width=&quot;3353&quot; data-origin-height=&quot;2514&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cGK9ia/btsogZ578LE/qU6WcnlWDZvVNetsWnPC41/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGK9ia/btsogZ578LE/qU6WcnlWDZvVNetsWnPC41/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGK9ia/btsogZ578LE/qU6WcnlWDZvVNetsWnPC41/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcGK9ia%2FbtsogZ578LE%2FqU6WcnlWDZvVNetsWnPC41%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; alt=&quot;Java Spring Framework - @Transactional&quot; loading=&quot;lazy&quot; width=&quot;3353&quot; height=&quot;2514&quot; data-filename=&quot;pexels-kevin-ku-577585.jpg&quot; data-origin-width=&quot;3353&quot; data-origin-height=&quot;2514&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;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;b&gt;클래스&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인터페이스&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메서드&amp;nbsp;&lt;/b&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;h3 data-ke-size=&quot;size23&quot;&gt;적용 범위에 따른 우선순위&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 메서드(Method) &amp;gt; 클래스(Class) &amp;gt; 인터페이스(Interface) &amp;gt; 빈(Bean)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메서드 단위에 @Transactional 어노테이션이 적용된 경우, 해당 메서드의 트랜잭션 설정이 우선적으로 적용됩니다.&lt;/li&gt;
&lt;li&gt;클래스 단위에 적용된 경우 해당 클래스의 모든 public 메서드에 영향을 미치지만, 메서드 단위에서 재정의 된 설정이 있다면 메서드 단위 설정이 우선 적용됩니다.&lt;/li&gt;
&lt;li&gt;인터페이스, 빈 단위에 적용 또한 위 내용과 동일합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 메서드 단위에 중복 적용되었을 경우&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하나의 메서드에 여러 개의 @Transactional 어노테이션이 적용된 경우, 가장 트랜잭션 범위가 좁은 설정이 우선 적용됩니다. 즉, 가장 안쪽에 있는 트랜잭션이 설정 적용됩니다.&amp;nbsp;&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;메서드 단위의 트랜잭션 설정이 우선순위가 높기 때문에 가능한 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;메서드 단위로 @Transactional 어노테이션을 적용하는 것을 권장&lt;/b&gt;&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;&amp;nbsp;&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;주요 속성&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;readOnly&lt;/b&gt;&lt;/span&gt; : 해당 트랜잭션이 읽기 전용인지 여부를 설정합니다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;true&lt;/span&gt;인 경우 Hibernate와 같은 ORM 프레임워크는 성능을 최적화하는 데 도움이 될 수 있는 여러 가지 내부 최적화를 수행할 수 있습니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1689831802993&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// default = false
@Transactional(readOnly = true)
public void somBusinessLogic() {...} 

@Transactional(readOnly = false)
public void somBusinessLogic() {...}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;timeout&lt;/b&gt;&lt;/span&gt; : 트랜잭션의 타임아웃 시간을 설정합니다.&lt;/li&gt;
&lt;li&gt;설정한 시간을 초과하면, 트랜잭션 시스템은 롤백하고 '&lt;b&gt;&lt;i&gt;TransactionTimeOutException&lt;/i&gt;&lt;/b&gt;'을 반환합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1689831931265&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// default = -1
@Transactional(timeout = 20)
public void somBusinessLogic() {...}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;rollbackFor / noRollbackFor&lt;/b&gt;&lt;/span&gt; : 특정 예외 발생 시 트랜잭션 롤백 여부를 설정합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;rollbackFor&lt;/span&gt;&lt;/b&gt; 속성은 트랜잭션 내에서 특정 예외가 발생했을 때 트랜잭션을 롤백하도록 설정하는 것입니다. 클래스 또는 클래스 이름의 배열을 인수로 받을 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;noRollbackFor&lt;/span&gt;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;속성은 특정 예외가 발생했을 때 트랜잭션을 롤백하지 않도록 설정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1689832034726&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Transactional(rollbackFor = IOException.class)
public void somBusinessLogic() {...} 

@Transactional(noRollbackFor = FileNotFoundException.class)
public void somBusinessLogic() {...}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;propagaion&lt;/b&gt;&lt;/span&gt; : 트랜잭션의 전파 방식을 설정합니다.&lt;/li&gt;
&lt;li&gt;가장 일반적인 값으로는 &lt;b&gt;&lt;i&gt;'Propagation.REQUIRED'&lt;/i&gt;&lt;/b&gt;&lt;i&gt;와&lt;/i&gt; &lt;i&gt;&lt;b&gt;'Propagation.REQUIRES_NEW'&lt;/b&gt;가&lt;/i&gt; 있습니다.&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;REQUIRED&lt;/span&gt; &lt;/b&gt;: 부모 트랜잭션 내에서 실행되거나, 부모 트랜잭션이 없는 경우 새로운 트랜잭션을 시작합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;SUPPORTS&lt;/span&gt; &lt;/b&gt;: 이미 시작된 트랜잭션이 있으면 그것을 사용하고, 없으면 트랜잭션 없이 실행됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;MANDATORY&lt;/span&gt; &lt;/b&gt;: 이미 시작된 트랜잭션이 있으면 그것을 사용하고, 없으면 예외를 던집니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;REQUIRES_NEW&lt;/span&gt;&lt;/b&gt; : 항상 새 트랜잭션을 시작하며, 이미 진행 중인 트랜잭션이 있으면 잠시 보류(suspend) 상태로 만듭니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;NOT_SUPPORTED&lt;/span&gt; &lt;/b&gt;: 트랜잭션 없이 메서드를 실행하며, 이미 진행 중인 트랜잭션이 있으면 잠시 보류(suspend) 상태로 만듭니다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;b&gt;NEVER&lt;/b&gt;&lt;/span&gt; : &lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;트랜잭션 없이 메서드를 실행하며, 이미 진행 중인 트랜잭션이 있으면&lt;span&gt; 예외를 던집니다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;b&gt;NESTED&lt;/b&gt;&lt;/span&gt; : 부모 트랜잭션 내에서 중첩 트랜잭션을 시작하거나, 부모 트랜잭션이 없는 경우 새로운 트랜잭션을 시작합니다. 이 옵션은 JDBC 3.0 드라이버에서 지원하는 'Savepoint' 기능을 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1689832197803&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// defalt = REQUIRED
@Transactional(propagation = Propagation.MANDATORY)
public void somBusinessLogic() {...} 

@Transactional(propagation = Propagation.NESTED)
public void somBusinessLogic() {...} 

@Transactional(propagation = Propagation.NEVER)
public void somBusinessLogic() {...} 

@Transactional(propagation = Propagation.REQUIRED)
public void somBusinessLogic() {...} 

@Transactional(propagation = Propagation.SUPPORTS)
public void somBusinessLogic() {...} 

@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void somBusinessLogic() {...} 

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void somBusinessLogic() {...}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;isolation&lt;/b&gt;&lt;/span&gt; : 트랜잭션의 격리 수준을 설정하는데 사용합니다.&lt;/li&gt;
&lt;li&gt;트랜잭션 격리 수준은 한 트랜잭션이 다른 트랜잭션에게 보이는 데이터를 결정합니다.&amp;nbsp;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;READ_UNCOMMITTED&lt;/span&gt;&lt;/b&gt; (읽기 미확정) : 한 트랜잭션이 다른 트랜잭션의 변경된, 하지만 아직 커밋되지 않은 데이터를 읽을 수 있습니다. 이렇게 되면 Dirty Read, Non-Repeatable Read, Phantom Read라는 세 가지 문제가 발생할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;READ_COMMITTED&lt;/span&gt;&lt;/b&gt; (읽기 확정) : 한 트랜잭션이 다른 트랜잭션의 변경된 데이터를 읽을 수 있지만, 해당 변경이 커밋된 후에만 가능합니다. 이 수준은 Dirty Read 문제를 해결하지만, Non-Repeatable Read, Phantom Read 문제는 여전히 발생할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;REPEATABLE_READ&lt;/span&gt;&lt;/b&gt; (반복 가능한 읽기) : 한 트랜잭션이 다른 트랜잭션에 의해 변경된 데이터를 읽지 못하도록 합니다. 즉, 트랜잭션 도중에 다른 트랜잭션에서 변경된 데이터를 반복해서 읽어도 동일한 결과를 보장합니다. 이 수준은&amp;nbsp;Dirty Read와&lt;span&gt;&amp;nbsp;&lt;/span&gt;Non-Repeatable Read 문제를 해결하지만 Phantom Read 문제는 여전히 발생할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;SERIALIZABLE&lt;/span&gt;&lt;/b&gt; (직렬 가능) : 트랜잭션들이 순차적으로 실행되어야 하므로 동시성을 완전히 제거합니다. 이 수준은 Dirty Read, Non-Repeatable Read, Phantom Read 모든 문제를 해결하지반, 트랜잭션 동시성이 제거되므로 성능이 크게 떨어질 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;b&gt;DEFAULT&lt;/b&gt;&lt;/span&gt; : 특정 격리 수준을 지정하지 않을 때 사용하는 격리 수준입니다. 이 옵션은 Spring은 백엔드 DBMS의 기본 트랜잭션 격리 수준을 사용합니다. 그래서, 'Isolation.DEFAULT'가 실제로 어떤 격리 수준을 나타내는지는 사용하는 DBMS에 따라 달라집니다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;예를 들면, MySQL의 경우 기본 격리 수준은 'REPEATABLE_READ'이며, ORCLE의 경우 격리 수준은 'READ_COMMITTED', PostgreSQL의 기본 격리 수준은 'READ_COMMITTED'입니다.&lt;br /&gt;&lt;br /&gt;해당 격리 설정으로 사용 시 문제 될 수 있는 부분은 다음과 같습니다.&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Non-repeatable reads&lt;/b&gt; : 'READ_COMMITTED'는 &lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;Non-repeatable reads&lt;span&gt; 문제를 해결하지 못합니다. 즉, 같은 트랜잭션 내에서 동일한 쿼리를 두 번 실행하면 다른 결과가 반환될 수 있습니다. 이는 다른 트랜잭션에 의해 데이터가 변경되었기 때문입니다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;&lt;span&gt;&lt;b&gt;Phantom read&lt;/b&gt; : 'READ_COMMITTED'는 &lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;Phantom read&lt;span&gt; 문제를 해결하지 못합니다. 즉, 같은 트랜잭션 내에서 동일한 쿼리를 두 번 실행하면 새로 생긴 행을 읽을 수 있습니다.. 이는 다른 트랜잭션에 의해 새 행이 추가되었기 때문입니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;&lt;span&gt;&lt;b&gt;DMBS 의존성&lt;/b&gt; : 트랜잭션 격리 수준을 명시적으로 설정하지 않으면, 애플리케이션이 DBMS에 의존적이게 됩니다. 즉, 백엔드 DBMS를 변경하면 트랜잭션의 동작이 변경될 수 있습니다. 이러한 의존성은 유지 관리와 이식성 문제를 야기할 수 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1689832282749&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Transactional(isolation = Isolation.READ_COMMITTED)
public void somBusinessLogic() {...} 

@Transactional(isolation = Isolation.DEFAULT)
public void somBusinessLogic() {...} 

@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public void somBusinessLogic() {...} 

@Transactional(isolation = Isolation.REPEATABLE_READ)
public void somBusinessLogic() {...} 

@Transactional(isolation = Isolation.SERIALIZABLE)
public void somBusinessLogic() {...}&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;Dirty Read, Non-Repeatable Read, Phantom Read에 대한 설명은 아래글 참조&lt;br /&gt;&lt;a style=&quot;background-color: #e6f5ff; color: #0070d1; text-align: start;&quot; href=&quot;https://daniel6364.tistory.com/entry/Transaction-isolation-%EA%B2%A9%EB%A6%AC-%EC%88%98%EC%A4%80%EC%97%90-%EB%94%B0%EB%A5%B8-%EC%84%B8%EA%B0%80%EC%A7%80-%ED%98%84%EC%83%81&quot;&gt;2023.07.20 - [Backend] - @Transaction - isolation 격리 수준에 따른 세가지 현상&lt;/a&gt;&amp;nbsp;&lt;/blockquote&gt;
&lt;figure id=&quot;og_1689840352123&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;@Transaction - isolation 격리 수준에 따른 세가지 현상&quot; data-og-description=&quot;1. Dirty Read 한 트랜잭션(T1)이 아직 커밋되지 않은 다른 트랜잭션(T2)에 의해 변경된 데이터를 읽는 현상을 말한다. 만약 T2가 롤백되면, T1이 읽은 데이터는 더 이상 유효하지 않게 됩니다. 이러한 &quot; data-og-host=&quot;daniel6364.tistory.com&quot; data-og-source-url=&quot;https://daniel6364.tistory.com/entry/Transaction-isolation-%EA%B2%A9%EB%A6%AC-%EC%88%98%EC%A4%80%EC%97%90-%EB%94%B0%EB%A5%B8-%EC%84%B8%EA%B0%80%EC%A7%80-%ED%98%84%EC%83%81&quot; data-og-url=&quot;https://daniel6364.tistory.com/entry/Transaction-isolation-%EA%B2%A9%EB%A6%AC-%EC%88%98%EC%A4%80%EC%97%90-%EB%94%B0%EB%A5%B8-%EC%84%B8%EA%B0%80%EC%A7%80-%ED%98%84%EC%83%81&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/zU7S8/hyTmpMTV1z/oqMuFYMQmTU6IP8NWDupQK/img.jpg?width=800&amp;amp;height=533&amp;amp;face=0_0_800_533,https://scrap.kakaocdn.net/dn/rSPbf/hyTmtPjadD/KEzOEkpCFM7bPp7ip5tzz0/img.jpg?width=800&amp;amp;height=533&amp;amp;face=0_0_800_533,https://scrap.kakaocdn.net/dn/CpsoO/hyTmomVlEQ/THAuaVCuUpPH8yXeuaXcW1/img.jpg?width=5281&amp;amp;height=3521&amp;amp;face=0_0_5281_3521&quot;&gt;&lt;a href=&quot;https://daniel6364.tistory.com/entry/Transaction-isolation-%EA%B2%A9%EB%A6%AC-%EC%88%98%EC%A4%80%EC%97%90-%EB%94%B0%EB%A5%B8-%EC%84%B8%EA%B0%80%EC%A7%80-%ED%98%84%EC%83%81&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://daniel6364.tistory.com/entry/Transaction-isolation-%EA%B2%A9%EB%A6%AC-%EC%88%98%EC%A4%80%EC%97%90-%EB%94%B0%EB%A5%B8-%EC%84%B8%EA%B0%80%EC%A7%80-%ED%98%84%EC%83%81&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/zU7S8/hyTmpMTV1z/oqMuFYMQmTU6IP8NWDupQK/img.jpg?width=800&amp;amp;height=533&amp;amp;face=0_0_800_533,https://scrap.kakaocdn.net/dn/rSPbf/hyTmtPjadD/KEzOEkpCFM7bPp7ip5tzz0/img.jpg?width=800&amp;amp;height=533&amp;amp;face=0_0_800_533,https://scrap.kakaocdn.net/dn/CpsoO/hyTmomVlEQ/THAuaVCuUpPH8yXeuaXcW1/img.jpg?width=5281&amp;amp;height=3521&amp;amp;face=0_0_5281_3521');&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;@Transaction - isolation 격리 수준에 따른 세가지 현상&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;1. Dirty Read 한 트랜잭션(T1)이 아직 커밋되지 않은 다른 트랜잭션(T2)에 의해 변경된 데이터를 읽는 현상을 말한다. 만약 T2가 롤백되면, T1이 읽은 데이터는 더 이상 유효하지 않게 됩니다. 이러한&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;daniel6364.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;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;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;pexels-tranmautritam-225502.jpg&quot; data-origin-width=&quot;5018&quot; data-origin-height=&quot;3241&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DazyI/btsonRFc5VQ/KKTMqS0Onw8qOuVW2pdo20/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DazyI/btsonRFc5VQ/KKTMqS0Onw8qOuVW2pdo20/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DazyI/btsonRFc5VQ/KKTMqS0Onw8qOuVW2pdo20/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDazyI%2FbtsonRFc5VQ%2FKKTMqS0Onw8qOuVW2pdo20%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; alt=&quot;Java Spring Framework - @Transactional&quot; loading=&quot;lazy&quot; width=&quot;5018&quot; height=&quot;3241&quot; data-filename=&quot;pexels-tranmautritam-225502.jpg&quot; data-origin-width=&quot;5018&quot; data-origin-height=&quot;3241&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;사용 시 주의할 점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 트랜잭션 범위의 이해 : @Transaction 어노테이션을 사용하면 해당 메서드는 새 트랜잭션 컨텍스트에서 실행됩니다. 이는 메서드 실행이 실패하면 트랜잭션이 롤백되며, 성공적으로 완료되면 커밋된다는 것을 의미합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1689837330180&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Transactional
public void someServiceMethod() {

	// 트랜잭션이 시작됨
    
    someDaoMethod1(); // 이 메서드는 현재 트랜잭션 내에서 실행
    someDaoMethod2(); // 이 메서드는 현재 트랜잭션 내에서 실행
    
    // someServieMethod가 성공적으로 완료되면 트랜잭션이 커밋됨
    // 만약 someDaoMethod1 또는 someDaoMethod2에서 예외가 발생하면, 트랜잭션은 롤백됨
}&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;2. 롤백 규칙의 이해 : @Transaction 어노테이션은 rollbackFor와 noRollbackFor 속성을 제공하여 특정 예외에 대한 롤백 동작을 정의할 수 있습니다. 롤백 규칙을 올바르게 설정하지 않으면 예기치 않은 동작이 발생할 수 있습니다.&amp;nbsp;&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;3. 프록시 기반 AOP의 이해 : Spring의 @Transactional은 프록시 기반의 AOP(Aspect Oriented Programming)를 사용합니다. 이 말은, 해당 어노테이션을 가진 메서드가 같은 클래스 내의 다른 메서드를 호출할 때는 트랜잭션이 적용되지 않는다는 것을 의미합니다.&amp;nbsp;&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;4. public 메서드에만 적용 : @Transactional 어노테이션은 public 메서드에만 적용해야 합니다. private, protected, package-private 메서드에 적용하면 어노테이션이 무시됩니다.&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;5. 성능 고려 : 트랜잭션은 리소스를 많이 사용하므로, 가능한 한 범위를 좁게 유지해야 합니다. 또한, 과도하게 트랜잭션 격리 수준을 유지하면 성능을 저하시킬 수 있으므로 적절한 격리 수준을 설정하는 것이 중요합니다.&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;6. propagation(트랜잭션 전파의 이해) : 올바른 설정을 통해 트랜잭션 전파 동작을 제어할 수 있어야 합니다.&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;7. 트랜잭션과 비즈니스 로직의 분리 : 트랜잭션의 관리는 서비스 계층에서 수행해야 하며, 비즈니스 로직은 도메인 계층에서 수행되어야 합니다. 이 두 가지를 혼동하면 코드가 복잡해질 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;//wcs.naver.net/wcslog.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
if(!wcs_add) var wcs_add = {};
wcs_add[&quot;wa&quot;] = &quot;194a7af0aa57bb0&quot;;
if(window.wcs) {
  wcs_do();
}
&lt;/script&gt;</description>
      <category>Backend</category>
      <category>AOP</category>
      <category>transaction</category>
      <category>스프링프레임워크</category>
      <category>어노테이션</category>
      <category>트랜잭션</category>
      <author>Michael Gary Scott</author>
      <guid isPermaLink="true">https://daniel6364.tistory.com/7</guid>
      <comments>https://daniel6364.tistory.com/entry/Java-Spring-Framework-Transactional#entry7comment</comments>
      <pubDate>Thu, 20 Jul 2023 17:06:26 +0900</pubDate>
    </item>
    <item>
      <title>@Transaction - isolation 격리 수준에 따른 세가지 현상</title>
      <link>https://daniel6364.tistory.com/entry/Transaction-isolation-%EA%B2%A9%EB%A6%AC-%EC%88%98%EC%A4%80%EC%97%90-%EB%94%B0%EB%A5%B8-%EC%84%B8%EA%B0%80%EC%A7%80-%ED%98%84%EC%83%81</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;pexels-rdne-stock-project-5530681.jpg&quot; data-origin-width=&quot;5281&quot; data-origin-height=&quot;3521&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clErnO/btson2mlYNe/EQHynsU6NxuYOdajljGTN1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clErnO/btson2mlYNe/EQHynsU6NxuYOdajljGTN1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clErnO/btson2mlYNe/EQHynsU6NxuYOdajljGTN1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclErnO%2Fbtson2mlYNe%2FEQHynsU6NxuYOdajljGTN1%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; alt=&quot;@Transaction - isolation 격리 수준에 따른 세가지 현상&quot; loading=&quot;lazy&quot; width=&quot;5281&quot; height=&quot;3521&quot; data-filename=&quot;pexels-rdne-stock-project-5530681.jpg&quot; data-origin-width=&quot;5281&quot; data-origin-height=&quot;3521&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Dirty Read&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;한 트랜잭션(T1)이 아직 커밋되지 않은 다른 트랜잭션(T2)에 의해 변경된 데이터를 읽는 현상을 말한다. 만약 T2가 롤백되면, T1이 읽은 데이터는 더 이상 유효하지 않게 됩니다. 이러한 현상을 방지하기 위해, 일반적으로 트랜잭션은 자신이 커밋되지 않은 다른 트랜잭션의 변경사항을 볼 수 없도록 격리됩니다.&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;2. Non-Repeatable Read&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;한 트랜잭션(T1) 내에서 동일한 쿼리를 두 번 실행했을 때, 그 사이에 다른 트랜잭션(T2)이 값을 변경하거나 삭제함으로써 두 쿼리의 결과가 서로 다르게 나오는 현상을 말합니다. 이를 방지하기 위해, 일반적으로 트랜잭션은 동일한 데이터에 대해 동시에 두 개 이상의 트랜잭션이 변경을 수행하지 못하도록 잠금을 설정하게 됩니다.&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;3. Phantom Read&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;한 트랜잭션(T1) 내에서 특정 범위의 행을 두 번 이상 읽을 때, 그 사이에 다른 트랜잭션(T2)이 그 범위에 새로운 행을 추가하거나 삭제함으로써 두 쿼리의 결과가 달라지는 현상을 말합니다. Non-Repeatable Read와 비슷하나, 이 경우는 범위 자체가 변경되는 문제입니다. 이를 방지하기 위해 일반적으로 트랜잭션 내에서 범위 잠금을 사용하여 특정 범위의 데이터를 보호하게 됩니다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;//wcs.naver.net/wcslog.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
if(!wcs_add) var wcs_add = {};
wcs_add[&quot;wa&quot;] = &quot;194a7af0aa57bb0&quot;;
if(window.wcs) {
  wcs_do();
}
&lt;/script&gt;</description>
      <category>Backend</category>
      <category>isolation</category>
      <category>transaction</category>
      <category>스프링프레임워크</category>
      <category>트랜잭션</category>
      <author>Michael Gary Scott</author>
      <guid isPermaLink="true">https://daniel6364.tistory.com/6</guid>
      <comments>https://daniel6364.tistory.com/entry/Transaction-isolation-%EA%B2%A9%EB%A6%AC-%EC%88%98%EC%A4%80%EC%97%90-%EB%94%B0%EB%A5%B8-%EC%84%B8%EA%B0%80%EC%A7%80-%ED%98%84%EC%83%81#entry6comment</comments>
      <pubDate>Thu, 20 Jul 2023 17:02:57 +0900</pubDate>
    </item>
    <item>
      <title>디자인 패턴 - 개방 폐쇄 원칙</title>
      <link>https://daniel6364.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EA%B0%9C%EB%B0%A9-%ED%8F%90%EC%87%84-%EC%9B%90%EC%B9%99</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;확장할 때는 개방, 수정할 때는 폐쇄&lt;/h2&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;p data-ke-size=&quot;size16&quot;&gt;코드 작성시 현재 코드에 앞으로 요구 사항이 추가될 가능성에 대해 더 많은 시간을 할애할 필요가 있다. 미리 설계해 확장 가능하도록 미리 구성하면, 코드의 전체 구조를 변경할 필요 없이 새로운 코드가 유연하게 추가되며, 코드 수정을 최소화하면서 요구 사항을 만족시킬 수 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&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;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;pexels-tranmautritam-326502.jpg&quot; data-origin-width=&quot;5184&quot; data-origin-height=&quot;3456&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nlsh7/btsnSX6DaOB/AQtHF6TfaM7Fzgka4tTiU0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nlsh7/btsnSX6DaOB/AQtHF6TfaM7Fzgka4tTiU0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nlsh7/btsnSX6DaOB/AQtHF6TfaM7Fzgka4tTiU0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fnlsh7%2FbtsnSX6DaOB%2FAQtHF6TfaM7Fzgka4tTiU0%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; alt=&quot;디자인 패턴 - 개방 폐쇄 원칙&quot; loading=&quot;lazy&quot; width=&quot;5184&quot; height=&quot;3456&quot; data-filename=&quot;pexels-tranmautritam-326502.jpg&quot; data-origin-width=&quot;5184&quot; data-origin-height=&quot;3456&quot;/&gt;&lt;/span&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;코드의 확장성은 코드의 품질을 판단하는 중요한 기준이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고전적인 디자인 패턴 22개 중 대부분은 코드 확장성의 문제를 해결하기 위한 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드의 확장성을 개선하기 위해 설계 원칙과 디자인 패턴에서 많이 사용되고 있는 방법은 &lt;i&gt;&lt;b&gt;다형성, 의존성 주입, 구현&lt;/b&gt;&lt;/i&gt;이 아닌 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;인터페이스 기반의 프로그래밍&lt;/b&gt;&lt;/span&gt;이 있다. 이는 전략 패턴, 템플릿 메서드 패턴, 책임 연쇄 패턴과 같은 대부분의 디자인 패턴에서 볼 수 있다.&amp;nbsp;&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;금융, 전자 상거리, 물류 시스템과 같은 비즈니스 시스템을 개발하는 경우 가능한한 많은 확장 포인트를 준비하기 위해 비즈니스에 대한 충분한 이해가 있어야 한다.&lt;/p&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;단기간 내에 진행할 수 있는 확장&lt;/li&gt;
&lt;li&gt;코드 구조 변경에 미치는 영향이 비교적 큰 확장&lt;/li&gt;
&lt;li&gt;구현 비용이 많이 들지 않는 확장에 대해 확장 포인트를 미리 준비하는 것&lt;/li&gt;
&lt;/ol&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://daniel6364.tistory.com/entry/%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99-single-responsibility-principle-SRP&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2023.07.27 - [Design Patterns] - 단일 책임 원칙 - single responsibility principle, SRP&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1690424856351&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;단일 책임 원칙 - single responsibility principle, SRP&quot; data-og-description=&quot;소개 객체지향 프로그래밍은 유지보수성과 재사용성으르 높이기 위해 다양한 설계 원칙을 제공합니다. 이 중에서도 '단일 책임 원칙'은 클래스나 모듈이 하나의 책임만을 가져야 한다는 원칙으&quot; data-og-host=&quot;daniel6364.tistory.com&quot; data-og-source-url=&quot;https://daniel6364.tistory.com/entry/%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99-single-responsibility-principle-SRP&quot; data-og-url=&quot;https://daniel6364.tistory.com/entry/%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99-single-responsibility-principle-SRP&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bgn8qJ/hyTqxYsxDJ/UE6StWzmZZnSNfqvmO8sOK/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/DR6hh/hyTrXOLJHf/pYhs4zBg3Qng64NmYEzxF0/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450&quot;&gt;&lt;a href=&quot;https://daniel6364.tistory.com/entry/%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99-single-responsibility-principle-SRP&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://daniel6364.tistory.com/entry/%EB%8B%A8%EC%9D%BC-%EC%B1%85%EC%9E%84-%EC%9B%90%EC%B9%99-single-responsibility-principle-SRP&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bgn8qJ/hyTqxYsxDJ/UE6StWzmZZnSNfqvmO8sOK/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/DR6hh/hyTrXOLJHf/pYhs4zBg3Qng64NmYEzxF0/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_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;단일 책임 원칙 - single responsibility principle, SRP&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;소개 객체지향 프로그래밍은 유지보수성과 재사용성으르 높이기 위해 다양한 설계 원칙을 제공합니다. 이 중에서도 '단일 책임 원칙'은 클래스나 모듈이 하나의 책임만을 가져야 한다는 원칙으&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;daniel6364.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;출처 : 디자인패턴의 아름다움&lt;/i&gt;&lt;/p&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;//wcs.naver.net/wcslog.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
if(!wcs_add) var wcs_add = {};
wcs_add[&quot;wa&quot;] = &quot;194a7af0aa57bb0&quot;;
if(window.wcs) {
  wcs_do();
}
&lt;/script&gt;</description>
      <category>Design Patterns</category>
      <category>개방폐쇄원칙</category>
      <category>디자인패턴</category>
      <author>Michael Gary Scott</author>
      <guid isPermaLink="true">https://daniel6364.tistory.com/5</guid>
      <comments>https://daniel6364.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EA%B0%9C%EB%B0%A9-%ED%8F%90%EC%87%84-%EC%9B%90%EC%B9%99#entry5comment</comments>
      <pubDate>Thu, 8 Jun 2023 17:24:31 +0900</pubDate>
    </item>
    <item>
      <title>디자인 패턴 - 팩토리 패턴(factory pattern)</title>
      <link>https://daniel6364.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%ED%8C%A9%ED%86%A0%EB%A6%AC-%ED%8C%A8%ED%84%B4factory-pattern</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;팩토리 패턴(&lt;code&gt;factory pattern&lt;/code&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;자바코드로 이해하기&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;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public interface Shape {
    void draw();
}

public class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println(&quot;Inside Rectangle :: draw() method.&quot;);
    }
}

public class Square implements Shape {
    @Override
    public void draw() {
        System.out.println(&quot;Inside Square :: draw() method.&quot;);
    }
}

public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println(&quot;Inside Circle :: draw() method.&quot;);
    }
}&lt;/code&gt;&lt;/pre&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;pexels-vojtech-okenka-392018.jpg&quot; data-origin-width=&quot;5184&quot; data-origin-height=&quot;3456&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/br9DDa/btsnGNKNorC/jxreWSdHdBoeJ0qnQtg29k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/br9DDa/btsnGNKNorC/jxreWSdHdBoeJ0qnQtg29k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/br9DDa/btsnGNKNorC/jxreWSdHdBoeJ0qnQtg29k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbr9DDa%2FbtsnGNKNorC%2FjxreWSdHdBoeJ0qnQtg29k%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; alt=&quot;디자인 패턴 - 팩토리 패턴&quot; loading=&quot;lazy&quot; width=&quot;5184&quot; height=&quot;3456&quot; data-filename=&quot;pexels-vojtech-okenka-392018.jpg&quot; data-origin-width=&quot;5184&quot; data-origin-height=&quot;3456&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;parameter를 통해 요청한 타입에 대한 클래스를 생성해서 리턴하는 것이 핵심&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1685670684938&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class ShapeFactory {
	public Shape getShape(String shapeType) {
    	if (shapeType == null) {
        	return null;
        }
        
        if (shapeType.equalsIgnoreCase(&quot;CIRCLE&quot;)) {
        	return new Circle();
        } else if (shapeType.equalsIgnoreCase(&quot;RECTANGLE&quot;)) {
        	return new Rectangle();
        } else if (shapeType.equalsIgnoreCase(&quot;SQUARE&quot;)) {
        	return new Square();
        } 
        
        return null;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 60px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 40px; text-align: center;&quot;&gt;확장성&lt;br /&gt;테스트 용이&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 40px; text-align: center;&quot;&gt;코드양 증가&lt;br /&gt;코드파악 난이도 증가&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;출처&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&lt;a href=&quot;https://jusungpark.tistory.com/14&quot;&gt;https://jusungpark.tistory.com/14&lt;/a&gt;&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=lINCOyvJo_M&quot;&gt;https://www.youtube.com/watch?v=lINCOyvJo_M&lt;/a&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=QOX10ntWj5Y&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.youtube.com/watch?v=QOX10ntWj5Y&lt;/a&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;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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;//wcs.naver.net/wcslog.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
if(!wcs_add) var wcs_add = {};
wcs_add[&quot;wa&quot;] = &quot;194a7af0aa57bb0&quot;;
if(window.wcs) {
  wcs_do();
}
&lt;/script&gt;</description>
      <category>Design Patterns</category>
      <category>Design Pattern</category>
      <category>Factory Pattern</category>
      <category>Java</category>
      <category>디자인패턴</category>
      <category>자바 디자인 패턴</category>
      <category>팩토리패턴</category>
      <author>Michael Gary Scott</author>
      <guid isPermaLink="true">https://daniel6364.tistory.com/4</guid>
      <comments>https://daniel6364.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%ED%8C%A9%ED%86%A0%EB%A6%AC-%ED%8C%A8%ED%84%B4factory-pattern#entry4comment</comments>
      <pubDate>Mon, 5 Jun 2023 17:10:08 +0900</pubDate>
    </item>
    <item>
      <title>인터페이스를 이해하는 다양한 방법</title>
      <link>https://daniel6364.tistory.com/entry/%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EB%A5%BC-%EC%9D%B4%ED%95%B4%ED%95%98%EB%8A%94-%EB%8B%A4%EC%96%91%ED%95%9C-%EB%B0%A9%EB%B2%95</link>
      <description>&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;li&gt;Java 1.8 이후부터는 인터페이스의 메서드에 코드 구현이 포함될 수 있으며, 인터페이스에 정적 멤버 변수가 포함될 수 있다.&lt;/li&gt;
&lt;li&gt;하지만, Java를 제외하면 인터페이스는 위의 특성을 그대로 간직하고 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;본질적으로 인터페이스는 프로토콜 또는 규약의 집합으로, 사용자에게 제공되는 기능의 목록이다.&amp;nbsp;&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;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;pexels-sora-shimazaki-5926393.jpg&quot; data-origin-width=&quot;5740&quot; data-origin-height=&quot;3827&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cm3VN8/btsnEL1AIny/J8kv8Jy62h859HVXt4zQCK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cm3VN8/btsnEL1AIny/J8kv8Jy62h859HVXt4zQCK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cm3VN8/btsnEL1AIny/J8kv8Jy62h859HVXt4zQCK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcm3VN8%2FbtsnEL1AIny%2FJ8kv8Jy62h859HVXt4zQCK%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; alt=&quot;인터페이스를 이해하는 다양한 방법&quot; loading=&quot;lazy&quot; width=&quot;5740&quot; height=&quot;3827&quot; data-filename=&quot;pexels-sora-shimazaki-5926393.jpg&quot; data-origin-width=&quot;5740&quot; data-origin-height=&quot;3827&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;불안정한 구현을 직접 노출하는 대신 캡슐화하여 감춤&lt;/li&gt;
&lt;li&gt;안정적인 인터페이스만 노출할 수 있기 때문&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;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;p data-ke-size=&quot;size18&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;size18&quot;&gt;추상화는 코드의 확장성, 유연성, 유지 보수성을 향상하는 효과적인 수단임&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출처 : 디자인&amp;nbsp;패턴의&amp;nbsp;아름다움&lt;/p&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;//wcs.naver.net/wcslog.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
if(!wcs_add) var wcs_add = {};
wcs_add[&quot;wa&quot;] = &quot;194a7af0aa57bb0&quot;;
if(window.wcs) {
  wcs_do();
}
&lt;/script&gt;</description>
      <category>Design Patterns</category>
      <category>인터페이스</category>
      <category>자바</category>
      <category>추상화</category>
      <author>Michael Gary Scott</author>
      <guid isPermaLink="true">https://daniel6364.tistory.com/3</guid>
      <comments>https://daniel6364.tistory.com/entry/%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EB%A5%BC-%EC%9D%B4%ED%95%B4%ED%95%98%EB%8A%94-%EB%8B%A4%EC%96%91%ED%95%9C-%EB%B0%A9%EB%B2%95#entry3comment</comments>
      <pubDate>Mon, 5 Jun 2023 14:35:55 +0900</pubDate>
    </item>
    <item>
      <title>메세지 큐(Message Queue)</title>
      <link>https://daniel6364.tistory.com/entry/%EB%A9%94%EC%84%B8%EC%A7%80-%ED%81%90Message-Queue</link>
      <description>&lt;h1&gt;메시지 큐(Message Queue)란?&lt;/h1&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;프로세스(프로그램) 간에 데이터를 교환할 때 사용하는 통신 방법 중에 하나로 더 큰 개념으로는 &lt;b&gt;MOM(Message Oriented Middleware : 메시지 지향 미들웨어 이하 MOM)&lt;/b&gt;을 의미&lt;/li&gt;
&lt;li&gt;MOM이란 비동기 메시지를 사용하는 프로그램 간의 데이터 송수신을 의미하는데 MOM을 구현한 시스템을 &lt;b&gt;MQ&lt;/b&gt;라고 한다. MQ는 작업을 늦출 수 있는 유연성을 제공한다.&lt;/li&gt;
&lt;li&gt;메시지를 교환할 때 &lt;b&gt;AMQP(Advanced Message Queuing Protocol 이하 AMQP)&lt;/b&gt;를 이용한다.&lt;/li&gt;
&lt;li&gt;AMQP는 ISO응용 계층의 MOM 표준으로 &lt;b&gt;JMS(Java Message Service)&lt;/b&gt;와 비교되는데 JMS는 MOM을 &lt;b&gt;자바에서 지원하는 표준 API&lt;/b&gt;다.&lt;/li&gt;
&lt;li&gt;JMS는 다른 Java Application 간에 통신은 가능하지만 다른 MOM(AMQP, SMTP 등)끼리는 통신할 수 없다.&lt;/li&gt;
&lt;li&gt;그에 반해 AMQP는 protocol만 일치한다면 다른 AMQP를 사용한 Application과도 통신이 가능하다. AMQP는 wire-protocol을 제공하는데 이는 octet stream을 이용해서 다른 네트워크 사이에 데이터를 전송할 수 있는 포맷이다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;메시지 큐의 장점&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비동기 : Queue에 넣기 때문에 나중에 처리할 수 있다.&lt;/li&gt;
&lt;li&gt;비동조 : Application과 분리할 수 있다.&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;h1&gt;메시지 큐의 사용처&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다른 곳의 API로부터 데이터 송수신&lt;/li&gt;
&lt;li&gt;다양한 Application에서 비동기 통신 가능&lt;/li&gt;
&lt;li&gt;이메일 발송 및 문서 업로드 가능&lt;/li&gt;
&lt;li&gt;많은 양의 프로세스 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;메시지 큐의 종류&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Kafka&lt;/li&gt;
&lt;li&gt;RabbitMQ&lt;/li&gt;
&lt;li&gt;ActiveMQ&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공통적으로 3가지 모두 비동기 통신을 제공하고 보낸 사람과 받는 사람을 분리한다. 하지만 업무에 따라서 다른 목적을 가지고 있다.&lt;/p&gt;
&lt;table style=&quot;height: 38px;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;th style=&quot;height: 19px;&quot;&gt;Kafka&lt;/th&gt;
&lt;th style=&quot;height: 19px;&quot;&gt;RabbitMQ, ActiveAQ(Apache)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;처리량이 많은 분산 메시징 시스템에 적합&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;신뢰성 있는 메시지 브로커가 필요한 경우 적합&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 여기서 신뢰성은 Kafka에 비해 높은 것이지 Kafka가 신뢰성이 없다는 것은 아니다.&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;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;pexels-markus-spiske-3991793.jpg&quot; data-origin-width=&quot;3500&quot; data-origin-height=&quot;2333&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/K4ic3/btsnK9fs4nQ/HWPE8ynIpBsFU0G46FnE01/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/K4ic3/btsnK9fs4nQ/HWPE8ynIpBsFU0G46FnE01/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/K4ic3/btsnK9fs4nQ/HWPE8ynIpBsFU0G46FnE01/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FK4ic3%2FbtsnK9fs4nQ%2FHWPE8ynIpBsFU0G46FnE01%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; alt=&quot;Message Queue&quot; loading=&quot;lazy&quot; width=&quot;3500&quot; height=&quot;2333&quot; data-filename=&quot;pexels-markus-spiske-3991793.jpg&quot; data-origin-width=&quot;3500&quot; data-origin-height=&quot;2333&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;메시지 큐 종류별 장점&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Kafka&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kafka는 확장성과 고성능 및 높은 처리량을 내세운 제품이다. 특화된 시스템이기 때문에 범용 메시징 시스템에서 제공하는 다양한 기능들은 제공되지 않는다. 분산 시스템을 기본으로 설계되었기 때문에 기존 메시징 시스템에 비해 분산 및 복제 구성을 손쉽게 할 수 있다.&lt;/p&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;AMQP 프로토콜이나 JSM API를 사용하지 않고 단순한 메시지 헤더를 지는 TCP기반 프로토콜을 사용함으로써 오버헤드가 비교적 작다.&lt;/li&gt;
&lt;li&gt;노드 장애에 대한 대응성을 가지고 있다.&lt;/li&gt;
&lt;li&gt;프로듀서는 각 메시지를 배치로 브로커에게 전달하여 TCP/IP 라운드 트립을 줄였다.&lt;br /&gt;(라운드 트립 : 클라이언트와 서버 간의 데이터 왕복 과정을 의미한다. 라운드 트립이 빈번하다는 것은 클라이언트와 서버 간에 요청과 응답이 빈번하다는 이야기이고, 결국 서버 측의 성능에 그리 좋지 않은 영향을 미친다. 따라서 라운드 트립이 적게 일어나도록 제작되는 것이 바람직하다.)&lt;/li&gt;
&lt;li&gt;메시지를 기본적으로 파일 시스템에 저장하여 별도의 설정을 하지 않아도 오료 발생 시 오류 지점부터 복구가 가능하다.&lt;br /&gt;(기존 메시징 시스템은 메시지를 메모리에 저장)&lt;/li&gt;
&lt;li&gt;메시지를 파일시스템에 저장하기 때문에 메시지가 많이 쌓여도 기존 메시징 시스템에 비해 성능이 크게 감소하지 않는다.&lt;/li&gt;
&lt;li&gt;window 단위의 데이터를 넣고 꺼낼 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. RabbitMQ&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RabbitMQ는 AMQP 프로토콜을 구현해 놓은 프로그램으로써 빠르고 쉽게 구성할 수 있으며 직관적이다.&lt;/p&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;br /&gt;(Message Queue가 도착하기 전에 라우팅 되며 플러그인을 통해 더 복잡한 라우팅도 가능)&lt;/li&gt;
&lt;li&gt;클러스터링&lt;br /&gt;(로컬네트워크에 있는 여러 RabbitMQ 서버를 논리적으로 클러스터링 할 수 있고 논리적인 중개인도 가능)&lt;/li&gt;
&lt;li&gt;관리 UI의 편리성&lt;br /&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;3. ActiveMQ&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ActiveMQ는 자바로 만든 오픈소스 메시지 브로커이다. JMS 1.1을 통해 자바뿐만 아니라 다른 언어를 사용하는 클라이언트를 지원한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다양한 언어와 프로토콜 지원(Java, C, C++, C#, Ruby, Perl, Python, PHP 클라이언트 지원)&lt;/li&gt;
&lt;li&gt;OpenWire를 통해 고성능의 Java, C, C++, C# 클라이언트 지원&lt;/li&gt;
&lt;li&gt;Stomp를 통해 C, Ruby, Perl, Python, PHP 클라이언트가 다른 인기있는 메시지 중개인들과 마찬가지로 ActiveMQ에 접근 가능&lt;/li&gt;
&lt;li&gt;Message Groups, Virtual Destinations, Wildcard와 Composite Destination을 지원&lt;/li&gt;
&lt;li&gt;Spring 지원으로 ActiveMQ는 Spring Application에 매우 쉽게 임베딩될 수 있으며, Spring의 XML 설정 메커니즘에 의해 쉽게 설정 가능&lt;/li&gt;
&lt;li&gt;Geronimo, JBoss 4, GlassFish, WebLogic과 같은 인기있는 J2EE 서버들과 함께 테스트됨&lt;/li&gt;
&lt;li&gt;고성능의 저널을 사용할 때에 JDBC를 사용하여 매우 빠른 Persistence를 지원&lt;/li&gt;
&lt;li&gt;REST API를 통해 웹기반 메시징 API를 지원&lt;/li&gt;
&lt;li&gt;웹 브라우저가 메시징 도구가 될 수 있도록, Ajax를 통해 순수한 DHTML(Dynamic HTML)을 사용한 웹 스트리밍 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;출처&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://steady-snail.tistory.com/165&quot;&gt;https://steady-snail.tistory.com/165&lt;/a&gt;&lt;/p&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;//wcs.naver.net/wcslog.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
if(!wcs_add) var wcs_add = {};
wcs_add[&quot;wa&quot;] = &quot;194a7af0aa57bb0&quot;;
if(window.wcs) {
  wcs_do();
}
&lt;/script&gt;</description>
      <category>Backend</category>
      <category>ActiveMQ</category>
      <category>Kafka</category>
      <category>messagequeue</category>
      <category>mq</category>
      <category>rabbitmq</category>
      <category>메세지큐</category>
      <category>카프카</category>
      <author>Michael Gary Scott</author>
      <guid isPermaLink="true">https://daniel6364.tistory.com/2</guid>
      <comments>https://daniel6364.tistory.com/entry/%EB%A9%94%EC%84%B8%EC%A7%80-%ED%81%90Message-Queue#entry2comment</comments>
      <pubDate>Mon, 27 Mar 2023 14:43:15 +0900</pubDate>
    </item>
  </channel>
</rss>