<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Lee's Grow up</title>
    <link>https://lee1535.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sat, 11 Apr 2026 23:25:09 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>효기로그</managingEditor>
    <item>
      <title>[CodingConvention] Google Java Coding Style 정리</title>
      <link>https://lee1535.tistory.com/146</link>
      <description>&lt;p&gt;구글에서 제공해주는 자바 코딩 스타일 가이드에 대한 정리입니다.&lt;a href=&quot;https://google.github.io/styleguide/javaguide.html#s2.3-special-characters&quot;&gt;원문&lt;/a&gt;&lt;br /&gt;해당 내용은 작성일 기준 문서의 내용을 정리한 것 입니다.&lt;/p&gt;
&lt;h2&gt;소스파일&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;이름 : 포함하고 있는 최상위 레벨의 대소문자 구분되는 이름으로 이루어집니다.&lt;/li&gt;
&lt;li&gt;확장자 : &lt;code&gt;.java&lt;/code&gt; 확장자를 사용합니다.&lt;/li&gt;
&lt;li&gt;인코딩 : UTF-8&lt;/li&gt;
&lt;li&gt;ASCII(0x20)은 유일한 공백 문자이며, 탭 문자는 공백에 사용하지 않습니다.&lt;/li&gt;
&lt;li&gt;모든 특수 문자를 사용할 때 이스케이프 시퀀스 (\b, \w 등)을 사용하며, 그 문자의 진수, 유니코드는 사용하지 않습니다.&lt;/li&gt;
&lt;li&gt;비 ASCII문자는 유니코드를 사용하고, 주석으로 설명해도 무방합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;소스파일 구조&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;소스 파일은 다음 순서로 구성됩니다. 각 객션 간에는 &lt;b&gt;공백 라인이 하나&lt;/b&gt; 들어가야 합니다.
&lt;ol&gt;
&lt;li&gt;라이센스 또는 저작권 정보 ( 있는 경우 )&lt;/li&gt;
&lt;li&gt;패키지 명세서&lt;/li&gt;
&lt;li&gt;import문&lt;/li&gt;
&lt;li&gt;최상의 클래스&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Pacakge 문&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;이름은 소문자로 작성합니다.&lt;/li&gt;
&lt;li&gt;패키지문은 아무리 길어도 한 문장으로 써야합니다. 줄 바꿈 되지 않습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Import 문&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;정적이든 비정적이든 &lt;b&gt;와일드 카드&lt;/b&gt;(*)는 사용하지 않습니다.&lt;/li&gt;
&lt;li&gt;순서
&lt;ul&gt;
&lt;li&gt;단일 블록에서 모든 정적&lt;/li&gt;
&lt;li&gt;단일 블록의 모든 비 정적&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;정적과 비정적 사이에만 빈 줄이 있고, 다른 import 문 사이에는 다른 빈 줄이 없습니다.&lt;/li&gt;
&lt;li&gt;각 블록 내에서의 이름은 ASCII 정렬 순서로 나타냅니다.&lt;/li&gt;
&lt;li&gt;정적 중첩 클래스에는 정적 import가 사용되지 않습니다. 일반 import를 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Class&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;대문자로 시작하며, UpperCamelCase를 사용하며, 명사 또는 명사구입니다. 인터페이스는 명사 또는 명사구 또는 형용사 형용사구가 될 수 있습니다.&lt;/li&gt;
&lt;li&gt;테스트 클래스의 경우 Test를 붙입니다. &lt;code&gt;HashTest&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;클래스 멤버의 순서는 절대적인 것은 없습니다. 다만 순서가 논리적이여야 합니다. 가령 새로운 메소드가 추가되었다고 해서 클래스의 가장 마지막에 구현되는 것은 논리적이지 않습니다.&lt;/li&gt;
&lt;li&gt;Class에 여러 생성자 또는 동일한 이름을 가진 여러 메서드가 있는 경우 사이에 다른 코드 없이 순차적으로 나타냅니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Method&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;lowCamelCase를 사용합니다.&lt;/li&gt;
&lt;li&gt;동사구입니다.&lt;/li&gt;
&lt;li&gt;JUnit 테스트 메서드 이름의 경우 _ 뒤엔 lowCamelCase를 따릅니다 `_ pop_emptyStack&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;상수&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;상수는 CONSTANT_CASE 구분은 밑줄로 모든 단어는 대문자로 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;필드&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;lowerCamelCase를 사용합니다.&lt;/li&gt;
&lt;li&gt;고용ㅇ 메소드에서 사용한 변수 이름은 피해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;지역 변수&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;lowerCamelCase를 사용합니다.&lt;/li&gt;
&lt;li&gt;절대로 상수로 지정해서는 안됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;유형 변수 이름&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;임의의 단일 대문자 T, E, X 또는 클래스 이름 + T , RequestT, FooT, BarT&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;포메팅&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;들여쓰기는 2space를 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;블록 {}&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;빈 블록의 경우&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;블록 문은 내용이 비어있거나, 단 하나의 문이 포함된 경우에도 사용한다.(if, else, for, do, while )&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;다중 블록이 아닌 경우, 블록({}) 사이에 문자나 줄 바꿈 없이 열린 직후 닫을 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;// 단일 블록은 둘 다 사용 가능
void doNothing() {} 
void doNothingElse() {
}
// 다중 블록은 사용 불가
try {
  doSomething();
} catch (Esception e) {} &lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;비어있지 않은 블록의 경우&amp;nbsp;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;여는 중괄호 앞에는 줄 바꿈이 없습니다.&lt;/li&gt;
&lt;li&gt;여는 중괄호 뒤의 줄 바꿈&lt;/li&gt;
&lt;li&gt;닫는 중괄호 앞의 줄바꿈&lt;/li&gt;
&lt;li&gt;닫는 중괄호 뒤의 줄바꿈 단, 중괄호가 명령문을 종료하거나, 메서드 , 생성자 또는 클래스의 본문을 종료하는 경우에는 줄바꿈이 없습니다. 예를들어 &lt;code&gt;; ( semicolon)&lt;/code&gt; 또는, &lt;code&gt;else&lt;/code&gt; 문&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;세로 공백&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;각 문 뒤에는 줄 바꿈이 있습니다. ( 한 줄에 하나의 문 )&lt;/li&gt;
&lt;li&gt;열 제한은 100자 입니다. 단 javadoc의 긴 ULR 또는 긴 JSNI 메소드 참조나, pacakge 문, import 문은 예외입니다.&lt;/li&gt;
&lt;li&gt;연속 줄바꿈인 경우 4space 의 indent를 사용합니다.&lt;/li&gt;
&lt;li&gt;세로 공백은 하나의 빈줄을 사용합니다. 여러 개의 빈 줄이 허용되지만 권장은 아닙니다.
&lt;ul&gt;
&lt;li&gt;클래스의 필드, 생성자, 메소드, 중첩 클래스, 정적 초기화 및 인스턴스 사이에 공백이 들어갑니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;두 개의 연속된 필드에 빈줄은 논리적은 그룹을 만드는데 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;가로 공백&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;if, for, catch 다음에 오는 '(' 사이에 공백문자&lt;/li&gt;
&lt;li&gt;else 또는 catch 이전에 오는 '}' 사이에 공백 문자&lt;/li&gt;
&lt;li&gt;여는 중괄호 '{' 앞에 공백
&lt;ul&gt;
&lt;li&gt;단 어노테이션의 경우 공백 사용하지 않음 @SomeAnnotation({a, b})&lt;/li&gt;
&lt;li&gt;배열의 경우 선택 사항 new int[] {5, 6} 또는 new int90 { 5, 6 }&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이항 또는 삼항 연산자에서
&lt;ul&gt;
&lt;li&gt;&amp;lt;T extends Foo &amp;amp; Bar&amp;gt;&lt;/li&gt;
&lt;li&gt;예외 catch 블록에 대한 파이프 : catch (Exception | BarException e)&lt;/li&gt;
&lt;li&gt;확장된 for문에서 ' : '&lt;/li&gt;
&lt;li&gt;람다 식의 화살표 ' -&amp;gt; '&lt;/li&gt;
&lt;/ul&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;h2&gt;수평 정렬&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;수평 정렬은 사용하지 않습니다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;// 맞는 사용
private int a;
private String b;

// 틀린 사용  
private int a;  
private String b
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Enum 클래스&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;열거 형 상수 뒤에 오는 각 쉼표 뒤에 줄 바꿈은 선택사항, 추가 빈줄도 허용합니다.&lt;/p&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;  private enum Answer {  
  YES {  
    @Override public String toString() {  
    return &quot;yes&quot;;  
    }  
  },

  NO,
  MAYBE&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;배열처럼 사용 가능합니다.&lt;/p&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;  private enum Suit { CLUBS, HEARTS, SPADES, DIAMONDS }
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;변수 선언&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;선언 당 변수 하나, int a, b; 는 허용되지 않습니다.
&lt;ul&gt;
&lt;li&gt;단 for 루프 헤더에 여러 변수 선언은 허용됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;시작 부분에 습관적으로 선언하지 않고, 필요할 때 선언하며, 필요한 지점에 가깝게 선언해 범위를 최소화 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;배열 선언&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;블록처럼 사용 가능합니다. 아래는 모두 가능합니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;new int[] {  
0, 1, 2, 3  
}

new int[] {  
0,  
1,  
2,  
3  
}

new int[] {  
0, 1,  
2, 3  
}

new int[]  
{0, 1, 2, 3}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;스타일 배열 선언을 사용하지 않습니다. &lt;code&gt;String[] args&lt;/code&gt; 는 가능 &lt;code&gt;String args[]&lt;/code&gt;는 사용 금지&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;스위치문&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;들여쓰기는 2spaces를 사용합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;default를 작성합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;break, continue, return이 없는 경우 &lt;code&gt;// fall through&lt;/code&gt; 주석 사용&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;
switch (input) {  
case 1:  
case 2:  
prepareOneOrTwo();  
// fall through  
case 3:  
handleOneTwoOrThree();  
break;  
default:  
handleLargeNumber(input);  
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;어노테이션&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;클래스, 메서드 또는 생성자의 주석은 문서 블록 바로 뒤에 나타나며, 각 주석은 1줄을 사용하며 들여쓰기를 사용하지 않습니다. 단 매개변수가 없는 단일 주석인 경우 한줄에 표현이 가능합니다. 필드에 적용되는 주석의 경우 한줄로 나열 될 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;
@Override  
@Nullable  
public String getNameIfPresent() { ... }

## 가능
@Override public int hashCode() { ... }

## 가능
@Partial @Mock DataLoader loader;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;매개변수, 지역변수, 타입에대한 어노테이션은 규칙은 없습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Modifiers 순서&lt;/h2&gt;
&lt;p&gt;public protected private abstract default static final transient volatile synchronized native strictfp&lt;/p&gt;
&lt;h2&gt;숫자 리터럴&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;long의 경우 대문자 접미사를 사용합니다. 숫자 1과 혼동을 피하기 위해&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;네이밍&lt;/h2&gt;
&lt;p&gt;아스키 코드나 숫자만 허용하며 prefixes 또는 suffixes를 사용하지 않습니다. not use &lt;code&gt;mName, KName&lt;/code&gt; 등&lt;/p&gt;
&lt;h2&gt;Override 어노테이션&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;생략하지 않습니다.단 부모 메소드가 @Deprecated인 경우 생략할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;예외&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;catch 블록은 무조건 액션을 취합니다. 다만 테스트 케이스일 경우 생략 가능합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;정적 멤버&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;클래스 이름으로 접근합니다. 인스턴스 명으로 접근하는건 잘못 된 예시입니다.
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;Foo aFoo = ....  
Foo.aStaticMethod() // OK  
aFoo.aStaticMethod() // bad&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Finalizers 사용 금지&lt;/h2&gt;
&lt;h2&gt;Javadocs 필수가 아닙니다. 필요시 문서 참조&lt;/h2&gt;</description>
      <category>Agile</category>
      <category>google style guide</category>
      <category>자바</category>
      <category>코딩가이드</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/146</guid>
      <comments>https://lee1535.tistory.com/146#entry146comment</comments>
      <pubDate>Tue, 8 Dec 2020 16:54:35 +0900</pubDate>
    </item>
    <item>
      <title>[Python/파이썬] 제어 - 조건문, 반복문 / if, for, while</title>
      <link>https://lee1535.tistory.com/141</link>
      <description>&lt;p&gt;해당 내용은 &lt;code&gt;Pythone&lt;/code&gt; 공식 문서를 참조하여 작성하였습니다. 작성 기준 버전은 &lt;code&gt;3.8.6&lt;/code&gt;입니다.&lt;/p&gt;
&lt;p&gt;공식문서 : &lt;a href=&quot;https://docs.python.org/3/tutorial/index.html&quot;&gt;docs.python.org/3/tutorial/index.html&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;1. if 문&lt;/h2&gt;
&lt;hr&gt;
&lt;p&gt;파이썬도 타 언어와 마찬가지로 조건을 판단하기 위해 if 문법을 제공해준다. 기본문법은 아래와 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;x = int(input(&amp;quot;Enter Integer : &amp;quot;))

if x % 2 == 0:
    print(&amp;quot;even&amp;quot;)
else:
    print(&amp;quot;odd&amp;quot;)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;내용은 입력 받은 값을 단순하게 홀수냐, 짝수이냐 판별해주는 조건문이다.&lt;br&gt;파이썬은 조건문 뒤에 &lt;code&gt;:&lt;/code&gt;을 붙이며, 수행할 코드를 들여쓰기로 구분해줘야한다 ( 띄어쓰기 4칸 또는 tab )&lt;br&gt;해당 규칙을 지키지 않으면 SyntaxError가 발생한다.&lt;br&gt;위 내용을 조건부 표현식으로 가독성 좋게 아래와 같이 표현이 가능하다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;x = int(input(&amp;quot;Enter Integer : &amp;quot;))
print(&amp;quot;even&amp;quot;) if x % 2 == 0 else print(&amp;quot;odd&amp;quot;)&lt;/code&gt;&lt;/pre&gt;&lt;h5&gt;다중 조건&lt;/h5&gt;
&lt;p&gt;위 예제에서는 조건이 참이냐, 거짓이냐 2가지로만 판별 가능하다. 파이썬도 타 언어와 마찬가지로 다중 조건을 줄 수 있으며, 키워드로는 &lt;code&gt;elif&lt;/code&gt;를 사용한다. else if의 줄임말이다. 이는 파이썬이 지향하는 간결한 문법이며 과도한 들여 쓰기를 방지해 가독성을 향상 시켰다고 문서는 말한다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;menu = int(input(&amp;quot;Select Menu 1. 아메리카노, 2. 라떼, 3. 카페모카 (번호로 선택 ): &amp;quot;))

if menu ==  1:
    print(&amp;quot;아메리카노&amp;quot;)
elif menu == 2:
    print(&amp;quot;라떼&amp;quot;)
elif menu == 3:
    print(&amp;quot;카페모카&amp;quot;)
else:
    print(&amp;quot;없는 메뉴입니다.&amp;quot;)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;또한, &lt;code&gt;elif&lt;/code&gt;로 대체가 가능하기 때문에 타 언어처럼 &lt;code&gt;switch&lt;/code&gt;문이 존재하지 않는다.&lt;br&gt;번외로 조건이 너무 길어지면, 가독성이 안좋아 지기 때문에 아래처럼 딕셔너리를 활용한 사용도 가능하다. 결과는 동일하다&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def switch(menu):
    return {1:&amp;quot;아메리카노&amp;quot;, 2:&amp;quot;라떼&amp;quot;, 3:&amp;quot;카페모카&amp;quot;}.get(menu,&amp;quot;없는 메뉴입니다.&amp;quot;)

print(switch(4))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;이러한 조건문에서 사용되는 비교 연산자는 ( &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;==&lt;/code&gt;, &lt;code&gt;!=&lt;/code&gt;, &lt;code&gt;&amp;lt;=&lt;/code&gt;, &lt;code&gt;&amp;gt;=&lt;/code&gt; )가 있으며 조건을 판단하는 연산자로는 ( &lt;code&gt;and&lt;/code&gt;, &lt;code&gt;or&lt;/code&gt;, &lt;code&gt;not&lt;/code&gt; )가 있다.&lt;/p&gt;
&lt;p&gt;마지막으로 &lt;code&gt;리스트&lt;/code&gt;, &lt;code&gt;튜플&lt;/code&gt;, &lt;code&gt;문자열&lt;/code&gt;, &lt;code&gt;딕셔너리&lt;/code&gt;인 경우 &lt;code&gt;in&lt;/code&gt; 키워드를 통해 조건문을 쉽게 작성할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;x = int(input(&amp;quot;Select Menu 1. 아메리카노, 2. 라떼, 3. 카페모카 (번호로 선택 ):&amp;quot;))
menu = {1:&amp;quot;아메리카노&amp;quot;, 2:&amp;quot;라떼&amp;quot;, 3:&amp;quot;카페모카&amp;quot;};
if x in menu:
    print(menu[x])
else:
    print(&amp;quot;없는 메뉴입니다.&amp;quot;)&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;for 문&lt;/h2&gt;
&lt;hr&gt;
&lt;p&gt;반복을 위한 구문입니다. 기본적으로 &lt;code&gt;for&lt;/code&gt; 와 &lt;code&gt;in&lt;/code&gt; 키워드를 사용하며 아래와 같은 기본 구조를 가집니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for w in words : print(w)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;일련의 숫자를 반복해야 하는 경우 &lt;code&gt;range()&lt;/code&gt; 내장함수를 같이 사용합니다.&lt;br&gt;  3개의 인수를 넘겨줄 수 있으며, 각각 시작 값, 종료 값, 단계로 구분됩니다. 인수로 음수도 가능합니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;range(5, 10) # 5, 6, 7, 8, 9
range(0, 10, 3) # 0, 3, 6, 9
range(-10, -100, -30) # -10, -40, -70&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;다만 &lt;code&gt;range()&lt;/code&gt;를 통해 반환된 객체는 &lt;code&gt;list&lt;/code&gt;처럼 동작하지만, 실제론 리스트가 아니기 때문에, 공간을 절약할 수 있습니다. 그래서 때로는 &lt;code&gt;enumerate()&lt;/code&gt; 기능을 사용하는 것이 편리합니다.&lt;/p&gt;
&lt;p&gt;  &lt;code&gt;ranage()&lt;/code&gt;가 반환해주는 객체를 반복 가능하다고 표현하며, 반복 가능한 함수에서 바로 사용 가능합니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sum(range(5))  # 0 + 1 + 2 + 3 + 4 &lt;/code&gt;&lt;/pre&gt;&lt;p&gt;리스트로 만들기 위해선 아래와 같이 사용합니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;list(range(5)) # [0, 1, 2, 3, 4]&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;반복문은 리스트 안에 사용(List comprehension)이 가능합니다. 또한 리스트 내포에는 조건문도 사용 가능합니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;numbers = [1, 2, 3, 4, 5]
odd = [num for num in numbers if num % 2 != 0]&lt;/code&gt;&lt;/pre&gt;&lt;h5&gt;break, continue, else&lt;/h5&gt;
&lt;p&gt;파이썬은 반복문에서도 &lt;code&gt;else&lt;/code&gt; 키워드가 사용 가능합니다. &lt;code&gt;else&lt;/code&gt; 구문의 실행문장은 &lt;code&gt;break&lt;/code&gt;문에 의해서 루프가 종료되는 경우에는 실행하지 않습니다. 아래와 같이 사용 가능합니다. ( 소수 판별 )&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for n in range(2, 10):
    for x in range(2, n):
        if n % x == 0:
            print(n, &amp;#39;equals&amp;#39;, x, &amp;#39;*&amp;#39;, n // x)
            break
    else:
        print(n, &amp;#39;is a prime number&amp;#39;)
# 2 is a prime number
# 3 is a prime number
# 4 equals 2 * 2
# 5 is a prime number
# 6 equals 2 * 3
# 7 is a prime number
# 8 equals 2 * 4
# 9 equals 3 * 3&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;continue&lt;/code&gt;는 &lt;code&gt;break&lt;/code&gt;문처럼 반복문 전체를 탈출하는게 아닌, 다음 요소로 넘어갈 때 사용하는 키워드입니다.&lt;/p&gt;
&lt;h2&gt;while 문&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;while&lt;/code&gt;도 &lt;code&gt;for&lt;/code&gt; 처럼 반복문으로 사용됩니다. 조건이 참일 경우 반복하는 반복문입니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;a = 0
result = 0
while a &amp;lt; 10:
    result += a
    a += 1
print(&amp;quot;sum :&amp;quot;, result)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;마찬가지로 &lt;code&gt;break&lt;/code&gt;,&lt;code&gt;continue&lt;/code&gt;를 사용할 수 있습니다. &lt;/p&gt;</description>
      <category>PROGRAMMING/Python</category>
      <category>FOR</category>
      <category>Python</category>
      <category>While</category>
      <category>반복문</category>
      <category>제어문</category>
      <category>조건문</category>
      <category>파이썬</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/141</guid>
      <comments>https://lee1535.tistory.com/141#entry141comment</comments>
      <pubDate>Tue, 6 Oct 2020 13:35:24 +0900</pubDate>
    </item>
    <item>
      <title>[자바/Java] Optional 개념, 사용</title>
      <link>https://lee1535.tistory.com/139</link>
      <description>&lt;p&gt;해당 내용은 책 &lt;code&gt;모던 자바 인 액션&lt;/code&gt;의 내용을 참고해서 작성하였습니다.&lt;/p&gt;
&lt;h2&gt;등장 배경&lt;/h2&gt;
&lt;p&gt;Java를 통해 개발을 진행하다 보면, 해당 객체의 참조 값이 &lt;code&gt;null&lt;/code&gt;인지 아닌지 체크하는 분기문이 생기는데, 이와 같은 분기문의 경우 코드의 가독성이 떨어지고, 해당 객체가 &lt;code&gt;null&lt;/code&gt;을 가질 수 있는 객체인지, 필수 값인지 직관적으로 알 수 있는 방법이 없어서 에러의 근원이 되는 문제가 발생했기 때문에, 선택형값을 캡슐화하는 클래스 &lt;code&gt;Optional&lt;/code&gt;을 Java 8에 추가되었다.&lt;/p&gt;
&lt;h2&gt;Optional 객체 만들기&lt;/h2&gt;
&lt;h5&gt;1. 빈 Optional 객체 만들기&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;Optionl&lt;/code&gt; 클래스의 정적 팩토리 메소드로 아래와 같이 사용 가능&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Optional&amp;lt;String&amp;gt; optStr = Optional.empty();&lt;/code&gt;&lt;/pre&gt;&lt;h5&gt;2. null이 아닌 값으로 Optional 만들기&lt;/h5&gt;
&lt;p&gt;만약 값이 null이라면 바로 &lt;code&gt;NullPointException&lt;/code&gt;이 발생하며, 값을 항상 넘겨줘야 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Optional&amp;lt;String&amp;gt; optStr = Optional.of(&amp;quot;not null&amp;quot;);&lt;/code&gt;&lt;/pre&gt;&lt;h5&gt;3. null 허용 Optional 만들기&lt;/h5&gt;
&lt;p&gt;null또는 값을 가질 수 있는 Optional을 리턴해준다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Optional&amp;lt;String&amp;gt; optStr = Optional.ofNullable(null);&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Optional 클래스의 메서드&lt;/h2&gt;
&lt;p&gt;예제를 위해 사용되는 클래스는 아래와 같다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class Person {

    private Car car;
    private int age;

    public Optional&amp;lt;Car&amp;gt; getCar(){ return Optional.ofNullable(car); }
    public int getAge() { return age; }
}

public class Insurance {

    private String name;

    public String getName() { return name; }
}

public class Car {

    private Insurance insurance;

    public Optional&amp;lt;Insurance&amp;gt; getInsurance(){ return Optional.ofNullable(insurance); }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;위와 같은 도메인 모델이 구성되어 있을 때, &lt;code&gt;Car&lt;/code&gt;을 기준으로 보면 &lt;code&gt;getCar&lt;/code&gt;은 Optional을 리턴하고 &lt;code&gt;getAge&lt;/code&gt;는 int형을 리턴해준다. 이렇게 한눈으로 값이 꼭 있어야 하는지, null이 들어갈 수 있는 객체인지 여부를 구체적으로 표현할 수 있는 장점이 있게된다. 또 특이한점은 필드로 옵셔널 객체 즉 &lt;code&gt;private Optional&amp;lt;Car&amp;gt; car&lt;/code&gt; 과 같은 방식을 사용하지 않은 이유는 해당 클래스를 설계한 사람이 용도를 선택형 반환값으로 구분을 지었기 때문에 &lt;code&gt;Serializable&lt;/code&gt;를 구현하지 않았다. 그래서 직렬화가 필요한 프레임워크나, 도구에서 문제가 생길 수가 있기 때문이다.&lt;/p&gt;
&lt;h5&gt;메서드의 종류&lt;/h5&gt;
&lt;h5&gt;1. empty, of, ofNullable&lt;/h5&gt;
&lt;p&gt;Optional 인스턴스를 반환 각각 빈 옵셔널, 널이 아닌 옵셔널, 널을 허용하는 옵셔널 ( 위에 설명이 있기 때문에 생략 )&lt;/p&gt;
&lt;h5&gt;2. filter&lt;/h5&gt;
&lt;p&gt;마치 스트림처럼 피리디케이트와 일치하면 값을 포함한 &lt;code&gt;Optional&amp;lt;T&amp;gt;&lt;/code&gt;을 리턴, 없으면 &lt;code&gt;empty&lt;/code&gt; 옵셔널을 리턴해준다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Optional.of(new Person()).optPerson.filter(p -&amp;gt; p.getAge() &amp;gt; 19);&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;위와 같이 사용가능하며, 나이가 19세를 넘어가는 Person인지 필터가 가능하다.&lt;/p&gt;
&lt;h5&gt;3. map&lt;/h5&gt;
&lt;p&gt;스트림과 비슷하며, 존재하면 값이 존재하면 매핑 함수를 적용&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Optional&amp;lt;String&amp;gt; name = 
                Optional.of(new Insurance()).map(Insurance::getName);

Optional&amp;lt;Optional&amp;lt;Car&amp;gt;&amp;gt; optCar = 
                Optional.of(new Person()).map(Person::getCar);&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;2개의 &lt;code&gt;map&lt;/code&gt;을 사용했으며, &lt;code&gt;optCar&lt;/code&gt;의 경우 반환 타입이 옵셔널 안에 옵셔널이 감싸지는 형태로 리턴이 된다. 이유는 &lt;code&gt;Optional.map&lt;/code&gt; 자체가 해당 값을 옵셔널로 감싸주는 메서드인데, &lt;code&gt;Person.getCar&lt;/code&gt;의 경우 리턴 타입이 &lt;code&gt;Optional&amp;lt;Car&amp;gt;&lt;/code&gt;이기 때문이다. 이와 같은 문제로 인해, 바로 아래 &lt;code&gt;flatMap&lt;/code&gt; 메서드를 제공해준다.&lt;/p&gt;
&lt;h5&gt;4. flatMap&lt;/h5&gt;
&lt;p&gt;스트림과 비슷, 평면화를 위해 사용. 값이 존재하면 제공된 함수를 적용한 결과를 값을 포함한 &lt;code&gt;Optional&amp;lt;T&amp;gt;&lt;/code&gt;을 리턴, 없으면 &lt;code&gt;empty&lt;/code&gt; 옵셔널을 리턴해준다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Optional&amp;lt;Insurance&amp;gt; optInsurancer = 
                Optional.of(new Person())
                        .flatMap(Person::getCar)
                        .flatMap(Car::getInsurance);&lt;/code&gt;&lt;/pre&gt;&lt;h5&gt;5. get&lt;/h5&gt;
&lt;p&gt;Optional이 감싸고 있는 값을 반환하고, 값이 없으면 &lt;code&gt;NoSuchElementException&lt;/code&gt; 발생&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Optional.empty().get();&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;위에는 빈 옵셔널에 &lt;code&gt;get&lt;/code&gt;메서드를 호출하기 때문에 &lt;code&gt;NoSuchElementException&lt;/code&gt;이 발생한다.&lt;/p&gt;
&lt;h5&gt;6. isPresent&lt;/h5&gt;
&lt;p&gt;값이 존재하면 true, 빈 옵셔널이면 false&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Optional.ofNullable(null).isPresent();
Optional.ofNullable(&amp;quot;not null&amp;quot;).isPresent();&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;위 첫번 째 결과는 &lt;code&gt;false&lt;/code&gt;, 두번째는 &lt;code&gt;true&lt;/code&gt;를 반환&lt;/p&gt;
&lt;h5&gt;7. ifPresent ,ifPresentOrElse&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;ifPresent&lt;/code&gt;의 경우 값이 존재하면 지정된 &lt;code&gt;Consumer&lt;/code&gt;를 실행하고, 없으면 아무동작도 안함&lt;br&gt;  &lt;code&gt;ifPresentOrElse&lt;/code&gt;은 java 9에 추가 되었으며, 추가로 &lt;code&gt;Runnable&lt;/code&gt; 인터페이스를 넘겨준다. 값이 존재하면 지정된 &lt;code&gt;Consumer&lt;/code&gt;를 실행하고, 값이 없으면 넘겨받은 &lt;code&gt;Runnable&lt;/code&gt;를 실행&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 첫번째 실행 안하고 not null만 출력
Optional.ofNullable(null).ifPresent(System.out::println);
Optional.ofNullable(&amp;quot;not null&amp;quot;).ifPresent(System.out::println);

// 무언가동작, not null 2개의 문장 출력
Optional.ofNullable(null).ifPresentOrElse(System.out::println, () -&amp;gt; System.out.println(&amp;quot;무언가 동작&amp;quot;));
Optional.ofNullable(&amp;quot;not null&amp;quot;).ifPresentOrElse(System.out::println, () -&amp;gt; System.out.println(&amp;quot;무언가 동작&amp;quot;));
&lt;/code&gt;&lt;/pre&gt;&lt;h5&gt;8. or&lt;/h5&gt;
&lt;p&gt;값이 존재하면 같은 &lt;code&gt;Optional&amp;lt;T&amp;gt;&lt;/code&gt;을 리턴, 없으면 &lt;code&gt;Supplier&lt;/code&gt;에서 만든 &lt;code&gt;Optional&amp;lt;T&amp;gt;&lt;/code&gt;을 리턴&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Optional.ofNullable(null).or(() -&amp;gt;(Optional.of(&amp;quot;UnKnown&amp;quot;)));
Optional.ofNullable(&amp;quot;not null&amp;quot;).or(() -&amp;gt;(Optional.of(&amp;quot;UnKnown&amp;quot;)));&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;각각 &lt;code&gt;Optional&amp;lt;String&amp;gt;&lt;/code&gt;를 리턴해주며, 첫번째는 &amp;quot;UnKnown&amp;quot;이라는 값을 가진 옵셔널을 두번째는 &amp;quot;not null&amp;quot;이란 값을 가진 옵서녈을 리턴해준다.&lt;/p&gt;
&lt;h5&gt;9. orElse&lt;/h5&gt;
&lt;p&gt;값이 존재하면 값을 리턴, 없으면 인자로 제공된 기본값을 반환&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Optional.ofNullable(null).orElse(&amp;quot;UnKnown&amp;quot;);&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;or&lt;/code&gt; 메서드와 다르게 바로 값을 반환해주며 해당 예제는 String 타입의 &amp;quot;UnKnown&amp;quot;을 리턴해준다&lt;/p&gt;
&lt;h5&gt;10. orElseGet&lt;/h5&gt;
&lt;p&gt;값이 존재하면 값을 리턴, 없으면 &lt;code&gt;Supplier&lt;/code&gt;에서 제공되는 값을 반환&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Optional.ofNullable(null).orElseGet(() -&amp;gt; new String(&amp;quot;UnKnown&amp;quot;));&lt;/code&gt;&lt;/pre&gt;&lt;h5&gt;11.orElseThrow&lt;/h5&gt;
&lt;p&gt;값이 존재하면 값을 리턴, 없으면 &lt;code&gt;Supplier&lt;/code&gt;에서 생성한 예외를 발생&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Optional.ofNullable(null).orElseThrow(NullPointerException::new);&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;예제에서는 &lt;code&gt;NullPointException&lt;/code&gt;을 사용했는데, 이러면 &lt;code&gt;Optional&lt;/code&gt;을 사용하는 의미가 없기 때문에, 필요하다면 사용자 정의 Exception 또는 기존에 정의된 Exception중 필요한걸 찾아서 넘겨주면 된다.&lt;/p&gt;
&lt;h5&gt;12. stream&lt;/h5&gt;
&lt;p&gt;값이 존재하면 존재하는 값만 포함하는 스트림을 반환하고, 없으면 empty 스트림 반환&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Optional.ofNullable(null).stream();&lt;/code&gt;&lt;/pre&gt;&lt;h5&gt;기본형 특화 옵셔널&lt;/h5&gt;
&lt;p&gt;스트림처럼 기본형 int, long, double 전용 옵셔널이 존재하지만. 스트림의 경우 요소가 여러개이기 때문에 오토박싱에 대한 비용을 감소시켜서 성능 향상의 효과가 있었지만, 옵셔널의 경우 요소의 수는 한개이므로 성능향상은 존재하지 않는다. 또한 &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;flatMap&lt;/code&gt;, &lt;code&gt;fillter&lt;/code&gt; 등을 지원해주지 않고, 기존의 &lt;code&gt;Optional&lt;/code&gt;과 혼용으로 사용이 불가능 하기 때문에 기본형 특화 옵셔널 사용을 하지 말아야 한다. &lt;/p&gt;</description>
      <category>PROGRAMMING/JAVA</category>
      <category>Java</category>
      <category>null참조</category>
      <category>optional</category>
      <category>옵셔널</category>
      <category>자바</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/139</guid>
      <comments>https://lee1535.tistory.com/139#entry139comment</comments>
      <pubDate>Wed, 3 Jun 2020 13:06:20 +0900</pubDate>
    </item>
    <item>
      <title>[Java/java] 스트림과 컬렉터 Stream, Collector</title>
      <link>https://lee1535.tistory.com/138</link>
      <description>&lt;p&gt;해당 내용은 모던 자바 인 액션의 내용을 참고해서 작성하였습니다.&lt;/p&gt;
&lt;h2&gt;스트림&lt;/h2&gt;
&lt;p&gt;스트림은 람다와 마찬가지로 자바8에서 추가된 기능이다. 여기서 스트림이란, 데이터 처리 연산을 지원하도록 소스에서 추출된 연속된 요소로 정의할 수 있다.&lt;/p&gt;
&lt;h5&gt;스트림과 컬렉션&lt;/h5&gt;
&lt;p&gt;스트림도 컬렉션과 마찬가지로 연속된 값 집합의 인터페이스를 제공한다. 단 데이터를 언제 계산하느냐가 컬렉션과 스트림의 가장 큰 차이. 컬렉션은 현재 자료구조가 포함하는 모든 값을 메모리에 저장하는 자료구조이다. 그 후, 계산이 가능하다. 그러나 스트림의 경우 요청할 때만 요소를 계산하는 고정된 자료구조이다.&lt;br&gt;이를 동영상으로 비유하면, 컬렉션은 동영상을 모두 다운로드 후에 볼 수 있고, 스트림의 경우 전체가 아닌 해당 구간만 다운받아서 볼 수 있는 스트리밍 서비스가 있다. 또한 스트림은 한번 사용하면 소멸된다. 재사용이 불가능&lt;/p&gt;
&lt;p&gt;또한 스트림은 내부 반복으로써 컬렉션과 같이 ( forEach ) 문등을 통해 반복을 컨트롤 할 필요가 없다. 이를 외부 반복이라 한다. 또한 스트림은 내부 반복을 사용하기 위해, &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;map&lt;/code&gt; 등과 같은 다양한 추가 연산자를 제공해준다.&lt;/p&gt;
&lt;h2&gt;스트림의 연산&lt;/h2&gt;
&lt;p&gt;스트림은 내부 반복을 위해 파이프라인과 다양한 추가 연산자를 제공해준다. 이런 연산을 크게 2가지로 나눌 수 있는데 &lt;strong&gt;중간 연산&lt;/strong&gt; 과 &lt;strong&gt;최종 연산&lt;/strong&gt;으로 구분할 수 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;중간 연산 : 중간 연산의 특징은 단말 연산을 스트림 파이프라인에 실행하기 전까지 아무 연산도 수행하지 않는다. 즉 게으르다는 것이다. 중간 연산을 합친 다음에 최종 연산으로 한 번에 처리하기 때문이다. (filter, map, limit, sorted, distinct 등)&lt;/li&gt;
&lt;li&gt;최종 연산 : 스트림 파이프라인에서 결과를 도출한다. (forEach, collect, count 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;위와 같이 스트림의 게으른 특성 덕분에 몇가지 최적화 효과를 얻을 수 있다. &lt;code&gt;limit&lt;/code&gt;를 통해 쇼트서킷 또는 서로 다른 연산자를 한 과정으로 병합할 수 있는 루프퓨전 ( &lt;code&gt;filter&lt;/code&gt; 과 &lt;code&gt;map&lt;/code&gt;을 한 연산에서 둘 다 사용 가능 )&lt;/p&gt;
&lt;p&gt;정리하자면 스트림은 질의를 수행한 ( 컬렉션 같은 ) 데이터 소스가 필요하고, 중간 연산, 최종 연산의 형태로 이용이 가능하다.&lt;br&gt;&lt;code&gt;members.stream().filter(m -&amp;gt; m.getAge() &amp;gt; 20 ).limit(3).forEach(System.out::println)&lt;/code&gt;&lt;br&gt;여기서 members는 데이터 소스, filter,limit는 중간연산, forEach는 최종 연산에 해당한다.&lt;/p&gt;
&lt;h2&gt;스트림의 활용&lt;/h2&gt;
&lt;h5&gt;1. 필터링&lt;/h5&gt;
&lt;p&gt;스트림은 &lt;code&gt;filter&lt;/code&gt; 메서드를 통해, 프리디케이트를 인수로 받아, 필터가 가능하고, &lt;code&gt;distinct&lt;/code&gt;를 통해 고유 요소의 중복을 제거 할 수있다. 여기서 고유 여부는 스트림의 hashCode, equals로 결정됨&lt;/p&gt;
&lt;h5&gt;2. 스트림 슬라이싱&lt;/h5&gt;
&lt;p&gt;데이터가 무수히 많은 경우, 특정 조건까지의 리스트만 반환하고 싶은 경우&lt;br&gt;예제에서 members는 10만건의 멤버를 가지고 있다고 나이순으로 정렬이 되어있다고 가정&lt;/p&gt;
&lt;p&gt;자바 9 이상부터는 아래의 2가지 방법을 제공&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;List&amp;lt;Member&amp;gt; result = members.stream().takeWhile(m -&amp;gt; member.getAge() &amp;lt; 20).collect(toList());&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;위와 같이 사용하면 20세 미만인 멤버 리스트를 반환해준다. 반대로 20세 보다 큰 사람을 탐색하고 싶은 경우, &lt;code&gt;dropWhile&lt;/code&gt;를 사용하면 된다.&lt;/p&gt;
&lt;p&gt;또는 간단하게 페이징등의 동작을 위해 정해진 갯수로 제한하고 싶을 경우 &lt;code&gt;limit&lt;/code&gt;를 사용할 수 있다.&lt;br&gt;마지막으로 검색된 요소를 n개 건너 뛰고 싶은 경우 &lt;code&gt;skip&lt;/code&gt;를 통해 검색된 스트림에서 n개만큼 컨너뛴 요소를 추출할 수 있다.&lt;/p&gt;
&lt;h5&gt;3. 매핑&lt;/h5&gt;
&lt;p&gt;어떤 문자열에서 겹치는 문자를 제외해야 하는 요구조건이 생겨서, &lt;code&gt;String.split(&amp;quot;&amp;quot;)&lt;/code&gt;를 통해 중복을 제거하려고 했다면, 스트림의 &lt;code&gt;map&lt;/code&gt;대신 &lt;code&gt;flatMap&lt;/code&gt;를 사용해야 한다. 이유는 &lt;code&gt;String.getBytes&lt;/code&gt;의 경우 리턴값이 String배열이기 때문에, 해당 배열을 평문으로 만들어줄 필요가 생기기 때문이다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Arrays.asList(&amp;quot;banana&amp;quot;,&amp;quot;apple&amp;quot;).stream()
                .map(s -&amp;gt; s.split(&amp;quot;&amp;quot;))
                .distinct()
                .forEach(System.out::println);&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;해당 코드는 중복제거가 되지 않기 때문에 원하는 결과를 얻을 수 없다. flatMap을 통해 Stream&amp;lt;String배열&amp;gt; 부분을 Stream&amp;lt;String타입&amp;gt;로 변경해준다.즉 스트림의 결과를 쉽게 평면화 해준다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Arrays.asList(&amp;quot;banana&amp;quot;,&amp;quot;apple&amp;quot;).stream()
                .map(s -&amp;gt; s.split(&amp;quot;&amp;quot;))
                .flatMap(Arrays::stream)
                .distinct()
                .forEach(System.out::println);  &lt;/code&gt;&lt;/pre&gt;&lt;h5&gt;검색과 매칭&lt;/h5&gt;
&lt;p&gt;스트림은 &lt;code&gt;allMatch&lt;/code&gt;, &lt;code&gt;noneMatch&lt;/code&gt;, &lt;code&gt;findFirst&lt;/code&gt;, &lt;code&gt;findAny&lt;/code&gt;등의 연산자를 통해, 검색과 매칭에 효율적으로 처리가 가능해진다. 이는 limit처럼 쇼트서킷을 활용했으며, 해당 기능은 이름대로 수행한다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;allMatch&lt;/code&gt;, &lt;code&gt;noneMatch&lt;/code&gt;의 경우 프리디케이트가 적어도 일치하냐, 일치하지 않느냐에 대한 수행 결과를 반환해주고,&lt;br&gt;&lt;code&gt;findFirst&lt;/code&gt;, &lt;code&gt;findAny&lt;/code&gt; 둘다, 일치하는 첫번 째 항목을 리턴해준다. 둘이 동작이 비슷하지만, 병렬에서는 &lt;code&gt;findAny&lt;/code&gt;를 사용하는게 좋으며, 값이 null일 수 있기 때문에 &lt;code&gt;Optional&amp;lt;T&amp;gt;&lt;/code&gt;를 리턴해준다.&lt;/p&gt;
&lt;h5&gt;리듀싱&lt;/h5&gt;
&lt;p&gt;스트림의 filter을 통해 서울에 사는 멤버들의 리스트를 추출할 수 있게되었다. 나아가 추출 된 멤버들 중 나이가 제일 많은 사람과, 제일 적은 사람을 구하시오와 같은 요구를 처리하기 위해선 모든 요소를 반복적으로 처리해야 하며, 이런 질의를 리듀싱 연산이라고 한다. 아래와 같이 해결할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int max = members.stream()
                    .filter(m -&amp;gt; m.getAge() &amp;gt; 20)
                    .map(Member::getAge)
                    .reduce(0, (a, b) -&amp;gt; a &amp;gt; b ? a : b);&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;reduce의 0은 초기값이며, 초기값을 생략도 가능한 메소드를 오버로딩해준다. 다만 값이 없을 수도 있기 때문에 Optional로 반환해준다. 나아가 메서드 참조를 통해 아래처럼도 사용 가능&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int max = members.stream()
                    .filter(m -&amp;gt; m.getAge() &amp;gt; 20)
                    .map(Member::getAge)
                    .reduce(0, Integer::max);&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;이렇게 값을 반복적으로 처리하기 위해 내부 상태를 가지고 있어야 하는 스트림을 &lt;strong&gt;내부 상태를 갖는 연산&lt;/strong&gt; 이라고 하며, &lt;code&gt;reduce&lt;/code&gt;의 경우 int나 double로 내부 상태로 사용했고, 해당 값은 한정되어 있는 값이다. 또한 소수에서 젤 큰 수를 찾아라와 같은 무한 스트림에서 &lt;code&gt;sorted&lt;/code&gt;나 &lt;code&gt;distinct&lt;/code&gt;의 경우 값을 비교하기 위해 무한적으로 요소가 버퍼에 추가되어야 하기 때문에 문제가 발생한다. 이렇게 내부 상태를 갖는 연산은 사용 시 주의가 필요하다.&lt;/p&gt;
&lt;p&gt;내부상태를 갖는 연산의 종류 : &lt;code&gt;distinct&lt;/code&gt;, &lt;code&gt;skip&lt;/code&gt;, &lt;code&gt;limit&lt;/code&gt;, &lt;code&gt;sorted&lt;/code&gt;, &lt;code&gt;reduce&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;기본형 특화&lt;/h2&gt;
&lt;p&gt;스트림은 기본적으로 참조 타입을 가지기 때문에, 오토박싱에 대한 비용이 발생하게 되고, 간단한 누계같은 함수를 바로 사용할 수 없다. 그래서 함수처럼 기본형 특화 스트림을 제공해주며, 기본적인 메소드들이 정의되어 있다.( min, max, range, rangeClosed 등 ) 이전에 최대값을 구하는 방식을 아래처럼 변경이 가능하다&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;OptionalInt max2 = members.stream()
                .filter(m -&amp;gt; m.getAge() &amp;gt; 20)
                .mapToInt(Member::getAge)
                .max();&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;여기서 리턴타입은 OptionalInt, OptionalDouble등 특화 참조타입으로 리턴을 해준다.&lt;br&gt;복원의 경우 &lt;code&gt;boxed&lt;/code&gt; 메소드를 사용하면 기본 스트림으로 변환해준다.&lt;/p&gt;
&lt;h2&gt;스트림 만들기&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;임의의 값으로 만들기&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Stream&amp;lt;Integer&amp;gt; stream = Stream.of(10, 20 , 41, 31 ) ;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;빈 스트림 만들기&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Stream&amp;lt;Integer&amp;gt; stream = Stream.empty();&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;null이 될 수 있는 객체로 스트림 만들기 return값이 null일때 빈 스트림을 반환해준다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Stream&amp;lt;String&amp;gt; values = Stream.ofNullable(System.getProperty(&amp;quot;hmoe&amp;quot;));&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;null이 될 수 있는 객체로 스트림 만들기 return값이 null일때 빈 스트림을 반환해준다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int[] arr = { 1, 2, 3, 4, 5 };
int sum = Arrays.stream(arr).sum();&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;그외 함수로 무한 스트림 만들기 iterate, generate : 둘의 차이는 값을 연속으로 계산하냐, 매번 인수로 받느냐 차이&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Collector 컬렉터&lt;/h2&gt;
&lt;p&gt;스트림 최종연산으로 &lt;code&gt;collect(toList())&lt;/code&gt;를 많이 사용했었는데, 이때 &lt;code&gt;collect&lt;/code&gt; 메서드는 &lt;code&gt;Collector&lt;/code&gt; 인터페이스의 구현을 매개변수로 받는다. 이 인터페이스의 구현은 스트림의 요소를 어떤 식으로 도출할지 지정한다.&lt;br&gt;또한 유틸성 클래스로 &lt;code&gt;Collector&lt;/code&gt;이 있으며 주로 스트림 요소를 하나의 값으로 리듀스하고, 요약하는 기능과 그룹화/분할 3가지로 구분할 수 있다.&lt;/p&gt;
&lt;h5&gt;1. 스트림 하나의 값으로 리듀싱&lt;/h5&gt;
&lt;p&gt;컬렉터를 통해서도 리듀싱 기능 즉 요약 연산이 가능하다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Long count = members.stream().collect(counting());&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;해당 코드는 아래처럼 요약이 가능하다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Long count = members.stream().count();&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;이외 최대 값, 최소 값을 리턴해주는 &lt;code&gt;maxBy(Comparaotr)&lt;/code&gt;, &lt;code&gt;minBy(comparator)&lt;/code&gt;도 제공해주며, 리턴은 &lt;code&gt;Optional&amp;lt;T&amp;gt;&lt;/code&gt; 타입으로 반환을 해준다.&lt;/p&gt;
&lt;p&gt;또 많이 사용하는 합계와, 평균값을 구해주는 메소드를 제공해주며 각각 &lt;code&gt;averagingInt(mapper)&lt;/code&gt;,&lt;code&gt;averagingLong(mapper)&lt;/code&gt;,&lt;code&gt;averagingDouble(mapper)&lt;/code&gt; 을 제공해주며, 동작 방식은 동일하고, 요약하는 데이터 형식이 다르다, 마찬가지로 합계도 &lt;code&gt;summingInt(mapper)&lt;/code&gt;과 같은 형태로 3가지를 제공한다.&lt;/p&gt;
&lt;p&gt;위 합계, 평균, 카운트, 최소, 최대 값을 한번에 모두 리턴해주는 놀라운 메소드도 제공해주며 이름은 &lt;code&gt;summarizingInt(mapper)&lt;/code&gt;로 제공주고 리턴으론 각각 요약 데이터 형식에 따른 객체를 리턴해준다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IntSummaryStatistics result = members.stream().collect(summarizingInt(Member::getAge));&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;해당 객체는 다음과 같이 값들이 들어있으며 &lt;code&gt;IntSummaryStatistics result = members.stream().collect(summarizingInt(Member::getAge))&lt;/code&gt; 익숙한 &lt;code&gt;getCount&lt;/code&gt;등과 같은 방식으로 값을 꺼낼 수 있다.&lt;/p&gt;
&lt;p&gt;마지막으로 문자열의 연산도 제공해주는데 &lt;code&gt;joining()&lt;/code&gt;이며, 구분자를 주고 싶은 경우 다음처럼 &lt;code&gt;joinging(&amp;quot;, &amp;quot;)&lt;/code&gt; 매개변수로 넘겨주면 된다.&lt;/p&gt;
&lt;h5&gt;2. 범용 리듀싱 요약 연산&lt;/h5&gt;
&lt;p&gt;위에서 사용한 모든 팩토리 메서드는 &lt;code&gt;reducing&lt;/code&gt;로 정의해 직접 사용할 수도 있다. 합계의 경우 다음과 같이 사용 가능&lt;br&gt;가동성이나, 생산성을 따져서 편리하게 사용하는게 좋음&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int sum = members.stream().collect(
                reducing(0, Member::getAge , Integer::sum  
            );&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;또한 예제에서는 &lt;code&gt;Collector&lt;/code&gt;을 한개만 사용했는데 진정한 강력함은 다른 &lt;code&gt;Collector&lt;/code&gt;과 함께 사용할 때 나타난다.&lt;/p&gt;
&lt;h5&gt;3. collect 와reduce&lt;/h5&gt;
&lt;p&gt;둘다 요약 연산을 하며, 결과를 도출해주는 메소드이다. 다만 &lt;code&gt;reduce&lt;/code&gt;의 경우 &lt;strong&gt;불변&lt;/strong&gt; 값을 결합하여 &lt;strong&gt;새로운 값을 생성&lt;/strong&gt;하는 연산이고, &lt;code&gt;collect&lt;/code&gt;는 컨테이너 를 변경 하여 생성해야하는 결과를 축적 하도록 설계되었습니다.&lt;br&gt;쉽게 말해, List와 같이 가변 컨테이너 관련 작업이면서, 병렬성을 확보하기 위해선 &lt;code&gt;collect&lt;/code&gt;를 사용하는 방법이 바람직합니다.&lt;/p&gt;
&lt;h5&gt;4. 그룹화&lt;/h5&gt;
&lt;p&gt;예제에서 성을 기준으로 멤버들을 그룹화하고 싶은 경우 &lt;code&gt;groupingBy&lt;/code&gt;를 사용 하면 된다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Map&amp;lt;LastName, List&amp;lt;Member&amp;gt;&amp;gt; result = members.stream().collect(groupingBy(Member::getLastname));&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;결과는 다음과 같다 &lt;code&gt;{PARK=[[age=15]], KIM=[[age=41], [age=61], [age=7]], LEE=[[age=23]]}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;이제 위 예제에서 성을 기준으로 그룹화하고, 성인인 사람을 필터링하고 싶다면? 아래와 같이 사용할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Map&amp;lt;LastName, List&amp;lt;Member&amp;gt;&amp;gt; result = members.stream()
                                        .filter(m -&amp;gt; m.getAge() &amp;gt; 19)
                                        .collect(groupingBy(Member::getLastname));&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;결과는 다음과 같다. &lt;code&gt;{LEE=[[age=23]], KIM=[[age=41], [age=61]]}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;위에서 잠깐 언급한, &lt;code&gt;collect&lt;/code&gt;는 컬렉터를 다른 컬렉터와 사용할 경우 막강한 기능을 제공한다고 소개했었다. 위 2개의 결과는 조금 차이가 있다. 바로 &lt;code&gt;filter&lt;/code&gt;에 해당하는 값이 없다면, 최종연산에 포함되지 않기 때문에 성이 PARK 타입은 그룹에서 제외가 되었다. 그래서 아래처럼 변경을 해본다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Map&amp;lt;LastName, List&amp;lt;Member&amp;gt;&amp;gt; result = members.stream()
                                            .collect(groupingBy(Member::getLastname
                                            ,filtering( m -&amp;gt; m.getAge() &amp;gt; 19, toList())));&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;결과는 다음과 같이 없는 경우에도 버킷을 생성한 결과를 리턴해준다. &lt;code&gt;{PARK=[], KIM=[[age=41], [age=61]], LEE=[[age=23]]}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;위처럼 동작하는 이유는 &lt;code&gt;collec&lt;/code&gt;가 최종 연산에 해당하기 때문에, 스트림의 결과에서 그룹화, 필터링을 진행하기 때문에 다른 연산 결과를 보여준다. 여기서 &lt;code&gt;filtering&lt;/code&gt;를 썻다는거는 &lt;code&gt;groupingBy&lt;/code&gt;도 사용 가능하다는 뜻이고, 다음과 같이 다수준으로 그룹화가도 가능해진다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Map&amp;lt;LastName, Map&amp;lt;Object, List&amp;lt;Member&amp;gt;&amp;gt;&amp;gt; result = members.stream()
                    .collect(groupingBy(Member::getLastname,
                            groupingBy(m -&amp;gt; {
                                if(m.getAge() &amp;gt; 19) return AgeGroup.ADULT ;
                                else return AgeGroup.CHILD;
                                }
                            )));&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;결과는 &lt;code&gt;{LEE={ADULT=[[age=23]]}, PARK={CHILD=[[age=15]]}, KIM={CHILD=[[age=7]], ADULT=[[age=41], [age=61]]}}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;이렇게 외부 컬렉터로 넘겨주는 컬렉터에는 제한이 없이, 다 사용이 가능하다는 강점이있다. &lt;/p&gt;
&lt;h5&gt;5. 분할&lt;/h5&gt;
&lt;p&gt;분할 함수라 불리는 프리디케이트를 분류 함수로 사용하는 특수한 그룹화 기능으로, Boolean 값 결과를 토대로 그룹화를 한다. 다음과 같이 사용할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Map&amp;lt;Boolean, List&amp;lt;Member&amp;gt;&amp;gt; result = 
                                members.stream()
                                    .collect(partitioningBy(
                                        m -&amp;gt; m.getLastname().equals(KIM)
                                    ));&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;결과는 &lt;code&gt;{false=[[age=23], [age=15]], true=[[age=41], [age=61], [age=7]]}&lt;/code&gt;&lt;/p&gt;</description>
      <category>PROGRAMMING/JAVA</category>
      <category>collect</category>
      <category>Java</category>
      <category>reduce</category>
      <category>스트림</category>
      <category>요약연산</category>
      <category>자바</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/138</guid>
      <comments>https://lee1535.tistory.com/138#entry138comment</comments>
      <pubDate>Tue, 26 May 2020 16:02:06 +0900</pubDate>
    </item>
    <item>
      <title>[자바/Java] Lambda 람다 표현식, 함수형 인터페이스</title>
      <link>https://lee1535.tistory.com/137</link>
      <description>&lt;p&gt;해당 내용은 모던 자바 인 액션을 참고해서 작성한 내용입니다.&lt;/p&gt;
&lt;h2&gt;람다란 무엇인가&lt;/h2&gt;
&lt;p&gt;&lt;b&gt;람다 표현식&lt;/b&gt;은 메서드로 전달할 수 있는 익명 함수를 단순화한 것이라고 할 수 있다. 람다 표현식에는 이름은 없지만, 파라미터나 리스트, 바디, 반환 형식, 발생할 수 있는 예외 리스트는 가질 수 있다. 이러한 람다는 아래 4가지의 특징을 가진다.&lt;/p&gt;
&lt;ul&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&gt;아래는 람다의 기본 구조이다&lt;br /&gt;&lt;code&gt;(Member m1, Member m2) -&amp;gt; m1.getName().compareTo(m2.getName());&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;위 예제처럼 람다는 &lt;code&gt;{ }&lt;/code&gt; 와 &lt;code&gt;return&lt;/code&gt; 문을 명시적으로 사용하지 않아도 된다. 하지만 람다 표현식 안에서 여러줄을 사용할 때는 &lt;code&gt;{ }&lt;/code&gt;를 사용해야 하며, 리턴이 있는 경우 &lt;code&gt;return&lt;/code&gt;문을 명시적으로 선언해줘야 한다.&lt;/p&gt;
&lt;pre class=&quot;sas&quot;&gt;&lt;code&gt;(int x, int y) -&amp;gt; { 
    System.out.println(&quot;x + y &quot;);  
    System.out.println(&quot; = &quot; + (x + y)); 
    return x + y ; 
  } &lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;람다의 사용&lt;/h2&gt;
&lt;p&gt;람다는 그렇다면 어디에 사용할 수 있는 건가? 모든 코드를 람다로 변화 할 수 있는건가? 답은 아니다. 바로 &lt;code&gt;함수형 인터페이스&lt;/code&gt;라는 문맥에서만 람다 표현식을 사용할 수 있다.&lt;br /&gt;&lt;code&gt;함수형 인터페이스&lt;/code&gt;란 &lt;b&gt;하나의 추상 메서드&lt;/b&gt;를 지정하는 인터페이스이다. 더 많거나, 적어도 안된다. 여기서 자바 언어 설계자들은 시대의 변화에 따라 함수라는 타입을 새로 만드는 방법 대신, 자바 개발자들에게 익숙한 인터페이스를 활용해 다른 언어의 함수처럼 사용할 수 있게 만드는 방법을 제공했다.&lt;/p&gt;
&lt;p&gt;추가로 &lt;code&gt;@FunctionalInterface&lt;/code&gt; 어노테이션을 제공, 선언 된 인터페이스가 함수형 인터페이스가 아니면 컴파일 오류가 발생하게 기능을 추가했다.&lt;/p&gt;
&lt;h2&gt;함수형 인터페이스 사용&lt;/h2&gt;
&lt;p&gt;자바 8부터는 &lt;code&gt;java.util.function&lt;/code&gt; 패키지로 여러 가지 함수형 인터페이스를 제공해주며. 그 중에 &lt;code&gt;Predicate&lt;/code&gt; 함수형 인터페이스를 통해 람다의 사용법 예제를 본다.&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;@FunctionalInterface
public interface MemberPredicate {
     boolean test(Member member);
}

public static List&amp;lt;Member&amp;gt; filter(List&amp;lt;Member&amp;gt; members, MemberPredicate mp) {
        List&amp;lt;Member&amp;gt; result = new ArrayList&amp;lt;&amp;gt;();
        for(Member member : members) {
            if(mp.test(member)) { 
                result.add(member);
            } 
        }
        return result;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같은 예제가 존재한다고 가정하고, 물론 제네릭을 통해 더 재사용성이 높은 코드를 만들 수 있지만, 이전의 다른 포스팅의 예제를 사용하기 때문에 위에처럼 선언했다. 아래는 사용 방법이다.&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;MemberPredicate memberPredicate = (Member m) -&amp;gt; LEE.equals(member1.getLastName());
List&amp;lt;Member&amp;gt; result = filter(members, memberPredicate);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위에 처럼 사용 가능하며 더 코드를 줄인다면 &lt;code&gt;List&amp;lt;Member&amp;gt; result = filter(members, (Member m) -&amp;gt; LEE.equals(m.getLastname()));&lt;/code&gt; 와 같이 선언해 사용할 수 있게 된다.&lt;/p&gt;
&lt;h2&gt;기본형 특화&lt;/h2&gt;
&lt;p&gt;자바는 모두 알다시피 참조형 또는 기본형으로 구성되어 있다. 그런데 &lt;code&gt;public interface Predicate&amp;lt;T&amp;gt; { boolean test(T T); }&lt;/code&gt; 와 같이 선언된 함수형 인터페이스의 경우 기본형으로 사용하고자 할 때 불필요하게 오토박싱이 일어나 메모리를 낭비하거나, 메모리 탐색등의 과정이 추가로 필요하게 된다.&lt;/p&gt;
&lt;p&gt;그래서 자바는 기본적으로 기본형 특화 함수형 인터페이스를 제공해준다. &lt;code&gt;public interface IntPredicate { boolean test(int t);}&lt;/code&gt;와 같이 해당 인터페이스들은 종류가 많기 때문에, 그냥 기본형만 사용할 경우 기본형 특화 인터페이스를 사용 할 수 있다는 것을 알고 필요하면 직접 구현 또는, Java API를 참조 하면 될 것 같다.&lt;/p&gt;
&lt;h2&gt;예외 사용법&lt;/h2&gt;
&lt;p&gt;함수형 인터페이스의 함수도 일반 메서드처럼 예외를 사용할 수 있다고 설명했다. 직접 구현한 경우 문제가 되지 않는다 가령, 아래처럼 말이다.&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;@FunctionalInterface
public interface MemberPredicate {
     boolean test(Member member) throws Exception;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그러나 좀 전에 설명한 Java에서 제공해주는 기본 함수형 인터페이스의 경우 내 마음대로 인터페이스를 수정할 수 없다는 문제점이 생긴다. 그래서 명시적으로 &lt;code&gt;throw new Exception()&lt;/code&gt; 을 발생시켜 원하는 예외처리를 할 수 있다.&lt;/p&gt;
&lt;h2&gt;람다의 형식 추론, 지역 변수&lt;/h2&gt;
&lt;p&gt;제너릭의 다이아몬드 연산자가 가능한 것 처럼 &lt;code&gt;List&amp;lt;Member&amp;gt; members = new ArrayList&amp;lt;&amp;gt;()&lt;/code&gt; 에서의 &lt;code&gt;&amp;lt;&amp;gt;&lt;/code&gt; 람다도 형식을 추론해 코드를 더욱 간결하게 만들 수 있다.&lt;br /&gt;&lt;code&gt;List&amp;lt;Member&amp;gt; result = filter(members, (Member m) -&amp;gt; LEE.equals(m.getLastname()));&lt;/code&gt; 앞서 사용한 예제 코드중 한 부분이며, 이를 다음처럼 코드를 줄일 수 있다. &lt;code&gt;List&amp;lt;Member&amp;gt; result = filter(members, (m) -&amp;gt; LEE.equals(m.getLastname()));&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;람다는 지역 변수를 사용할 수 있다. 다만 지역 변수의 경우 값을 변경할 수 없다는 제약이 존재한다. 이는 동작 방식의 메커니즘에 의해서 제약이 생기게 되는데 자세한 내용은 추가로 검색하길 바란다.&lt;/p&gt;
&lt;h2&gt;메서드 참조&lt;/h2&gt;
&lt;p&gt;메서드 참조를 이용하면 기존의 메서드 정의를 재활용해서 람다처럼 전달할 수 있다. 아래가 예시이다.&lt;br /&gt;&lt;code&gt;members.sort((Member m1, Member m2) -&amp;gt; m1.getAge().compareTo(a2.getAge()))&lt;/code&gt; 를 메서드 참조를 사용하면&lt;br /&gt;&lt;code&gt;members.sort(Comparator.compareTo(Member::getAge)&lt;/code&gt;로 줄일 수 있게 된다. 이러한 메소드 참조를 만드는 3가지 방법은 아래와 같다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;정적 메서드 참조 : Integer의 parseInt는 Integer::parseInt&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;인스턴스 메서드 참조 : String의 length는 String::length&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;개존 객체의 인스턴스 메서드 참조 : Member객체의 인스턴스 member의 getAge는 member::getAge&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;람다와 메서드 참조 단축 표현 예제&lt;/p&gt;
&lt;pre class=&quot;rust&quot;&gt;&lt;code&gt;( Member member ) -&amp;gt; member.getName()           //  Member::getName
( String str, Integer i ) -&amp;gt; str.substring(i)   // String::substring
( String str ) -&amp;gt; System.out.println(str)       // System.out::println
( String str ) -&amp;gt; this.isValidStr(str)          // this::isValid &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위 예제들과 같이 메서드 참조를 사용하게 되면 가독성을 높일 수 있게 된다는 큰 장점이 생긴다.&lt;/p&gt;
&lt;h2&gt;생성자 참조&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;ClassName::new&lt;/code&gt; 처럼 클래스명과 new 연산자를 통해 메서드 참조처럼 기존 생성자의 참조를 만들 수 있다. 마치 메서드 참조의 정적 메서드 참조를 만드는 방법과 비슷하다.&lt;/p&gt;
&lt;p&gt;예를들어 매개변수가 없는 기본 생성자가 존재하는 &lt;code&gt;Member&lt;/code&gt; 클래스가 있다고 가정했을 때, 아래와 같이 사용 가능&lt;br /&gt;&lt;code&gt;Supplier&amp;lt;Member&amp;gt; m1 = Member::new&lt;/code&gt; Supplier 함수형 인터페이스는 매개변수 없이 T 타입을 리턴하는 &lt;code&gt;() -&amp;gt; T&lt;/code&gt; 형식의 시그니처를 가진기 때문에 이처럼 사용이 가능하다.&lt;/p&gt;
&lt;p&gt;그렇다면 생성자에 매개변수를 가지는 경우는 어떻게 사용할까? 바로 &lt;code&gt;Function&lt;/code&gt; 함수형 인터페이스를 사용하면 편하게 사용이 가능하다. &lt;code&gt;Member&lt;/code&gt; 클래스는 생성자가 나이를 매개변수로 받는다고 가정한다.&lt;/p&gt;
&lt;pre class=&quot;fortran&quot;&gt;&lt;code&gt;Function&amp;lt;Integer, Member&amp;gt; f = Member::new;
Member member = f.apply(28); &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위처럼 선언하면 28이라는 나이를 가진 새로운 맴버 객체를 생성하게 된다. 그렇다면 매개변수가 2개인 경우는? 다행히 &lt;code&gt;BiFunction&lt;/code&gt; 함수형 인터페이스의 경우 &lt;code&gt;( T, U ) -&amp;gt; R&lt;/code&gt; 형식의 시그니처를 가지기 때문에 활용이 가능하다. 더 나아가, 3개 이상이거나 가변적일 경우는? 새로운 함수형 인터페이스를 선언하면 문제는 해결이 된다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;public interface TriFunction&amp;lt;T, U, V, R&amp;gt; {
    R apply ( T t, U u, V v );
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;디폴트 메서드와 메서드의 조합&lt;/h2&gt;
&lt;p&gt;아래와 같은 이름을 가지는 리스트가 있을 존재한다고 가정한다.&lt;/p&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;List&amp;lt;Member&amp;gt; members = Arrays.asList(
                    new Member(23),
                    new Member(15),
                    new Member(41),
                    new Member(61),
                    new Member(7)
                );&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이때, 나이순으로 정렬을 원하는 요구가 생길 경우 아래와 같이 정렬을 쉽게 할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;members.sort(Comparator.comparing(Member::getAge))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그런데 여기에서 결과를 내림차순으로 보고 싶다고 하면 또 다른 &lt;code&gt;Comparator&lt;/code&gt; 인터페이스를 생성할 필요 없이, 간단하게 반전된 결과를 얻을 수 있게 된다.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;members.sort(Comparator.comparing(Member::getAge).reversed())&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그런데 처음 위 예제를 봤을 때 뭔가 불편한 느낌을 받았었다. 람다를 사용할 수 있다는 것은, 함수형 인터페이스라는말이고, 함수형 인터페이스는 1개의 추상 메서드를 가지는 메서드라고 배웠는데, 여기서 &lt;code&gt;comparing&lt;/code&gt;가 해당하는 추상 메서드인건 알겠다.&lt;br /&gt;그럼 &lt;code&gt;reversed()&lt;/code&gt; 메서드는 무엇인가? 바로 자바8에 새로 추가된 &lt;b&gt;디폴트 메서드&lt;/b&gt;이다. 디폴트 메서드는 추상 메서드가 아니기 때문에, 위와 같이 함수형 인터페이스에 선언이 가능하고 사용이 가능하다.&lt;/p&gt;
&lt;p&gt;추가로 &lt;code&gt;Comperator&lt;/code&gt;에는 &lt;code&gt;thenComparing&lt;/code&gt;를 제공한다. 해당 메소드는 기존의 정렬 기준이 동일 할때 즉, 예제에선 나이가 같은 사람들이 있을 때, 추가로 조건을 줄 수 있게 해주는 메소드이다.&lt;/p&gt;
&lt;h5&gt;Predicate, Function 의 디폴트 메소드&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;Predicate&lt;/code&gt; 인터페이스의 경우도 결과를 반전시켜주는 &lt;code&gt;negate()&lt;/code&gt;, or과 and 연산을 위한 &lt;code&gt;or&lt;/code&gt;, &lt;code&gt;and&lt;/code&gt;도 제공해준다.&lt;br /&gt;&lt;code&gt;Function&lt;/code&gt; 인터페이스의 경우 &lt;code&gt;andThen&lt;/code&gt; , &lt;code&gt;compose&lt;/code&gt;를 제공하며, &lt;code&gt;andThen&lt;/code&gt;의 경우 결과를 전달, &lt;code&gt;compose&lt;/code&gt;의 경우 인수로 주어진 함수를 먼저 실행한 후에 실행 &lt;code&gt;f.andThen(g)&lt;/code&gt; -&amp;gt; f 실행 후 g 실행, &lt;code&gt;f.compose(g)&lt;/code&gt; g 실행 후 f 실행&lt;/p&gt;
&lt;h2&gt;함수형 인터페이스의 종류&lt;/h2&gt;
&lt;p&gt;기본형 특화를 제외한 큰 분류의 함수형 인터페이스만 소개하겠습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.4263%;&quot;&gt;함수형 인터페이스&lt;/td&gt;
&lt;td style=&quot;width: 20.6589%;&quot;&gt;함수 디스크립터&lt;/td&gt;
&lt;td style=&quot;width: 58.9147%;&quot;&gt;디폴트 메소드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.4263%;&quot;&gt;Predicate&amp;lt;T&amp;gt;&lt;/td&gt;
&lt;td style=&quot;width: 20.6589%;&quot;&gt;T -&amp;gt; boolean&lt;/td&gt;
&lt;td style=&quot;width: 58.9147%;&quot;&gt;and(Predicate&amp;lt;? super T&amp;gt; other) - &amp;amp;&amp;amp; 연산자와 대응&lt;br /&gt;or(&lt;span style=&quot;color: #333333;&quot;&gt;Predicate&amp;lt;? super T&amp;gt; other&lt;/span&gt;) - || 연산자와 대응&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;negate() - ! 연산자와 대응 ( 반전 )&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.4263%;&quot;&gt;Consumer&amp;lt;T&amp;gt;&lt;/td&gt;
&lt;td style=&quot;width: 20.6589%;&quot;&gt;T -&amp;gt; void&lt;/td&gt;
&lt;td style=&quot;width: 58.9147%;&quot;&gt;andThen(Consumer&lt;span&gt;&amp;lt;? super&lt;span&gt; T&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;gt;&amp;nbsp;after&lt;/span&gt;) : 후 처리 연결&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.4263%;&quot;&gt;Function&amp;lt;T, R&amp;gt;&lt;/td&gt;
&lt;td style=&quot;width: 20.6589%;&quot;&gt;T -&amp;gt; R&lt;/td&gt;
&lt;td style=&quot;width: 58.9147%;&quot;&gt;andThen(Function&amp;lt;? super R, ? extends V&amp;gt; after ) :&amp;nbsp; &lt;span style=&quot;color: #333333;&quot;&gt;후 처리 연결&lt;/span&gt;&lt;br /&gt;compose&lt;span style=&quot;color: #333333;&quot;&gt;(Function&amp;lt;? super R, ? extends V&amp;gt; after ) : 전처리 ( 인자로 받은 function을 먼저 실행 )&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.4263%;&quot;&gt;Supplier&amp;lt;T&amp;gt;&lt;/td&gt;
&lt;td style=&quot;width: 20.6589%;&quot;&gt;( ) -&amp;gt; T&lt;/td&gt;
&lt;td style=&quot;width: 58.9147%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.4263%;&quot;&gt;UnaryOperator&amp;lt;T&amp;gt;&lt;/td&gt;
&lt;td style=&quot;width: 20.6589%;&quot;&gt;T -&amp;gt; T&lt;/td&gt;
&lt;td style=&quot;width: 58.9147%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.4263%;&quot;&gt;BinaryOperator&amp;lt;T&amp;gt;&lt;/td&gt;
&lt;td style=&quot;width: 20.6589%;&quot;&gt;( T, T ) -&amp;gt; T&lt;/td&gt;
&lt;td style=&quot;width: 58.9147%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.4263%;&quot;&gt;BiPrdecate&amp;lt;T, U&amp;gt;&lt;/td&gt;
&lt;td style=&quot;width: 20.6589%;&quot;&gt;( T, U ) -&amp;gt; boolean&lt;/td&gt;
&lt;td style=&quot;width: 58.9147%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;and(&lt;span style=&quot;color: #333333;&quot;&gt;BiPrdecate&lt;/span&gt;&amp;lt;? super T, ? super &amp;gt; other) - &amp;amp;&amp;amp; 연산자와 대응&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;or(&lt;span style=&quot;color: #333333;&quot;&gt;BiPrdecate&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;lt;? super T,&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;? super&lt;/span&gt;&amp;gt; other&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;) - || 연산자와 대응&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;negate() - ! 연산자와 대응 ( 반전 )&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.4263%;&quot;&gt;BiConsumer&amp;lt;T, U&amp;gt;&lt;/td&gt;
&lt;td style=&quot;width: 20.6589%;&quot;&gt;( T, U ) -&amp;gt; void&lt;/td&gt;
&lt;td style=&quot;width: 58.9147%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;andThen(BiConsumer&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;lt;? super&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;T, ? super U&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;gt;&amp;nbsp;after&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;) : 후 처리 연결&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.4263%;&quot;&gt;BiFunction&amp;lt;T, U, R&amp;gt;&lt;/td&gt;
&lt;td style=&quot;width: 20.6589%;&quot;&gt;( T, U ) -&amp;gt; R&lt;/td&gt;
&lt;td style=&quot;width: 58.9147%;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;andThen(BiFunction&amp;lt;? super R, ? extends V&amp;gt; after ) : &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;후 처리 연결&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;스태틱 메소드나, 기본형 특화에 대한 참고를 원하시는분은 &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/function/Predicate.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;링크&lt;/a&gt;를 클릭해서 확인하시길 바랍니다. ( java 8 기준 )&lt;/p&gt;</description>
      <category>PROGRAMMING/JAVA</category>
      <category>디폴트</category>
      <category>람다</category>
      <category>메서드</category>
      <category>인터페이스</category>
      <category>자바</category>
      <category>함수형</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/137</guid>
      <comments>https://lee1535.tistory.com/137#entry137comment</comments>
      <pubDate>Fri, 22 May 2020 10:08:45 +0900</pubDate>
    </item>
    <item>
      <title>[Java/자바]  람다의 사용, 동작을 파라미터화</title>
      <link>https://lee1535.tistory.com/136</link>
      <description>&lt;h2&gt;요구사항의 변화&lt;/h2&gt;
&lt;p&gt;소비자의 요구사항은 언제든지 변할 수 있기 때문에, 변화에 조금 더 유연한 방식이 필요하게 되었다.&lt;br&gt;예를 들어, 처음에는 성이 &amp;#39;LEE&amp;#39;인 사람들만 추출해주는 되는 프로그램이 있다고 가정했을 때, 갑자기 소비자가 성이 &amp;#39;LEE&amp;#39;이고, 나이가 28살 이상인 사람들의 리스트를 추출해주세요. 라고 요구사항이 변경 될 경우 어떠한 방법으로 해결할 수 있는지 예제를 통해 알아보겠습니다.&lt;/p&gt;
&lt;p&gt;해당 내용은 &lt;code&gt;Mordern Java in Action&lt;/code&gt; 책의 내용을 참고하여 작성하였습니다.&lt;/p&gt;
&lt;h2&gt;1. 이름에서 성을 기준으로 필터링&lt;/h2&gt;
&lt;p&gt;첫 요구사항처럼 멤버 리스트에서 성이 &lt;code&gt;LEE&lt;/code&gt;인 사람들을 필터링 하는 코드를 아래처럼 작성할 수 있습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public static List&amp;lt;Member&amp;gt; filterByLastNameLee(List&amp;lt;Member&amp;gt; members) {
        List&amp;lt;Member&amp;gt; result = new ArrayList&amp;lt;&amp;gt;();
        for(Member member : members) {
            if(LEE.equals(member.getLastname())) { 
                result.add(member);
            } 
        }
        return result;
    }&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;위와 같은 코드를 작성했을 경우, 성이 고정적으로 &lt;code&gt;LEE&lt;/code&gt; 타입인 사람만 필터링이 가능하다는 문제점이 생깁니다. 여기서 만약 &lt;code&gt;KIM&lt;/code&gt;으로도 필터링을 하고 싶다는 요구사항이 생긴다면 우리는 성을 고정으로 &lt;code&gt;LEE&lt;/code&gt; 타입으로 두는게 아닌, 파라미터로 받는 방법으로 해결 할 수 있습니다.&lt;/p&gt;
&lt;h2&gt;2. Lastname을 파라미터화&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;public static List&amp;lt;Member&amp;gt; filterByLastNameLee(List&amp;lt;Member&amp;gt; members, Lastname lastname) {
        List&amp;lt;Member&amp;gt; result = new ArrayList&amp;lt;&amp;gt;();
        for(Member member : members) {
            if(lastname.equals(member.getLastname())) { 
                result.add(member);
            } 
        }
        return result;
    }&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;위와 같이 작성하게 되면, 성에 대해서는 유연성을 가지는 메소드를 가지게 되었습니다. 여기에 성이 아닌 나이로 조건을 주는 요구사항이 생기면 추가로 메소드의 수정이 필요하게 됩니다.&lt;/p&gt;
&lt;h2&gt;3. 나이로 필터링 추가&lt;/h2&gt;
&lt;p&gt;우리는 멤버의 성에 대해서는 유연한 메소드를 가지고 있습니다. 하지만 또 다시 어떤 조건보다 큰 나이를 가지는 사람이라는 요구 사항이 추가될 경우 동일하게 기존의 메소드를 살짝 변경해 파라미터를 추가해줍니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public static List&amp;lt;Member&amp;gt; filterByLastName(List&amp;lt;Member&amp;gt; members, LastName lastname, int age) {
        List&amp;lt;Member&amp;gt; result = new ArrayList&amp;lt;&amp;gt;();
        for(Member member : members) {
            if(lastname.equals(member.getLastname()) &amp;amp;&amp;amp; age &amp;lt; member.getAge()) { 
                result.add(member);
            } 
        }
        return result;
    }&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;하지만 아직 문제점이 발생합니다. 점점 파라미터가 많아지기 시작했고, 추가로 둘다 말고, 어떨때는 성으로만, 어떨 때는 성과 나이로 조건을 주고 싶어요 등의 요구사항이 생기게 됩니다.&lt;br&gt;해결 방안으로 별도의 메소드를 분리하거나, 최악이지만 플래그용 &lt;code&gt;boolean&lt;/code&gt; 변수를 선언해서 조건을 컨트롤 하는 방식으로 할 수도 있을 것입니다. 뭐가 되었든, 중복이 발생하거나, 최악의 코드가 되는건 마찬가지입니다.&lt;/p&gt;
&lt;h2&gt;4. 인터페이스를 통해 동작 파라미터화 ( 전략 패턴 )&lt;/h2&gt;
&lt;p&gt;여러 요구사항에 대응하기 위해 동작(조건)을 추상적으로 해결하는 방법을 사용합니다. 바로 디자인패턴의 전략패턴을 활용해서 필요에 따라 선택하는 방식입니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public interface MemberPredicate {
     boolean test(Member member);
}

public class MemberLeeLastNamePredicate implements MemberPredicate{

    @Override
    public boolean test(Member member) {
        return LEE.equals(member.getLastname());
    }
}

public class MemberKimLastNamePredicate implements MemberPredicate {

    @Override
    public boolean test(Member member) {
        return KIM.equals(member.getLastname());
    }
}

public static List&amp;lt;Member&amp;gt; filter(List&amp;lt;Member&amp;gt; members, MemberPredicate mp) {
        List&amp;lt;Member&amp;gt; result = new ArrayList&amp;lt;&amp;gt;();
        for(Member member : members) {
            if(mp.test(member)) { 
                result.add(member);
            } 
        }
        return result;
    }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;위와 같이 인터페이스와, 구현 클래스를 추가해주고, 기존의 메소드를 변경해주면, 이제 조건 동작 자체를 파라미터화 할 수 있게 되고, 아래와 같이 필요한 전략을 사용해서 원하는 조건을 선택할 수 있게 됩니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;List&amp;lt;Member&amp;gt; leeMembers = filter(members, new MemberLeeLastNamePredicate());
List&amp;lt;Member&amp;gt; kimMembers = filter(members, new MemberKimLastNamePredicate());&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;이제 동작이 달라도 파라미터도 안늘어나고, 비슷한 메소드 중복이 제거 되었으니 끝일까? 아쉽지만, 마찬가지로 새로운 요구조건이 생기면 추가로 클래스를 정의를 해야하거나, 사용할 때 인스턴스화 해야하는 번거로운 작업이 남아있습니다.&lt;/p&gt;
&lt;h2&gt;5. 익명 클래스와 람다&lt;/h2&gt;
&lt;p&gt;똑똑하신 분들은 그럼 구현체를 만들지말고 사용할때 익명 클래스를 사용하면 되지 않을까? 라는 생각을 하셨을겁니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;List&amp;lt;Member&amp;gt; result1 = filter(members, new MemberPredicate() {
            @Override
            public boolean test(Member member) {
                return PARK.equals(member.getLastname());
            }
        });

        List&amp;lt;Member&amp;gt; result2 = filter(members, new MemberPredicate() {
            @Override
            public boolean test(Member member) {
                return LEE.equals(member.getLastname());
            }
        });&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;이제 원하는 방식으로 동작을 구현해서 사용을 할 수가 있습니다. 그러나 코드가 상당히 길어지고 메소드의 기본 구조가 되는 코드가 &lt;code&gt;@Override public boolean test(Member member) {}&lt;/code&gt; 불필요하게 반복 됩니다.&lt;/p&gt;
&lt;p&gt;여기서 어차피 메소드의 반환타입, 메소드명, 파라미터등 기본 기조는 정해져 있으니까 컴파일 시점에서 추론을 할 수 있지 않을까 해서 생략을 가능하게 기능을 자바8에서 추가가 되었습니다. 바로 람다입니다.&lt;br&gt;이제 위 코드를 람다로 변환하면 아래와 같이 사용할 수 있습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;List&amp;lt;Member&amp;gt; result1 = filter(members, (m) -&amp;gt; LEE.equals(m.getLastname()));
List&amp;lt;Member&amp;gt; result2 = filter(members, (m) -&amp;gt; LEE.equals(m.getLastname()));&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;위 익명 클래스를 사용한 방식과 동일한 수행 결과를 반환합니다. 이러한 방식을 지원하기 위해 java는 8버전부터 람다, 함수형 인터페이스 제공등 다양한 변화가 생겼습니다.&lt;/p&gt;
&lt;p&gt;나아가서 &lt;code&gt;filter&lt;/code&gt;메소드의 &lt;code&gt;List&amp;lt;Member&amp;gt;&lt;/code&gt; 부분도 &lt;code&gt;List&amp;lt;T&amp;gt;&lt;/code&gt; 과 같이 제네릭을 사용하게 되면 타입에 제한 없이 사용 가능한 메소드로 만들 수 있게 됩니다.&lt;/p&gt;
&lt;h2&gt;6. 디자인패턴 리팩토링&lt;/h2&gt;
&lt;p&gt;예제에서는 전략 패턴을 예제로 사용했습니다. 전략 패턴 외 템플릿 메서드, 옵저버, 역할 사슬 체인, 팩토리 등에서도 람다로 변환해서 사용할 수 있습니다.&lt;/p&gt;</description>
      <category>PROGRAMMING/JAVA</category>
      <category>동작 파라미터화</category>
      <category>람다</category>
      <category>자바</category>
      <category>필터</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/136</guid>
      <comments>https://lee1535.tistory.com/136#entry136comment</comments>
      <pubDate>Thu, 21 May 2020 13:56:13 +0900</pubDate>
    </item>
    <item>
      <title>[자바/java] 지네릭스 &amp;amp; 와일드 카드</title>
      <link>https://lee1535.tistory.com/134</link>
      <description>&lt;h2&gt;지네릭스(Generics)&lt;/h2&gt;
&lt;p&gt;지네릭스는 다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에 컴파일 시의 타입체크를 해주는 기능이다. 객체의 타입을 컴파일 시에 체크하기 때문에 객체의 타입 안정성을 높이고 형변환의 번거로움이 줄어든다.&lt;br&gt;  쉽게 말해 타입을 명시함으로써 타입에 대한 안정성과, 번거로운 형변환을 줄여주는 기능이다. 그리고 지네릭은 클래스와, 메소드에 선언이 가능하다. &lt;/p&gt;
&lt;h2&gt;지네릭 클래스&lt;/h2&gt;
&lt;p&gt;Java의 지네릭 클래스인 &lt;code&gt;ArrayList&lt;/code&gt; 클래스를 참고해보자 내용은 Oracle 홈페이지의 JDK 11의 API의 내용입니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class ArrayList&amp;lt;E&amp;gt; extends AbstractList&amp;lt;E&amp;gt;
            implements List&amp;lt;E&amp;gt;, RandomAccess, Cloneable, Serializable {
    // 기타
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;위에처럼 클래스에 선언된 지네릭을 지네릭 클래스라 하며, 사용법은 &lt;code&gt;클래스이름&amp;lt;T&amp;gt;&lt;/code&gt;과 같은 방법으로 사용이 가능하다.&lt;br&gt;&lt;code&gt;ArrayList&lt;/code&gt;는 지네릭 안에 &lt;code&gt;&amp;lt;E&amp;gt;&lt;/code&gt;라는 문자가 들어갔고 설명에서는 &lt;code&gt;&amp;lt;T&amp;gt;&lt;/code&gt;가 들어갔는데 여기서 E나 T는 임의의 타입을 선언하는 문법으로써 수학의 x, y, z 등으로 선언하는 것과 비슷하다고 생각하면 됩니다.&lt;/p&gt;
&lt;p&gt;이제 간단하게 클래스를 하나 선언과 구현을 해보겠습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class Item&amp;lt;T&amp;gt; {

    private T item;
    public Item(T item) { this.item = item; }
    public T getItem() { return item; }
}

// 실행
public class Main {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Item&amp;lt;String&amp;gt; stringItem = new Item&amp;lt;&amp;gt;(&amp;quot;Lee&amp;quot;);
        System.out.println(stringItem.getItem());

        Item&amp;lt;Integer&amp;gt; intItem = new Item&amp;lt;&amp;gt;(20);
        System.out.println(intItem.getItem());
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;여기서 &lt;code&gt;Item&lt;/code&gt; 클래스는 T 라는 타입문자 말고 구체적인 클래스를 선언해서 해당 클래스만 받도록 강제화할 수 있습니다. 예를들어 &lt;code&gt;class Item&amp;lt;String&amp;gt;&lt;/code&gt;로 선언하면 &lt;code&gt;String&lt;/code&gt; 타입만 사용할 수 있게 됩니다. &lt;/p&gt;
&lt;h5&gt;지네릭 클래스의 제한&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;static 멤버에 타입 변수 T를 사용할 수 없다. 그 이유는 타입변수는 인스턴스 변수로 간주되기 때문에 인스턴스 되기 전까지 타입을 알 수 없기 때문이다.&lt;/li&gt;
&lt;li&gt;new 연산자의 경우도 마찬가지이다 그래서 동적으로 객체를 생성하는 &lt;code&gt;newInstance()&lt;/code&gt;등과 같은 메소드로 생성하는 방법이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;자 그렇다면 객체지향의 특징인 상속 관계에서는 어떻게 사용해야 할까? 기존의 &lt;code&gt;Item&lt;/code&gt; 클래스를 조금 변경하고, &lt;code&gt;Book, JavaBook&lt;/code&gt;를 추가해줍니다. &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class Item&amp;lt;T&amp;gt; {

    private List&amp;lt;T&amp;gt; list = new ArrayList&amp;lt;T&amp;gt;();

    public List&amp;lt;T&amp;gt; getList() {
        return list;
    }
}

public class Book { }

public class JavaBook extends Book { }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;이제 메인 메소드에서 &lt;code&gt;Item&amp;lt;Book&amp;gt; book = new Item&amp;lt;Book&amp;gt;();&lt;/code&gt; 과 같이 선언해보면 당연히 컴파일 오류가 발생하지 않는다. 그럼 다음과 같이 상속관계인 클래스를 사용해보자 &lt;code&gt;Item&amp;lt;Book&amp;gt; javaBook = new Item&amp;lt;JavaBook&amp;gt;();&lt;/code&gt; 얼핏 보면 될거 같지만 컴파일 오류가 발생한다. 이유는 타입을 &lt;code&gt;Book&lt;/code&gt; 클래스 타입으로 강제화 했기 때문에 &lt;code&gt;new Item&amp;lt;JavaBook&amp;gt;()&lt;/code&gt; 부분이 불가능한 것. 그래서 앞에 선언되는 타입과 뒤에 new 연산자 부분의 타입이 일치하니 java 1.7 부터는 new 연산자 부분에 타입이 생략이 가능해졌다. &lt;/p&gt;
&lt;h5&gt;타입 변수 T의 타입 제한&lt;/h5&gt;
&lt;p&gt;그렇다면 T로 선언하면 결국 모든 타입을 다 받을 수 있는거 아니야? 라고해서 제한을 주기 위해 &lt;code&gt;extends&lt;/code&gt; 라는 키워드를 제공해서 해당 클래스의 상속 관계인 클래스만 타입을 넣을 수 있도록 제공을 해준다. &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class Item&amp;lt;T extends Book&amp;gt; { }

public class Book { }

public class JavaBook extends Book { }

public class Drink { }&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;위와 같은 클래스가 존재한다고 할 때 &lt;code&gt;Item&amp;lt;Book&amp;gt; book = new Item&amp;lt;&amp;gt;()&lt;/code&gt; 나  &lt;code&gt;Item&amp;lt;JavaBook&amp;gt; javaBook = new Item&amp;lt;&amp;gt;()&lt;/code&gt;는 사용이 가능하지만, &lt;code&gt;Book&lt;/code&gt; 클래스와 관계가 없는 &lt;code&gt;Drink&lt;/code&gt;는 사용이 불가능하다 &lt;code&gt;Item&amp;lt;Drink&amp;gt; drink = new Item&amp;lt;&amp;gt;();&lt;/code&gt; 사용 불가, &lt;/p&gt;
&lt;p&gt;추가로 인터페이스의 구현을 해야 한다는 제약이 필요하면 마찬가지로 &lt;code&gt;implements&lt;/code&gt;가 아닌 &lt;code&gt;extends&lt;/code&gt; 키워드를 사용하고 여러개일 경우 &lt;code&gt;&amp;amp;&lt;/code&gt;라는 키워드로 연결해주면 된다 . &lt;code&gt;public class Item&amp;lt;T extends Book &amp;amp; List&amp;gt; { }&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;와일드 카드&lt;/h2&gt;
&lt;p&gt;기존의 &lt;code&gt;Item&lt;/code&gt;을 매개변수로 받는 static 메소드를 가지는 클래스를 하나 생성해보자.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class Printer {    
    static void printItem(Item&amp;lt;Book&amp;gt; item) {
        System.out.println(&amp;quot;Book 타입의 item&amp;quot;);
    }
    static void printItem(Item&amp;lt;JavaBook&amp;gt; item) {
        System.out.println(&amp;quot;JavaBook 타입의 item&amp;quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;여기서 &lt;code&gt;Item&lt;/code&gt; 자체는 extends란 키워드를 사용해서 상속 관계의 제한을 걸어둔 상태이다. 그러면 현재 &lt;code&gt;Item&lt;/code&gt;은 Book 타입과 JavaBook 타입 둘다 가질 수 있는 상태인데, 해당 메서드는 Book 타입만 지원을 한다. 그렇다면 메소드 오버로딩을 사용해서 아래와 같이 추가하면 해결이 될까? 안타깝게도 &lt;strong&gt;지네릭만 다르다고 오버로딩은 성립되지 않는다.&lt;/strong&gt; 그래서 등장한게 와일드 카드라는 개념이다.&lt;br&gt;&lt;code&gt;?&lt;/code&gt;라는 기호로 사용하면 해당 지네릭은 어떤 타입도 될 수 있다는 표현이다. &lt;/p&gt;
&lt;p&gt;기존의 메소들를 아래와 같이 변경 &lt;code&gt;static void printItem(Item&amp;lt;?&amp;gt; item) { }&lt;/code&gt; 와일드 카드도 제한을 줄 수 있는 키워드를 제공 하는데 &lt;code&gt;extends&lt;/code&gt;와 &lt;code&gt;super&lt;/code&gt;이다 각각 본인과 자손, 본인과 조상들까지 제한을 걸 수 있다.&lt;/p&gt;
&lt;h2&gt;제너릭 메서드&lt;/h2&gt;
&lt;p&gt;메소드의 반환 타입앞에 타입 변수 를 선언하는 메서드를 말한다&lt;br&gt;&lt;code&gt;static &amp;lt;T&amp;gt; void sort(List&amp;lt;T&amp;gt; list, Comparator&amp;lt; ? super T &amp;gt; c )&lt;/code&gt; 여기서 매개변수의 T와 메소드에 선언된 T는 별개의 타입 변수란 점을 기억해야 한다. &lt;/p&gt;</description>
      <category>PROGRAMMING/JAVA</category>
      <category>Java</category>
      <category>자바</category>
      <category>지네릭</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/134</guid>
      <comments>https://lee1535.tistory.com/134#entry134comment</comments>
      <pubDate>Fri, 15 May 2020 10:24:57 +0900</pubDate>
    </item>
    <item>
      <title>[JAVA/JPA] 값 타입</title>
      <link>https://lee1535.tistory.com/130</link>
      <description>&lt;p&gt;해당 내용은 인프런의 &lt;code&gt;자바 ORM 표준 JPA 프로그래밍 - 기본편, 김영한&lt;/code&gt; 의 내용을 기반으로 정리해서 작성한 글입니다.&lt;br&gt;자세한 내용은 해당 강의 또는 책을 구매하시는걸 추천합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;JAP는 크게 값 타입을 2종류로 분류한다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;엔티티 타입 -&amp;gt; Entity로 정의된 객체 , 데이터가 변해도 식별자로 지속해서 추적 가능&lt;/li&gt;
&lt;li&gt;값 타입 -&amp;gt; int, Integer처럼 단순히 값으로 사용되는 기본 자료형 또는 래퍼클래스 또는 String&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;값 타입 분류&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;기본 값 타입&lt;ol&gt;
&lt;li&gt;자바 기본 타입 int float&lt;/li&gt;
&lt;li&gt;래퍼 클래스 Integer Double Float&lt;/li&gt;
&lt;li&gt;String&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;임베디드 타입&lt;ol&gt;
&lt;li&gt;좌표를 묶어서 쓰고 싶은 값 ex)포지션 클래스 -&amp;gt; 포지션 클래스 자체를 값 처럼 쓰는걸 임데디드 타입&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;컬렉션 타입 -&amp;gt; java 컬렉션&lt;/li&gt;
&lt;/ol&gt;
&lt;h5&gt;기본값 타입&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;String name, int age&lt;/li&gt;
&lt;li&gt;생명주기를 엔티티의 의존&lt;/li&gt;
&lt;li&gt;값 타입은 공유 x ex) &lt;code&gt;int a = 10 ; int b = a;&lt;/code&gt; 일때 a = 30 으로 변경 해도 b는 10 그대로&lt;/li&gt;
&lt;li&gt;래퍼 클래스는 공유는 가능하나, 기본적으로 java에서는 값을 변화시킬 수가 없기 때문에 변경이 불가능함 사이드 이펙트 발생 x&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;임베디드 타입 ( 복합 값 타입 )&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;새로운 값 타입을 정의할 수 있음 이를 JPA는 임베디드 타입이라고 함&lt;/li&gt;
&lt;li&gt;주로 기본 값 타입을 모아서 만들어서 복합 값 타입이라고도 함&lt;/li&gt;
&lt;li&gt;int, String과 같은 값 타입의 모음&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;예제로 멤버는 이름 아이디 근무시간 (startDate, endDate)를 묶고 주소 (address, zipCode, city ) 등을 묶은 임베디드 타입을 만들 수 있다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;장점 : 재사용, 높은 응집도, Period.isWokr() 처럼 해당 값 타입만 사용하는 의미 있는 메소드를 만들 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;임베디드 타입을 포함한 모든 값 타입은, 값 타임을 소유한 엔티티에 생명주기를 의존함, 기본 생성자가 필수&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Entity
public class Member {
    @Id @GeneratedValue
    @Column(name = &amp;quot;member_id&amp;quot;)
    private Long id;
    private String name

    // 기간 
    @Embedded // 해당 어노테이션은 생략 가능하나,유지보수 측면에서 사용을 권장 해당 클래스만 보고 임베디드 타입인지 알 수 있음
    private Period workPeriod;

    // 주소
    @Embedded
    private Address homeAddress
}

// 값 타입은 @Embeddable를 선언
@Embeddable
public clas Period{

    private LocalDateTime startDate;
    private LocalDateTime endTime;

    public void getWorkTime() {  
        ... ( 근무 시간과 관련된 로직 ) 
    } 
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위 방식처럼 좀 더 entity를 객체스럽게 테이블 구조와 다르게 역할에 따라 분리하고, 하나의 테이블로 사용 가능&lt;br&gt;엔티티와 값 타입임을 명시해야 하며 둘 중 한곳에만 해도 되지만 유지보수성 을 위해 둘다 사용을 권장&lt;/p&gt;
&lt;p&gt;공통으로 사용 가능&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Entity&lt;/code&gt;와 마찬가지로 &lt;code&gt;@Column&lt;/code&gt;등 사용가능하고, 값 으로 &lt;code&gt;Entity&lt;/code&gt;도 가질 수 있다&lt;/p&gt;
&lt;h5&gt;동일한 Embeded 객체 사용&lt;/h5&gt;
&lt;p&gt;값으로 동일한 객체를 쓰고 싶은 경우 @AttributeOverride 속성 재정의해서 사용 가능, 필요하면 참고할것&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Entity
public class Member {
    @Id @GeneratedValue
    @Column(name = &amp;quot;member_id&amp;quot;)
    private Long id;

    @Embedded
    private Address homeAddress // Address 객체 중복

    @Embedded
    private Address workAddress // Address 객체 중복
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같을 경우 Address를 두번 사용하기 때문에 오류 발생 아래와 같이 새로 매핑을 해줘야 사용 가능&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Entity
public class Member {
    @Id @GeneratedValue
    @Column(name = &amp;quot;member_id&amp;quot;)
    private Long id;
    private String name

    // 기간 
    @Embedded // 둘중 하나만 써도 되나 유지보수 측면에서 사용을 권장
    private Period workPeriod;

    // 주소
    @Embedded
    private Address homeAddress

    @Embedded
    @AttributeOverrides({
        @AttributeOverride(name=&amp;quot;city&amp;quot;, column=@Column(name = &amp;quot;work_city&amp;quot;)), // 이런식으로
    })
    private Address workAddress;
}&lt;/code&gt;&lt;/pre&gt;&lt;h5&gt;정리&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;임베디드 타입은 엔티티의 &lt;strong&gt;값일 뿐이다.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;임베디드 타입을 사용해도 매핑되는 테이블은 변경이 없다. 그냥 추출일 뿐&lt;/li&gt;
&lt;li&gt;공통되는 로직을 재사용할 수 있게 해준다. ex) 좌표 계산이나, 주소를 리턴해주는 로직 등&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;값 타입과 불변 객체&lt;/h2&gt;
&lt;p&gt;값 타입은 복잡한 객체 세상을 조금이라도 단순화하려고 만든 개념이다. 따라서 값 타입은 단순하고 안전하게 다룰 수 있어야 한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;값 타입 공유 참조&lt;ul&gt;
&lt;li&gt;임베디드 타입 같은 값 타입은 여러 엔티티에서 공유하면 위험함, 즉 객체이기 때문에 참조 값으로 여러개가 묶일 수 있다. 이럴 경우 참조된 모든 객체에 영향을 주기 때문에 위험&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;값 타입을 불변 객체로 만든다. String, Integer 처럼...&lt;ul&gt;
&lt;li&gt;setter을 제거하고 getter만 만들어둔다.&lt;/li&gt;
&lt;li&gt;builder 패턴을 통해 객체 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;값 타입은 동등성 동일성 비교 인스턴스 참조 값 비교 동일성 값 자체 비교는 동등성 -&amp;gt; equals,hash를 모든 필드에 대해서 재정의 해야 함&lt;/p&gt;
&lt;h2&gt;값 타입 컬렉션&lt;/h2&gt;
&lt;p&gt;값 타입 자체를 컬렉션에 담아서 사용하는 경우를 말함&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Embedded
private Address homeAdderss;

@ElementCollection
@CollectionTable( name = &amp;quot;addres_history&amp;quot; , joinColumns = @JoinColumn(name = &amp;quot;member_id&amp;quot;))
private List&amp;lt;address&amp;gt; addressHistory ; // 와 같은 형식

@ElementCollection
@CollectionTable( name = &amp;quot;favorite_food&amp;quot; , joinColumns = @JoinColumn(name = &amp;quot;member_id&amp;quot;))
@Column(name = &amp;quot;food_name&amp;quot;)
private List&amp;lt;String&amp;gt; favoriteFood ; // 와 같은 형식&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이때 테이블은 1:N 이기 때문에 객체에서는 한번에 표현 가능하지만 테이블은 별도의 테이블로 생성이 된다.&lt;br&gt;이때 &lt;code&gt;favorite_food&lt;/code&gt; 같은 경우 필드가 하나일때그냥 &lt;code&gt;@Column&lt;/code&gt; 선언가능&lt;/p&gt;
&lt;p&gt;이력 테이블용으로 사용이 용이, 기본적으로 지연 로딩, member만 persist해도 전부다 값이 들어감.&lt;br&gt;왜냐 값타입이기 때문 그냥 Member의 컬럼 취급을 하기 때문&lt;/p&gt;
&lt;p&gt;컬렉션도 값타입과 마찬가지로 불변객체여야 한다 side effective가 발생할 확률이 높음&lt;br&gt;객체를 새로 복사해서 통으로 값을 복사&amp;amp;변경 하던가, 별도의 메소드를 통해서 속성에 접근하는 방식을 구현할 것&lt;/p&gt;
&lt;h5&gt;값 타입의 컬렉션 변경&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;값 타입은 엔티티와 다르게 식별자 개념이 없다. 그래서 값은 변경하면 추적이 어렵다&lt;/li&gt;
&lt;li&gt;값 타입 컬렉션에 변경 사항이 발생하면 주인 엔티티와 연관된 모든 데이터를 삭제하고, 값 타입 컬렉션에 있는 현재 값을 모두 다시 저장한다.&lt;/li&gt;
&lt;li&gt;값 타입 컬렉션을 매핑하는 테이블은 키값이 없기 때뭉네, 모든 컬럼을 묶어서 기본 키를 구성해야 함 -&amp;gt; null 입력 x, 중복 저장 x&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;위와 같이 문제 때문에 관계가 복잡해질 경우, 값 타입 컬렉션 대신 일대다 관계를 고려할 것 ( 엔티티로 값 타입을 빼기 )&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Entity
public class AddressEntity {

    @Id
    Long id

    private Address address;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;로 변경 후&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;// Member entity
@OneToMany ( casecade = CascadeType.ALL , orphanRemoval = true)  
@JoinColumn( name = &amp;quot;member_id&amp;quot;)
private List&amp;lt;AddressEntity&amp;gt; addressHistory = new ArrayList&amp;lt;&amp;gt;();
// 위와 같이 사용  실무에서 더 사용이 용이함
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;casecade = CascadeType.ALL&lt;/code&gt; 속성의 경우 &lt;code&gt;Member&lt;/code&gt;을 저장할 때 &lt;code&gt;AddressEntity&lt;/code&gt; 도 같이 저장하는 전파 속성&lt;br&gt;&lt;code&gt;orphanRemoval = true&lt;/code&gt; 는 연관관계가 끊긴 엔티티를 테이블에서도 자동으로 삭제쿼리를 실행하는 속성&lt;/p&gt;
&lt;h5&gt;결론 : 값 타입 컬렉션 대신 엔티티로 승격해서 사용해라. 엔티티로 만들어야 할지 값 타입인지 잘 구분할것, 식별자가 필요한지 우뮤, 사용할 경우 진짜 단순하게 셀렉트 박스에 치킨, 피자를 멀티로 선택가능한 셀렉트 박스일 경우, 이런 단순한 경우에만 사용, 추적할 필요도 없고 값이 바뀌어도 업데이트 칠 필요가 없는 경우&lt;/h5&gt;</description>
      <category>PROGRAMMING/JAVA</category>
      <category>Java</category>
      <category>JPA</category>
      <category>값 타입</category>
      <category>값 타입 컬렉션</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/130</guid>
      <comments>https://lee1535.tistory.com/130#entry130comment</comments>
      <pubDate>Mon, 13 Apr 2020 23:11:38 +0900</pubDate>
    </item>
    <item>
      <title>[JAVA/JPA] 상속관계 매핑</title>
      <link>https://lee1535.tistory.com/128</link>
      <description>&lt;p&gt;해당 내용은 인프런의 &lt;code&gt;자바 ORM 표준 JPA 프로그래밍 - 기본편, 김영한&lt;/code&gt; 의 내용을 기반으로 정리해서 작성한 글입니다.&lt;br&gt;자세한 내용은 해당 강의 또는 책을 구매하시는걸 추천합니다.&lt;/p&gt;
&lt;h2&gt;1. 테이블의 상속&lt;/h2&gt;
&lt;p&gt;상속을 테이블로 구현하기 위해서는 3가지 방법이 존재&lt;/p&gt;
&lt;ul&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;JPA에서는 기본 전략으로 싱글 테이블을 따름&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Entity public class Item {
    // 필드
 }

@Entity public Book extends Item{
 // 필드
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;실제 테이블 생성 쿼리를 보면 Item, Book 클래스의 필드를 모두 가지는 테이블을 생성&lt;/p&gt;
&lt;h2&gt;2. 조인 전략&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;@Entity 
@Inheritance(strategy = InheritanceType.JOINED)
public class Item {
    // 필드
 }

@Entity public Book extends Item{
 // 필드
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;이렇게 사용하면 하위 클래스에 매핑되는 테이블에 자동으로 외래키가 기본키로 생성됨, 정규화되어서 테이블을 생성해준다. 실제 JPA 엔티티 설계와 제일 비슷한 모양으로 테이블이 설계가 됨&lt;/p&gt;
&lt;p&gt;그래서 하위 클래스에 값을 넣어도 상위 클래스에도 테이블에도 값이 들어감&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    Book book = new Book();
    book.setName(&amp;quot;연습용 책&amp;quot;);
    book.set...
    ...&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;위와 같은 로직을 수행하면 &lt;code&gt;Book&lt;/code&gt;,&lt;code&gt;Item&lt;/code&gt;에 동일한 key 값이 들어가고 각각 맞는 컬럼에 값이 추가된다. 또한 하위 클래스를 셀렉트할 경우 상위 클래스를 조인해서 값을 조회해온다.&lt;/p&gt;
&lt;p&gt;추가로 &lt;code&gt;@DiscriminatorColumn(name=&amp;quot;사용할 컬럼명&amp;quot;)&lt;/code&gt; 으로 사용할 경우 부모 테이블에 &lt;code&gt;DTYPE&lt;/code&gt;가 자동으로 추가&lt;br&gt;&lt;code&gt;DTYPE&lt;/code&gt;이 있을 경우 ITEM 테이블만 가지고 운영또는 조회할경우 어느 하위 테이블의 타입 객체인지 알 수 있기 때문&lt;/p&gt;
&lt;p&gt;&lt;code&gt;DTYPE&lt;/code&gt;에 들어가는 이름은 기본적으로 &lt;code&gt;Entity&lt;/code&gt; 네임이 들어감 변경하고 싶은 경우, 하위 클래스에서 &lt;code&gt;@DiscriiminatorValue(&amp;quot;설정할 값&amp;quot;)&lt;/code&gt; 으로 설정가능&lt;/p&gt;
&lt;h2&gt;3. 싱글테이블 전략 ( 기본전략이기도함 )&lt;/h2&gt;
&lt;p&gt;기본전략으로 나와있기 때문에 설명은 생략. 다만 &lt;code&gt;@DiscriminatorColumn&lt;/code&gt;은 필수로 넣어야지 어떤 타입인지 알 수 있기 때문에 필수로 선언할 것, 기본적으로 해당 하위 객체 컬럼의 값이 있냐 없냐등의 로직으로 구분 가능하겠지만 불필요한 작업&lt;/p&gt;
&lt;p&gt;타입을 추가해서 해당 테이블의 데이터가 Book인지 Movie인지 즉 어떤 타입인지 알 수 있게 추가가 필요함&lt;/p&gt;
&lt;h2&gt;테이블당 구현 전략&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;@Entity 
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Item {
    // 필드
 }

@Entity public Book extends Item{
 // 필드
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;하위 클래스를 전부다 테이블로 만드는 전략으로 &lt;strong&gt;상위 클래스를 추상클래스로 정의&lt;/strong&gt;, 전략을 &lt;code&gt;TABLE\_PER\_CLASS&lt;/code&gt;로 변경&lt;br&gt;&lt;code&gt;@DiscriminatorColumn&lt;/code&gt;은 의미가 없어서 사용해도 적용안됨 -&amp;gt; 테이블 자체가 구분이 되기 때문&lt;/p&gt;
&lt;p&gt;그러나 상위 클래스 즉 ITEM이 없는 테이블이기 때문에 객체지향적으로 &lt;code&gt;ITEM&lt;/code&gt;으로 셀렉트할 경우, 모든 테이블을 다 조회 &lt;code&gt;union&lt;/code&gt;후 있는 값을 리턴해주는 불필요하고, 어려운 로직이 동작됨. 얼핏 간단하고 쉬워보이지만 단점이 많다.&lt;/p&gt;
&lt;h5&gt;정리&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;조인 전략&lt;ul&gt;
&lt;li&gt;장점&lt;ul&gt;
&lt;li&gt;테이블 정규화&lt;/li&gt;
&lt;li&gt;외래 키 참조 무결성 제약조건 활용가능&lt;/li&gt;
&lt;li&gt;저장공간 효율화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;단점&lt;ul&gt;
&lt;li&gt;조회시 조인을 많이 사용. 성능 저하&lt;/li&gt;
&lt;li&gt;조회 쿼리가 복잡&lt;/li&gt;
&lt;li&gt;데이터 저장시 insert가 부모 클래스 만큼 동작 ex) 예제에선 2번&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;단일 테이블 전략&lt;ul&gt;
&lt;li&gt;장점&lt;ul&gt;
&lt;li&gt;조인이 필요x 성능이 제일 빠름, 쿼리가 단순&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;단점&lt;ul&gt;
&lt;li&gt;자식 entity 의 컬럼을 모두 null 허용 해야함.. 데이터 무결성에 문제가 생김&lt;/li&gt;
&lt;li&gt;오히려 테이블의 컬럼이 너무 많아져서 더 느려질 수 도 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;구현 클래스마다 테이블 전략 ( 사용하면 안됨 )&lt;ul&gt;
&lt;li&gt;장점&lt;ul&gt;
&lt;li&gt;테이블 하나하나로 조회할 땐 효과적, not null 제약조건 가능&lt;ul&gt;
&lt;li&gt;단점&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;자식 테이블 관리가 힘들다, 쿼리가 복잡해진다. 유지보수성이 어렵다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;@MappedSuperclass&lt;/h2&gt;
&lt;p&gt;실제 상속이나 DB는 서로 관계가 없지만, 공통으로 들어가는 컬럼을 추가할 때 사용&lt;br&gt;ex) 등록, 수정, 삭제,수정일, 수정자, 등등이 모든 테이블에 필요하다는 조건이 있을 경우&lt;/p&gt;
&lt;p&gt;상속 관계 매핑이 아님, 매핑 정보만 제공 하기 때문에 &lt;code&gt;BaseEntity&lt;/code&gt; 조회나 검색이 안됨 (find 사용 불가능), 그래서 추상 클래스로 사용을 권장, 그래야 사용 시점에 해당 클래스를 조작하지 않고 구현체를 조작하기 때문에&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@MappedSuperclass
public abstract class BaseEntity{
    @Column(name =&amp;quot;createMemberId&amp;quot;)
    private String createdBy;
    private LocalDateTime createdDate;
    private String lastModifiedBy;
    private LocalDateTime lastModifiedDate;

    // 필요하면 getter // setter 추가
}

// 각각의 클래스에 BaseEntity를 상속받는다.
// 단독으로 저장할 필요가 없을 경우 추상 클래스로 구현하는것을 고려!! Itemp이든 BaseEntity처럼 말이다.
&lt;/code&gt;&lt;/pre&gt;&lt;h5&gt;정리&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;상속관계의 매핑이 아니다.&lt;/li&gt;
&lt;li&gt;엔티티처럼 @Column등 사용 가능하지만, 엔티티가 아니고, 테이블과 매핑이 되지 않는다.&lt;/li&gt;
&lt;li&gt;부모 클래스를 상속 받는 자식 클래스에게 매핑 정보만 제공&lt;/li&gt;
&lt;li&gt;조회나, 검색 등 불가, 같은 이유로 직접 사용할 이유가 없기 때문에 추상 클래스로 선언 권장&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>PROGRAMMING/JAVA</category>
      <category>Java</category>
      <category>JPA</category>
      <category>매핑</category>
      <category>상속관계</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/128</guid>
      <comments>https://lee1535.tistory.com/128#entry128comment</comments>
      <pubDate>Mon, 13 Apr 2020 14:36:11 +0900</pubDate>
    </item>
    <item>
      <title>[독서리뷰] 클린코드</title>
      <link>https://lee1535.tistory.com/127</link>
      <description>&lt;h2&gt;1. 깨끗한 코드&lt;/h2&gt;
&lt;p&gt;일정? 압박? 어떠한 이유로든 지저분한 코드를 지양하고, 깨끗한 코드를 만들려고 노력하라&lt;br&gt;&lt;code&gt;깨긋한 코드 : 가독성이 좋으며, 적당히 추상적이며 최소한의 일을 하고 중복이 적어야함&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;2. 의미 있는 이름&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;메소드, 변수 클래스 등 이름이라는 방법으로 최소한의 정보를 &amp;#39;정확&amp;#39;하게 전달해야 한다.&lt;/li&gt;
&lt;li&gt;여러개의 목록일 경우 실제 list에 담는게 아니라면 accountList 같이 list라는 예약어를 쓰지말고, accounts 등으로 명명&lt;/li&gt;
&lt;li&gt;불용어를 피하며, getCustomer(), getCustomerInfo()와 같이 구분이 불분명하게 사용을 피하라&lt;/li&gt;
&lt;li&gt;인코딩을 피해라.. 단 인터페이스나 구체 클래스의 경우 imp정도는 사용하는게 가독성이 좋음.&lt;/li&gt;
&lt;li&gt;클래스명은 명사나 명사구, Data, Info같은 포괄적인 단어는 피하고 동사 사용 금지&lt;/li&gt;
&lt;li&gt;동사구를 사용 save, delete 등등..&lt;/li&gt;
&lt;li&gt;한 개념에 한 단어를 사용 같은 메소드를 클래스마다 get, fetch 등 다르게 사용 하면 헷갈린다&lt;/li&gt;
&lt;li&gt;적절한 접두어 사용&lt;/li&gt;
&lt;li&gt;불필요한 맥락을 제거&lt;/li&gt;
&lt;li&gt;해법 영역 즉 silgleton 같이 친숙한 용어 사용 권장&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;결론 : 변수명이든, 클래스명이든, 함수명이든 이름이 중요하다&lt;/h5&gt;
&lt;h2&gt;3. 함수&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;함수는 한 가지를 해야 한다. 그 한가지를 잘 해야 한다. 그 한 가지만을 해야 한다. &lt;ul&gt;
&lt;li&gt;함수 당 추상화 수준은 하나로, 추상화 수준이 높은 함수의 경우 다른 함수도 높은 수준의 추상화를 구현해야 한다&lt;br&gt;ex) getHtml()은 상당히 높은 추상화 이와 같은 함수를 사용하는대 동시에 .append()와 같은 낲은 수준의 추상화를 같이 사용하지 말라.. 이러면 읽는 사람이 개념인지 세부사항을 구현한 함수인지 구분하기 어려워진다.&lt;/li&gt;
&lt;li&gt;부수효과를 발생하지 말아라&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;위에서 아래로 -&amp;gt; 추상화 수준이 낮아지는 방식으로 이야기를 읽듯이 구현&lt;/li&gt;
&lt;li&gt;모듈내에서 함수 이름은 같은 문구, 명사, 동사를 사용한다&lt;/li&gt;
&lt;li&gt;인수는 0개가 이상적.그 다음이 1,2, 3이상부터는 가능하면 피하는게 좋다 4는 특별한 이유 아니고선 무조건 피하기&lt;ul&gt;
&lt;li&gt;인수가 많아질수록 독자가 함수 파악이 어려워진다. ex render(boolean isSuite) 보다는 renderForSuite()가 한눈에 보기 편함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;인수가 많아지면, 클래스로 만드는 방법을 고려해봐라  &lt;/li&gt;
&lt;li&gt;객체 상태를 변경하거나, 객체 정보를 반환하거나 둘 중 하나이다. 둘다 사용하면 안된다.&lt;/li&gt;
&lt;li&gt;오류코드구문 if로 구분하지말고 try-catch로 구분&lt;/li&gt;
&lt;li&gt;반복하지 말아라.&lt;/li&gt;
&lt;li&gt;함수는 동사, 클래스는 명사&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;결론 : 이유불문, 함수는 최대한 작게 만들어라, 구현이 아니라 어떻게 풀어갈지 잘 서술하는 느낌으로 설계하라&lt;/h5&gt;
&lt;h2&gt;4. 주석&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;주석은 실패한코드, 잘 작성한 코드는 그 자체로 의도가 분명하다.&lt;/li&gt;
&lt;li&gt;프로그램은 변화하는데 그에 맞게 주석을 관리하기란 현실적으로 불가능! 그래서 주석은 최대한 피해라.&lt;/li&gt;
&lt;li&gt;그렇다면 좋은 주석은? 저작권라이센스, 정규식 설명, 의도 설명, TODO주석 Javadocs 등&lt;/li&gt;
&lt;li&gt;나쁜 주석은? 의무적 주석, 이력 주석, 닫히는 구문에 주석, 기본적인 설명 주석 등&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;결론 : 주석은 불필요하다. 단 필요한 경우도 존재하니 필요할때만 작성&lt;/h5&gt;
&lt;h2&gt;5. 형식 맞추기&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;적절한 행 길이를 유지하라.일반적으로 짧을수록 이해하기가 편하다.&lt;/li&gt;
&lt;li&gt;개념은 빈 행으로 분리해라 함수와 함수, 패키지와 클래스명 등등&lt;/li&gt;
&lt;li&gt;개념있는 관계는 세로로 밀집시켜라&lt;/li&gt;
&lt;li&gt;연관 관계의 함수끼리는 세로거리로 연관성을 표현한다 -&amp;gt; protected 변수를 피해야 하는 이유중 하나.. 부모 클래스를 가봐야 하니까&lt;/li&gt;
&lt;li&gt;변수선언은 사용하는 위치에 최대한 가까우 곳에 선언, 인스턴스는 클래스 맨 처음에&lt;/li&gt;
&lt;li&gt;가로 정렬은 기본적으로 강조의 의미가 불분명해져서 불필요.. 멤버가 길어지면 클래스를 쪼개는것을 고려&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;팀 규칙이 있다면 결국 그게 규칙이다.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;결론 : 형식을 맞춰서 가독성이 좋은 코드를 작성해야 한다.&lt;/h5&gt;
&lt;h2&gt;객체와 자료 구조&lt;/h2&gt;
&lt;p&gt;자료구조나 알고리즘의 경우 객체보단 절차적인 클래스가 좀 더 효율적&lt;/p&gt;
&lt;h5&gt;결론 : 새로운 타입을 추가하는 유연성이 필요하면 객체로, 새로운 동작이 추가되는 유연셩이 필요하면 자료 구조와 절차적인 코드가 더 적합하다.&lt;/h5&gt;
&lt;h2&gt;오류 처리&lt;/h2&gt;
&lt;p&gt;깨긋한 코드는 읽기도 중요하지만, 안정성도 높아야 한다. 오류 처리와 프로그램 논리를 분리하면 유지보수성이 크게 높아진다.&lt;/p&gt;
&lt;h2&gt;경계&lt;/h2&gt;
&lt;p&gt;경계에 위치하는 코드는 깔끔하게 분리, 테스트 케이스를 작성해둔다. 우리쪽 에서 외부 패키지를 자세하게 알 필요가 없다. 통제 불가능한 외부 api 대신 통제 가능한 내부에 의존하는게 좋다. 외부 패키지 호출코드를 줄여 경계를 관리하자. wrapper로 감싸거나 adapter 패턴을 사용해 우리가 원하는 인터페이스를 패키지가 제공하는 인터페이스로 변환하자.&lt;/p&gt;
&lt;h2&gt;단위 테스트&lt;/h2&gt;
&lt;ol&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;테스트의 F.I.R.S.T 5가지 조건&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Fast 빨라야 한다. 테스트가 느리면 테스트를 돌리기 부담스러움 -&amp;gt; 코드 품질 엉망으로 이어진다.&lt;/li&gt;
&lt;li&gt;Independent 독립적이어야 한다. 각 테스트는 독립적이고 어떤 순서로 실행해도 상관 없어야 한다.&lt;/li&gt;
&lt;li&gt;Repeatable 반복 가능하게 : QA호ㅓㅏㄴ경, 인터넷 환경에 상관없이 실행할 수 있어야 한다.&lt;/li&gt;
&lt;li&gt;Self-Validating 자가 검증하는 : 테스트는 bool 값으로 결과를 내야한다. 성공아니면 실패&lt;/li&gt;
&lt;li&gt;Timely 적시에 : 테스트는 적시에 작성해야한다. 단위 테스트는 테스트하려는 실제 코드를 구현하기 직전에 구현한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;클래스&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;클래스는 작아야한다. 함수에서의 작아야 한다는 의미가 아니라 단일 책임의 원칙을 지켜야 한다.&lt;ul&gt;
&lt;li&gt;얼만큼 작아야 하나? 함수는 물리적인 행 수로 크기를 측정했다면, 클래스는 맡은 책임을 센다.&lt;/li&gt;
&lt;li&gt;그렇다면 단일 책임이란 무엇인가? 클래스나 모듈을 변경할 이유가 하나뿐이어야 한다는 원칙이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;인터페이스를 사용한 변경으로부터 격리 사용하기, 외부 API를 받아올때 바로 사용하지말고 하나의 인터페이스를 두어서 호출&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;창발적 설계로 깔끔한 코드를 구현&lt;/h2&gt;
&lt;ul&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&gt;위에서부터 중요도 순서&lt;/p&gt;
&lt;h2&gt;살아있는 프로그램&lt;/h2&gt;
&lt;p&gt;그저 돌아가는 코드가 아닌, 점진적으로 개선하는 코드를 작성해라. 한번에 완벽한 프로그램을 만들 필요는 없다.&lt;br&gt;점점 개선해 나가면 된다. 저자는 테스트주도 개발을 기반으로 코드를 계속 리팩토링해 나간다.&lt;/p&gt;
&lt;h2&gt;마무리&lt;/h2&gt;
&lt;p&gt;책의 마지막 부분에는 실제 사례를 통해서 위 이론들을 어떻게 풀어가는지에 대해 자세히 나와있다.&lt;br&gt;책에는 위 내용 말고도 더 자세히 많은 내용이 담겨있으니, 깨긋한 코드란 무엇인지 고민해보고 싶은 사람이라면&lt;br&gt;한번쯤 아니 두번 세번 읽어봐야할 책인 것 같다.&lt;/p&gt;</description>
      <category>일상/독서</category>
      <category>독서리뷰</category>
      <category>클린코드</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/127</guid>
      <comments>https://lee1535.tistory.com/127#entry127comment</comments>
      <pubDate>Fri, 3 Apr 2020 14:11:03 +0900</pubDate>
    </item>
    <item>
      <title>[독서리뷰] 객체지향의 사실과 오해 리뷰</title>
      <link>https://lee1535.tistory.com/125</link>
      <description>&lt;p&gt;이책을 처음 알게된 시점은 인프런의 김영한님의 JPA 강의를 보는데 강의 초반에 해당 책을 짧게 소개해주면서 강의를 진행했습니다. 그리고 강의를 계속 보는데 객체적인 관점?에 대해 강조를 많이 하시고, 실제 듣다 보면 나도 객체지향적인 프로그래밍 방식을 사용하고 있지 않구나라는 생각이 들어 해당 책을 구매해서 읽어 보고 독후감 같은 느낌으로 내용을 정리해봅니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;292&quot; data-origin-height=&quot;400&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvFbxx/btqCPA4uD3f/xPopmUsDI9STZnK23cjw7k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvFbxx/btqCPA4uD3f/xPopmUsDI9STZnK23cjw7k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvFbxx/btqCPA4uD3f/xPopmUsDI9STZnK23cjw7k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvFbxx%2FbtqCPA4uD3f%2FxPopmUsDI9STZnK23cjw7k%2Fimg.jpg&quot; width=&quot;100%&quot; data-origin-width=&quot;292&quot; data-origin-height=&quot;400&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2&gt;시작하며&lt;/h2&gt;
&lt;p&gt;사실 객체 지향하면 떠오르는 &lt;code&gt;추상화&lt;/code&gt;, &lt;code&gt;캡슐화&lt;/code&gt;, &lt;code&gt;상속&lt;/code&gt;, &lt;code&gt;다형성&lt;/code&gt; 4개의 단어가 떠오릅니다.&lt;br /&gt;그리고 우린 이러한 객체 지향이란 특성을 이해하기 위해서 실제 세계를 기반으로 객체의 개념을 이해했습니다.&lt;br /&gt;예를 들어 저는 클래스는 붕어빵틀이고 객체는 붕어빵이다 라는 문구를 통해 &lt;code&gt;객체 = 클래스&lt;/code&gt; 라는 개념이 머리속에 자리잡혔던 것 같습니다. 이 책은 이런 저를 비웃기라도 하듯 &lt;b&gt;객체&lt;/b&gt;란 무엇인지 부터 설명을 시작합니다.&lt;/p&gt;
&lt;h5&gt;객체지향의 목표는 실세계를 모방하는 것이 아니다, 오히려 새로운 세계를 창조하는 것이다.&lt;/h5&gt;
&lt;p&gt;&lt;b&gt;객체란 실 세계를 모방하는 것이 아니다.&lt;/b&gt; 우리는 객체를 이해하기 위해 실세계를 모방 해왔습니다. 예를 들어 자동차 클래스를 만들고, 핸들, 기어 등을 가지며 전진, 후진 등의 기능을 가진 객체를 만들면서 객체의 속성과, 기능을 배워왔습니다. 하지만 실제로 프로그랭을 하면서 자동차, 붕어빵 등의 클래스를 만든 기억이 존재하나요? 물론 누군가는 있을수도 있지만 거의 존재하지 않습니다. 그렇다면 현실과 객체의 세계는 어떤 부분이 다를지 생각해봅니다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;객체간 메세지를 전달하며 상호 간 협력하는게 객체 지향입니다.&lt;/b&gt; 앞서 언급한 자동차의 경우 실 세계에선 '사람'이 '자동차'의 시동을 걸고, 주행을 할 뿐입니다. 그러나 객체 세계에서의 자동차는 스스로 시동걸기와, 주행의 기능을 가지고 있습니다. 그리고 '사람'은 '자동차'에게 요청(메세지)를 보낼 뿐입니다. 객체 세계에서의 자동차는 마치 하나의 생명체 같이 메세지를 받으면 자율적으로 메세지에 대한 처리를 합니다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;결론 : 실제는 객체와 현실은 전혀 다른 세계이기 때문에 그 차이를 인지하고 객체지향적으로 접근하는 것&lt;/b&gt;&lt;/p&gt;
&lt;h2&gt;그래서 객체란 무엇이고 객체 지향의 본질은 무엇인데?&lt;/h2&gt;
&lt;h5&gt;이 책에서는 객체가 객체 답기 위해선 아래 3가지를 충족해야 한다고 정의합니다&lt;/h5&gt;
&lt;ul&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;/p&gt;
&lt;h5&gt;객체 지향의 본질에 대해서는 아래와 같이 정의합니다&lt;/h5&gt;
&lt;ul&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&gt;여기서 1,2번은 앞서 설명한 내용과 중복이 됩니다. 그만큼 이 책에서 강조하는 부분이라 생각합니다. 추가로 눈치가 빠르신 분들은 &lt;code&gt;객체&lt;/code&gt;라는 단어 말고 &lt;code&gt;역할&lt;/code&gt;, &lt;code&gt;책임&lt;/code&gt;, &lt;code&gt;협력&lt;/code&gt;, &lt;code&gt;메세지&lt;/code&gt;,라는 단어가 계속 반복해서 나오는걸 눈치채셨을 겁니다. 이 키워드들은 앞으로 계속 강조되는 부분이니 기억해두길 바랍니다.&lt;/p&gt;
&lt;h2&gt;객체의 행동, 상태, 식별자&lt;/h2&gt;
&lt;p&gt;우리는 방금까지 객체는 어때야 하고, 객체 지향이란 어떤것인지에 대해 알아봤습니다. 이제 &lt;code&gt;객체&lt;/code&gt;란 무엇인지 조금 더 구체적으로 설명을 합니다. 이 책인 객체를 다음과 같이 정의합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;객체란 식별 가능한 개체 또는 사물이다. 구체적인 사물또는 추상적인 개념일 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이러한 객체들의 상태를 변경할 수 있는것은 오로지 객체 자신의 행동입니다. 여기서 행동에 대해서 이책은 아래와 같이 정의합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;행동이란 외부의 요청 또는 수신된 메세지에 응답하기 위해 동작하고 반응하는 활동. 활동의 결과로 객체는 자신의 상태를 변경하거나 객체에게 메세지를 전달할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;마지막으로 식별자란 말 그대로 객체는 식별이 가능하다는 뜻입니다. 현실 세계이든 객체 세계이는 상태의 변화는 존재합니다. 여기서 우리가 &lt;code&gt;Member member = new Member&lt;/code&gt; 이라고 선언 후, &lt;code&gt;member.setName(&quot;Lee&quot;)&lt;/code&gt; 로 객체를 선언했고, 동일하게 &lt;code&gt;member2&lt;/code&gt; 객체를 만들어준다. 이때 name이 같다고 해서 두 객체는 같은 객체라고 할 수 있는가? 당연히 아닙니다. name이 동등할 뿐이지 두 객체가 동일하지는 않다는 말입니다.&lt;/p&gt;
&lt;h5&gt;모든 것은 행동이 상태를 결정한다&lt;/h5&gt;
&lt;p&gt;위 주제가 핵심 주제라고 생각합니다. 예를 들어 우리가 &lt;code&gt;Car&lt;/code&gt; 클래스를 하나 만든다고 생각해봅니다. 이때 우리는 어떻게 합니까? 저의 경우 아래와 같이 행동 할 것 입니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;클래스를 하나 생성한다.&lt;/li&gt;
&lt;li&gt;속성을 정한다. id 값을 넣고, 자동차의 모델명, 색상, 바퀴 등등등..&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이 책은 이와 같은 접근 방법은 잘못되었다고 정의합니다. 우리가 만드는 협력 속에서 Car 객체는 어떤 객체와 어떤 메세지를 주고 받을지 예상을 하고 객체의 속성을 결정하는가? &lt;b&gt;즉 행동을 생각한 후 행동을 수행할 객체를 선택, 필요한 속성이 결정되어야 합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;협력안에서의 객체의 행동은 객체가 완수해야할 책임이라고 표현합니다. 따라서 어떤 행동 즉 책임이 필요한가를 결정하는 과정이 전체 설계를 주도해야 합니다. 이에 따라 객체가 선택되고 속성이 정의되어야 합니다. 이 같은 방법을 따르면 &lt;b&gt;응집도 높고 재사용이 가능한 객체&lt;/b&gt;를 만들 수 있게 해줍니다.&lt;/p&gt;
&lt;h5&gt;타입과 추상화&lt;/h5&gt;
&lt;p&gt;도로 위 여러 종류의 승용자, 트럭, 화물차 등이 달리고 있을 때 우리는 '차'라는 분류로 하나로 묶을 수 있다. 이와 같이 사물들의 공통접을 취하고 차이점은 버리는 &lt;b&gt;일반화를 통해 단순화하는 것을 추상화라고 합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;객체지향에서의 추상화는 중요합니다. 이런 추상화를 통해서 나오는게 객체의 타입입니다.&lt;br /&gt;그렇다면 타입을 결정짓는 요소는 무엇인가? 결국엔 여기서도 &lt;code&gt;행동&lt;/code&gt;이다. 어떤 행동에 따라 객체들을 분류하고, 추상화해서 타입이 결정된다. 그리고 이러한 타입을 구현할 수 있는 한가지 방법이 클래스일 뿐 클래스는 객체가 아닙니다.&lt;/p&gt;
&lt;p&gt;타입이 같은 객체끼리 같은 메세지를 수신하지만, 결과적으로 각 객체별로 내부 표현 방식이 다를 수 있기 때문에, 동일한 메세지에 대한 처리가 다릅니다. 이를 &lt;code&gt;다형성&lt;/code&gt;이라고 말합니다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;결론 : 즉 객체의 타입이든, 속성이든 정의를 하기 위해선 객체와 객체 사이 어떤 메세지가 주고 받을지 즉 행동을 최우선으로 생각하고, 그에 따른 객체의 타입과 속성을 결정해야 합니다.&lt;/b&gt;&lt;/p&gt;
&lt;h2&gt;역할, 책임, 협력&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;역할&lt;/code&gt;, &lt;code&gt;책임&lt;/code&gt;, &lt;code&gt;협력&lt;/code&gt;, &lt;code&gt;메세지&lt;/code&gt; 키워드 중 메세지에 대한 중요성과 설명을 했고, 쉬어가는 타임으로 역할, 책임, 협력에 대해서 알아보겠습니다.&lt;/p&gt;
&lt;p&gt;협력은 말 그대로 협력입니다. 객체는 협력속에서 책임에 따른 역할이 존재합니다.&lt;br /&gt;예를 들어 어떤 사람이 자동차에 시동을 걸고 전진한다고 생각해봅니다.&lt;/p&gt;
&lt;p&gt;이때 사람이라는 역할은 제가 될 수도, 여러분이 될 수도 자동차라는 역할은 승용차, 세단, 트럭 어떤 객체가 될 지 모릅니다. 여기서 '사람' 이라는 역할과 '자동차'라는 역할을 만들어서 협력을 구성했습니다. 이렇게 '역할'은 &lt;b&gt;객체의 추상화&lt;/b&gt;입니다.&lt;br /&gt;또한, &lt;b&gt;협력 또한 추상화&lt;/b&gt;할 수 있습니다. 예를 들어 제가 승용차에 시동을 건다, 제가 트럭에 시동을 건다.. 와 같은 협력을 사람이 시동을 건다. 라는 간단한 협력으로 추상화할 수 있게 해줍니다.&lt;/p&gt;
&lt;p&gt;위 과정에서 어떤 객체가 요청에 대해 대답해 줄 수 있거나, 적절한 행동을 할 의무가 있는 경우 객체가 책임을 가진다고 말합니다.&lt;br /&gt;예시에서 사람이라는 역할이 자동차라는 역할에게 시동을 걸라는 메세지를 요청합니다. 이때 자동차라는 역할은 스스로 시동을 걸고 어떠한 행동이나 응답을 해야 한다는 책임이 생깁니다.&lt;br /&gt;이와 같은 과정에서 자동차마다 시동을 거는 방식이 다를겁니다. 이를 시동을 건다 라는 책임으로 인터페이스를 구성합니다.&lt;/p&gt;
&lt;h2&gt;객체지향 설계 기법&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;책임주도 설계
&lt;ul&gt;
&lt;li&gt;협력에서 책임 식별후, 적합한 객체에 책임을 할당하는 방식&lt;/li&gt;
&lt;li&gt;여태 강조한 협력속에서 어떤 책임이 필요하고, 어떤 객체가 필요한지 결정하는 과정이 전체 설계 자체를 주도하는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;디자인 패턴
&lt;ul&gt;
&lt;li&gt;정해진 협력, 책임, 역할의 템플릿으로, 책임-주도 설계의 절차를 따르지 않고도, 빠르게 협력, 책임, 역할을 선택 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;테스트 주도 개발
&lt;ul&gt;
&lt;li&gt;책임을 수행할 객체 또는 클라이언트가 기대하는 객체의 역할이 메세지를 수신할 때 어떤 결과를 반환하고, 그 과정에서 어떤 객체와 협력할 것인지에 대한 기대를 코드의 형태로 작성하는 방식&lt;/li&gt;
&lt;li&gt;이 과정에서, 테스트 코드는 덤이고, 리팩토링의 이점도 존재&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;객체를 올바르게 설계하기&lt;/h5&gt;
&lt;ul&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;b&gt;결론 : 협력을 설계하고, 협력에서의 책임을 기준으로 전체적인 설계가 주도되어야 한다.쉽게 말해 메세지를 먼저 정하고, 해당 책임들을 역할(객체)에개 적절하게 할당하는 방식으로 설계가 주도되어야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;h2&gt;책임과 메세지&lt;/h2&gt;
&lt;p&gt;&lt;b&gt;객체 지향의 강력함을 누리기 위한 출발점은 책임을 자율적으로 만드는 것입니다.&lt;/b&gt; 그리고 이것은 여러분이 선택하는 메세지에 따라 달라집니다.&lt;br /&gt;자율적인 객체란? 객체 스스로 판단에 따라 책임을 수행하는 것을 뜻하며, 또한 해당 책임에 따라 적절한 객체를 할당하는 과정이 객체 지향의 설계입니다. 이 때문에 책임-주도 설계 방식이 널리 사용&lt;/p&gt;
&lt;p&gt;객체는 스스로 판단에 따라 책임을 수행해야 한다고 말했습니다. 그렇기 때문에 메세지는 너무 세세한 요구를 하면 객체의 자율성을 무너뜨립니다.&lt;br /&gt;예를들어, 자동차가 시동을 걸어야 하는 책임이 있다고 가정합니다. 이때, 세세하게 스마트 키를 이용해서 시동을 걸어라, 일반 키를 이용해서 시동을 걸어라 등의 세세한 메세지는 객체의 자율성을 무너트립니다. 자율적인 객체는 스스로가 판단해서 스마트키이든, 일반 키 방식이든 선택해서 시동을 걸어야 합니다.&lt;br /&gt;그렇다고 너무 추상적인 책임은 좋지 못합니다. 예를 들어 그냥 시동을 걸어라일 경우, 자동차의 시동인지 오토바이의 시동인지 알 수 없기 때문입니다. &lt;b&gt;따라서 협력 관계 속에서 절절한 수준에서 추상적으로 책임을 선택해야합니다.&lt;/b&gt;&lt;/p&gt;
&lt;h5&gt;인터페이스, 다형성&lt;/h5&gt;
&lt;p&gt;자동차의 시동을 걸어라라는 메세지를 수신했을 때, 스마트키 자동차와, 일반 키로 동작하는 자동차는 같은 메세지를 수신하지만 다른 행동을 합니다. 이와 같이 &lt;code&gt;다형성&lt;/code&gt;이라는 형질을 이용해, 송신자는 수신자를 몰라도 요청이 가능하게 되면서 수신자의 외부와 내부처리를 분리하는 &lt;code&gt;캡슐화&lt;/code&gt;도 가능합니다.&lt;/p&gt;
&lt;p&gt;다형성의 장점&lt;/p&gt;
&lt;ul&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;code&gt;메세지&lt;/code&gt;를 통해 이루어지기 때문이다. 그래서 &lt;b&gt;객체가 메세지를 선택하는게 아닌, 메세지를 중심으로 적절한 객체를 선택, 메세지를 중심으로 협력을 설계해야 합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;**결론 : 메세지를 기반으로 책임을 자율적으로 만들어야 한다.&lt;/p&gt;
&lt;h2&gt;기능의 관점, 구조의 관점&lt;/h2&gt;
&lt;p&gt;실세계이든 객체 세계이든 변화는 막을 수 없다. 그렇기 때문에 &lt;code&gt;기능의 관점&lt;/code&gt;으로 설계를 할 경우, 재사용이 불가능하고 수정이 반복이 된다. 예를 들어 길을 찾아가는데 사람에게 물어가며 길을 찾아간다고 생각해보자. 누군가가 앞으로 가시다가 사거리에서 우회전... 편의점에서 좌회전...등등 직관적이고 해결이 쉽겠지만, 3년후 같은 같은 위치에서 같은 질문을 했을 경우 해당 위치에 편의점이 없어질수도, 극단적으로 사거리가 없어질수도 있다. 아무도 예측이 불가능합니다.&lt;br /&gt;그렇다면 지도를 보고 찾아가는 &lt;code&gt;구조의 관점&lt;/code&gt;으로 접근해보자. 전체적인 지형의 형태로 길을 찾아가기 때문에 해당 건물에 편의점이 음식점으로 바뀌어도 원하는 길을 찾아가는데 문제가 없습니다.&lt;/p&gt;
&lt;h5&gt;기능 설계 vs 구조 설계&lt;/h5&gt;
&lt;p&gt;그렇다면 기능은 필요가 없는가? 전혀 아니다. 기능은 즉 서비스입니다. 설계 초반에 사용자가 원하는 요구를 파악하고, 충족하기 위해 어떤 기능을 제공해야 하는지 초점을 맞춰야 합니다.&lt;br /&gt;구조는 기능을 구현하기 위한 기반으로, &lt;b&gt;변경을 수용할 수 있도록 안정적이어야 합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;기능과 구조를 표현하기 위한 기법&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;기능 표현 : 유스케이스 모델링&lt;/li&gt;
&lt;li&gt;구조 표현 : 도메인 모델링&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;유스케이스 모델을 통한 기능과, 도메인 모델을 통한 구조를 책임-주도 설계로 합쳐서 안정적인 시스템을 만드는 방법을 연습해야 한다.&lt;br /&gt;또한 코드 작성은 도메인 모델을 기반으로 작성해 방향성을 잃지 않고 코드를 작성하도록 한다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;결론 : 요구사항을 식별, 도메인 모델을 생성한 후, 코드를 작성 후, 요구사항을 충족시키기 위해 객체들간의 메세지 전송을 정의해야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;h2&gt;마무리&lt;/h2&gt;
&lt;p&gt;책에 대한 전반적인 리뷰를 마무리하며, 해당 책에는 이상한 나라의 엘리스라는 책을 기준으로 더 많은 내용과 설명을 몰입도 있게 표현하고 있으니, 조금이라도 객체지향에 대한 호기심이 생긴 사람이라면 적극적으로 읽어볼 것을 추천합니다. 또한 책의 분량도 많지 않기 때문에 부담 없이 읽으면서 조금 더 견문??이 넓어지는 듯한 생각이듭니다. &lt;b&gt;책을 적극적으로 추천합니다.&lt;/b&gt;&lt;/p&gt;
&lt;h5&gt;결론 모아보기&lt;/h5&gt;
&lt;ol&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;</description>
      <category>일상/독서</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/125</guid>
      <comments>https://lee1535.tistory.com/125#entry125comment</comments>
      <pubDate>Thu, 19 Mar 2020 14:08:53 +0900</pubDate>
    </item>
    <item>
      <title>[인강리뷰] 자바 : 클래스의 이해와 객체지향 프로그래밍</title>
      <link>https://lee1535.tistory.com/122</link>
      <description>&lt;p&gt;요즘 인프런을 통한 강의로 부족한 기본기를 다지는 중인데 인프런에 등록된 로드맵중 시작단계에 해당 강의가 있어서 구매하게 되었다. &lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cNLzJe/btqCGP8vJou/4aoyAZdRvoLzKSRm5CVsC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cNLzJe/btqCGP8vJou/4aoyAZdRvoLzKSRm5CVsC1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cNLzJe/btqCGP8vJou/4aoyAZdRvoLzKSRm5CVsC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcNLzJe%2FbtqCGP8vJou%2F4aoyAZdRvoLzKSRm5CVsC1%2Fimg.png&quot; width=&quot;100%&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2&gt;이런 걸 배울 수 있어요&lt;/h2&gt;
&lt;ul&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;h2&gt;클래스를 알면 자바가 정말 쉽습니다.&lt;/h2&gt;
&lt;p&gt;자바는 클래스로 시작해서 클래스로 끝난다고 볼 수 있는데&lt;br&gt;  그렇다면 클래스를 안다는 것이 얼마나 중요한 일이겠습니까?&lt;br&gt;  &lt;br&gt;&lt;br&gt;이 강의를 통해 클래스를 이해하고 많은 용어를 이해하면&lt;br&gt;자바 코드를 볼 때 &amp;quot;아 이게 그거였구나&amp;quot;하면서&lt;br&gt;자바 코드를 보는 것이 즐겁게까지 느껴질지도 모릅니다.( 바램입니다 ^^ ) &lt;/p&gt;
&lt;p&gt;...이하 생략&lt;/p&gt;
&lt;h2&gt;수강 대상&lt;/h2&gt;
&lt;ul&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;h2&gt;느낀점&lt;/h2&gt;
&lt;p&gt;우선 인프런에서 로드맵을 통해 공부중에 해당 강의는 기본 강의라고 생각해서 패스했었습니다.&lt;br&gt;  그런데 요즘 코로나 관련해서 강의가 세일중이기에... 부담스럽지 않은 가격이라 구매를 결정 후 하루만에 정독하였습니다.&lt;br&gt;우선 수강 대상이 자바 프로그래밍을 잘 하고 싶으신 분 이라는 문구가 제일 눈에 띄여서 구매를 결정했던거 같습니다.&lt;br&gt;내용은 일반 책이나 강의에서 들을 수 없는 부분까지 설명을 해주시고 왜 사용하는지, 이론부터 설명을 해주기 때문에 자바를 처음 공부하는 사람은 자바 책과 같이 들으면 좀 더 이해가 쉬웠을거 같다고 생각합니다.&lt;br&gt;  사실 저의 경우도 취업전까지 추상클래스나, 인터페이스, 다형성 등등등 자세히 모르고 그냥 사용하다가 면접을 준비하면서 공부한 케이스인데 해당 강의를 보면 이런 부분에 대한 설명이 쉽게 나와있습니다.&lt;br&gt;  여기서 젤 중요한 부분은 자바를 처음 접하고 기본서를 공부중이신 분들에게는 강추하는 강의입니다.&lt;br&gt;  그러나 기본서는 필요없다 하는 분들은 말 그대로 초급과정의 강의이기 때문에 불필요하다고 생각합니다. &lt;/p&gt;</description>
      <category>일상/독서</category>
      <category>Java</category>
      <category>인강리뷰</category>
      <category>인프런</category>
      <category>자바</category>
      <category>클래스의 이해와 객체지향 프로그래밍</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/122</guid>
      <comments>https://lee1535.tistory.com/122#entry122comment</comments>
      <pubDate>Thu, 12 Mar 2020 13:29:10 +0900</pubDate>
    </item>
    <item>
      <title>[독서리뷰] 코드로 배우는 스프링 웹 프로젝트 - 개정판</title>
      <link>https://lee1535.tistory.com/121</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;unnamed.jpg&quot; data-origin-width=&quot;413&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chMcRn/btqCB7OB1yB/Dlh3h1fgeidn5qi9TZSMJK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chMcRn/btqCB7OB1yB/Dlh3h1fgeidn5qi9TZSMJK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chMcRn/btqCB7OB1yB/Dlh3h1fgeidn5qi9TZSMJK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchMcRn%2FbtqCB7OB1yB%2FDlh3h1fgeidn5qi9TZSMJK%2Fimg.jpg&quot; data-filename=&quot;unnamed.jpg&quot; data-origin-width=&quot;413&quot; data-origin-height=&quot;512&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;스프링 공부를 하고 싶어서 여러 블로그, 커뮤니티 등을 참고해서 책을 선정하기로 마음 먹었다. 사실 맨 처음 사람들이 추천해주는 토비의 책으로 공부하려고 했으나.. 우선 책의 두께가 있어서 그런지 책을 보기도 전에 덜컥 거부감과 부담이 생겨서 좀 더 이론보다는 구현을 해보자라는 마음에 해당 책을 선택했습니다. 우선 내용은 신입??이 스프링기반 웹 프로젝트를 기본은 할 수 있도록 가이드를 제공해주는 책이라고 생각하면 됩니다.&lt;/p&gt;
&lt;h2&gt;책 소개&lt;/h2&gt;
&lt;p&gt;이 책은 Spring Framework를 사용해서 웹 프로젝트를 어떻게 생성하고, 진행하는지 설명하는 책입니다.&lt;br&gt;  좀 더 구체적으로는 스프링으로 웹 프로젝트에서 사용되는 게시물 관리를 만들어 보는 것이 주된 목적입니다. 모든 웹 프로젝트는 그 성격에 따라 구성과 구조가 다르기는 하지만 결과적으로는 게시물 관리 모듈의 집합체라고 볼 수 있습니다. 이 책에서는 웹 프로젝트에 사용되는 게시물을 다음과 같은 예제들로 작성합니다.&lt;/p&gt;
&lt;h2&gt;목차&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;스프링 개발 환경 구축&lt;/li&gt;
&lt;li&gt;스프링 MVC 설정&lt;/li&gt;
&lt;li&gt;기본적인 웹 게시물 관리&lt;/li&gt;
&lt;li&gt;REST 방식과 Ajax를 이용하는 댓글 처리&lt;/li&gt;
&lt;li&gt;AOP와 트랜잭션&lt;/li&gt;
&lt;li&gt;파일 업로드 처리&lt;/li&gt;
&lt;li&gt;Spring Web Security를 이용한 로그인 처리&lt;/li&gt;
&lt;li&gt;부록&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;저자 소개 - 구멍가게 코딩단&lt;/h2&gt;
&lt;p&gt;프로그래밍을 좋아하지만. 남들 앞에 나설 용기 없는 10년 차 이상 개발자, 현업 관리자, 강사들의 비공개 모임.&lt;br&gt;  어린 시절 구멍가게 앞 아저씨들이 인생의 진리를 가볍게 던졌던 것처럼 프로그래밍의 오의를 가볍게 던지고 싶은 사람들의 모임&lt;/p&gt;
&lt;h2&gt;느낀점&lt;/h2&gt;
&lt;p&gt;우선 읽은 사람들 모두, 예제에 나온 오타, 맞춤법 등의 악평이 많지만... 뭐 저는 읽으면서 불편하다고 느끼지는 않았습니다.&lt;br&gt;  또한 스프링 프레임워크에 대한 이론적인 부분 보다는 예제를 통한 프로젝트를 구현하는게 목표인 책이다 보니, 책을 읽어가면서 부족한 부분은 Spring Docs나 다른 블로그 등을 참고해서 이론부분을 채워가면서 읽으니까 좀 더 스프링에 대해서 이해하는데 도움이 된 것 같습니다. 전체적으로 스프링에 대해서 처음 입문하고, 스프링 하면 덜컥 겁부터 나는 저같은 사람에겐 소중한 책이였던것 같습니다.&lt;br&gt;  스프링을 공부해야 하는데 책이 어렵고, 뭐부터 해야 할지 모르겠는 사람에게 추천하는 책입니다.&lt;/p&gt;</description>
      <category>일상/독서</category>
      <category>구멍가게 코딩단</category>
      <category>독서리뷰</category>
      <category>스프링</category>
      <category>코드로 배우는 스프링 웹 프로젝트</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/121</guid>
      <comments>https://lee1535.tistory.com/121#entry121comment</comments>
      <pubDate>Mon, 9 Mar 2020 10:15:27 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] Spring Project 생성, xml 없이 java로 설정하기 (web.xml servlet-context.xml root-context.xml 제거 )</title>
      <link>https://lee1535.tistory.com/118</link>
      <description>&lt;p&gt;해당 내용은 &lt;code&gt;코드로 배우는 스프링 웹 프로젝트&lt;/code&gt; 라는 책의 내용을 기반으로 작성된 내용입니다.&lt;/p&gt;
&lt;h1&gt;Spring 프로젝트 생성&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;시작은 &amp;#39;Spring Legacy Project&amp;#39;로 프로젝트를 하나 생성해줍니다.&lt;br&gt;그럼 아래 그림과 같이 프로젝트 구조가 생성되는데, 이중 .xml로 설정된 파일을 제거하기 위해&lt;br&gt;web.xml을 삭제하고 servlet-context.xml과 root-context.xml을 포함하고 있는 spring 폴더 자체를 삭제해줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;이미지 1.png&quot; data-origin-width=&quot;229&quot; data-origin-height=&quot;354&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qAHIY/btqCoRMx39W/CHyeKTtznqng97z5Ccz7jk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qAHIY/btqCoRMx39W/CHyeKTtznqng97z5Ccz7jk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qAHIY/btqCoRMx39W/CHyeKTtznqng97z5Ccz7jk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqAHIY%2FbtqCoRMx39W%2FCHyeKTtznqng97z5Ccz7jk%2Fimg.png&quot; data-filename=&quot;이미지 1.png&quot; data-origin-width=&quot;229&quot; data-origin-height=&quot;354&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;삭제 후 pom.xml에 에러 표시가 발생합니다. 이는 기존 웹 프로젝트들이 web.xml을 사용하는 것을 기반으로 설정했기 때문입니다. 에러를 제거하기 위해 pom.xml의 의 아래와 같은 설정을 추가&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;plugins&amp;gt;
  &amp;lt;plugin&amp;gt;
      &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;
      &amp;lt;artifactId&amp;gt;maven-war-plugin&amp;lt;/artifactId&amp;gt;
      &amp;lt;version&amp;gt;3.2.3&amp;lt;/version&amp;gt;
        &amp;lt;configuration&amp;gt;
          &amp;lt;failOnMissingWebXml&amp;gt;false&amp;lt;/failOnMissingWebXml&amp;gt;
      &amp;lt;/configuration&amp;gt;
  &amp;lt;/plugin&amp;gt;
...
&amp;lt;plugins&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;마지막으로 pom.xml에 java 관련 버전 설정을 1.7로 되어있는 데 사용하는 버전으로 변경 ( properties 와 maven-compiler-plugin ) 설정을 마무리하고 프로젝트 우클릭 -&amp;gt; maven -&amp;gt; update project 실행&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;위 과정을 마치면 일단 오류는 사라집니다. 이제 남은 과정은 삭제한 xml파일의 설정 값들을 java Class로 추가하는 작업입니다.&lt;/p&gt;
&lt;h1&gt;root-context.xml 대체하기&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;root-context.xml&lt;/code&gt; 이란 ?&lt;br&gt;Spring는 Context라는 영역을 만들어서 거기서 bean들을 관리해주며, 여러 개의 Context를 가질 수 있고 servlet-context 다음 root-context라는 계층형 구조를 가지고 있습니다. 이중 root-context 영역에 대한 설정을 담당하는 파일이 &lt;code&gt;root-context.xml&lt;/code&gt; 입니다.&lt;br&gt;&lt;br&gt;&lt;br&gt;또한 계층 구조상 root-context는 servlet-context 인스턴스에서 공유해야 하는 데이터 저장소 및 비지니스 서비스와 같은 인프라 &lt;code&gt;Bean&lt;/code&gt;을 등록하게 됩니다. 쉽게 말해 datasources와 같이 공통 사용 빈 또는 설정할 때 사용하게 됩니다. &lt;a href=&quot;https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc&quot;&gt;참조&lt;/a&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;그럼 서론은 여기까지 하고, 아래와 같이 적당한 패키지와 클래스 이름을 정해서 클래스를 하나 정의해줍니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = {&amp;quot;com.ljh.study&amp;quot;})
public class RootConfig { }&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;@Configuration&lt;/code&gt; 어노테이션은 해당 클래스를 설정 클래스라고 알려주는 어노테이션입니다.&lt;br&gt;&lt;code&gt;@ComponentScan&lt;/code&gt; 어노테이션은 기존 xml에 사용하던 것과 동일하게 &lt;code&gt;@Componet&lt;/code&gt;로 선언된 클래스들을 Bean으로 인식해 Context 영역에 객체를 생성하도록 해주는 어노테이션 설정입니다.&lt;/p&gt;
&lt;h5&gt;RootConfig Test 작성&lt;/h5&gt;
&lt;p&gt;방금 만들어진 RootConfig 클래스가 정상적으로 동작하는지 테스트하기 위해 하나의 클래스를 만들어줍니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package com.ljh.study.sample;
import org.springframework.stereotype.Component;

@Component
public class Sample { }&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;@Component&lt;/code&gt;라는 어노테이션을 통해 Spring Context가 관리해야 되는 객체라고 선언합니다.&lt;br&gt;여기까지 완료되었으면, 이제 테스트 코드를 작성합니다. 테스트는 원하는 버전을 선택합니다. 저의 경우 Junit5를 사용하였습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@DisplayName(&amp;quot;Root Context 테스트&amp;quot;)
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = RootConfig.class)
public class RootConfigTest {

    private Sample sample;

    @Autowired
    public RootConfigTest(Sample sample) {
        this.sample = sample;
    }

    @Test
    @DisplayName(&amp;quot;Root Context Component scan 확인&amp;quot;)
    void rootContextComponentScanTest() {
        assertNotNull(sample);
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;RootConfig 클래스를 통해 정상적으로 Bean들이 등록이 되었다면 &lt;code&gt;@Autowired&lt;/code&gt;가 동작을 하고 객체에 의존성을 주입받을 것입니다.&lt;br&gt;실행을 하면 아래와 같이 테스트가 통과하는 걸 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;이미지 3.png&quot; data-origin-width=&quot;417&quot; data-origin-height=&quot;119&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NhH8H/btqCkRfKJww/74rJDENP0SarPykEImf3q0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NhH8H/btqCkRfKJww/74rJDENP0SarPykEImf3q0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NhH8H/btqCkRfKJww/74rJDENP0SarPykEImf3q0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNhH8H%2FbtqCkRfKJww%2F74rJDENP0SarPykEImf3q0%2Fimg.png&quot; data-filename=&quot;이미지 3.png&quot; data-origin-width=&quot;417&quot; data-origin-height=&quot;119&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;web.xml 대체하기&lt;/h1&gt;
&lt;p&gt;이제 web.xml을 대신할 클래스를 아래와 같이 작성합니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class WebConfig extends AbstractAnnotationConfigDispatcherServletInitializer{

    @Override
    protected Class&amp;lt;?&amp;gt;[] getRootConfigClasses() {
        return new Class[] {RootConfig.class};
    }

    @Override
    protected Class&amp;lt;?&amp;gt;[] getServletConfigClasses() {
        return null;
    }

    @Override
    protected String[] getServletMappings() {
        return null;
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;WebApplicationInitializer&lt;/code&gt;를 상속받아 구현하는 방법도 존재하지만 해당 클래스의 구현체인 &lt;code&gt;AbstractAnnotationConfigDispatcherServletInitializer&lt;/code&gt;를 상속받아 좀 더 간편하게 구현이 가능합니다.&lt;/p&gt;
&lt;p&gt;이제 Run As -&amp;gt; Run On Server로 실제 동작을 해보면 콘솔에 아래와 같은 로그가 찍히면서 WebConfig 클래스의 설정이 적용이 되었는지 확인할 수 있습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;INFO : org.springframework.web.context.ContextLoader - Root WebApplicationContext: initialization started
INFO : org.springframework.web.context.ContextLoader - Root WebApplicationContext initialized in 531 ms
INFO : org.springframework.web.servlet.DispatcherServlet - Initializing Servlet &amp;#39;dispatcher&amp;#39;
INFO : org.springframework.web.servlet.DispatcherServlet - Completed initialization in 219 ms&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;만약 해당 로그가 뜨지 않는다면 정상적으로 설정이 되지 않은 것이니 다시 확인하셔야 합니다.&lt;/p&gt;
&lt;h2&gt;DB 연결하기&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;해당 예제에서는 DB로 Oracle 11g를 사용합니다.&lt;/li&gt;
&lt;li&gt;오라클 버전에 맞는 JDBC 스펙을 Oracle 홈페이지에서 확인 후 프로젝트에 추가 해줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;위와 같이 사전 준비가 완료되었다면, 이제 DB에 정상적으로 접속이 되는지 테스트 코드를 작성해봅니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Log4j
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = RootConfig.class)
@DisplayName(&amp;quot;DB 관련 테스트&amp;quot;)
public class DBTest {

    @Test
    @DisplayName(&amp;quot;JDBC 연결 테스트&amp;quot;)
    void jdbcTest() {
        try {
            DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
            try (Connection connection = 
                    DriverManager.getConnection(
                              &amp;quot;jdbc:oracle:thin:@localhost:1521:orcl&amp;quot;
                            , &amp;quot;study&amp;quot;
                            , &amp;quot;study&amp;quot;)) {
                log.info(connection);
            }
        } catch (SQLException e) {
            log.error(e.getMessage());
        }
    }&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;위와 같이 각각 DB에 맞는 드라이버를 등록 후 접속을 테스트 해보는 간단한 테스트입니다.&lt;br&gt;정상적으로 동작한다면 Log4j를 통해 출력된 &lt;code&gt;connection&lt;/code&gt; 객체의 정보가 출력될 것 입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dRlVV8/btqCsIaW4la/KRo2W3yTvt57bUzYKN3Xo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dRlVV8/btqCsIaW4la/KRo2W3yTvt57bUzYKN3Xo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dRlVV8/btqCsIaW4la/KRo2W3yTvt57bUzYKN3Xo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdRlVV8%2FbtqCsIaW4la%2FKRo2W3yTvt57bUzYKN3Xo0%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2&gt;Connection Pool 사용&lt;/h2&gt;
&lt;p&gt;이제 DB랑 접속이 되는지 확인이 되었으니, 커넥션 풀을 설정할 차례입니다. 예제에서는 HikariCP를 사용합니다.&lt;br&gt;우선 HikaraCP를 사용하기 위해 &lt;code&gt;pom.xml&lt;/code&gt;에 아래와 같이 의존성을 추가해줍니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- https://mvnrepository.com/artifact/com.zaxxer/HikariCP --&amp;gt;
&amp;lt;dependency&amp;gt;
      &amp;lt;groupId&amp;gt;com.zaxxer&amp;lt;/groupId&amp;gt;
      &amp;lt;artifactId&amp;gt;HikariCP&amp;lt;/artifactId&amp;gt;
      &amp;lt;version&amp;gt;3.4.2&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;그 후 기존에 작성된 &lt;code&gt;RootConfig&lt;/code&gt;클래스에 다음과 같이 Bean을 추가해줍니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Configuration
@ComponentScan(basePackages = {&amp;quot;com.ljh.study&amp;quot;})
public class RootConfig { 

    @Bean
    public DataSource dataSource() {
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setDriverClassName(&amp;quot;oracle.jdbc.OracleDriver&amp;quot;);
        hikariConfig.setJdbcUrl(&amp;quot;jdbc:oracle:thin:@localhost:1521:orcl&amp;quot;);
        hikariConfig.setUsername(&amp;quot;study&amp;quot;);
        hikariConfig.setPassword(&amp;quot;study&amp;quot;);

        return new HikariDataSource(hikariConfig);
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;위와 같이 root-context를 수정해서 DataSource를 HikariDataSource로 설정해줍니다.&lt;br&gt;이런 설정을 통해 &lt;code&gt;dataSource&lt;/code&gt;라는 빈에 &lt;code&gt;hikariConfig&lt;/code&gt;를 참조시키는 설정을 진행하게 됩니다.&lt;/p&gt;
&lt;p&gt;자 이제 당연하게 HikariCP가 정상적으로 적용이 되었는지 Test를 작성해줍니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Log4j
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = RootConfig.class)
@DisplayName(&amp;quot;DB 관련 테스트&amp;quot;)
public class DBTest {

    private DataSource dataSource;

    @Autowired
    public DBTest(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Test
    @DisplayName(&amp;quot;Hikari 설정 테스트&amp;quot;)
    void datasourceTest() {
        try(Connection connection = dataSource.getConnection()){
            log.info(connection);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;간단하게 위와 같이 테스트 코드를 작성하고 실행해보면 Test코드가 실행하면서 Spring가 Bean으로 HikariCP를 통해 커넥션을 사용하는 로그가 찍히는지 확인해봅니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
INFO : com.zaxxer.hikari.pool.PoolBase - HikariPool-1 - Driver does not support get/set network timeout for connections. (oracle.jdbc.driver.T4CConnection.getNetworkTimeout()I)
INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
....&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;Mybatis 연동&lt;/h2&gt;
&lt;p&gt;Mybatis를 사용하기 위해 아래의 의존성들을 추가해줍니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.mybatis&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;mybatis&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;3.5.4&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;

&amp;lt;!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring --&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.mybatis&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;mybatis-spring&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;2.0.3&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;

&amp;lt;!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc --&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-jdbc&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;${org.springframework-version}&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;추가로 &lt;code&gt;spring-tx&lt;/code&gt;가 없으신분들은 추가로 의존성을 작성해줍니다.&lt;/p&gt;
&lt;p&gt;이제 사용하기 위한 사전 준비는 끝났고, Mybatis에서 사용하는 클래스들중 &lt;code&gt;SQLSession&lt;/code&gt;과 &lt;code&gt;SQLSessionFactory&lt;/code&gt;를 사용하기 위해 스프링에 Bean으로 등록해주는 작업을 해줍니다.&lt;br&gt;기존에 작성된 &lt;code&gt;RootConfig&lt;/code&gt;클래스에 아래와 같이 Bean을 추가로 작성해줍니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Bean
public SqlSessionFactory sessionFactory() throws Exception {
    SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
    sessionFactoryBean.setDataSource(dataSource());
    return sessionFactoryBean.getObject();
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;두 객체에 대해서 간략하게 설명하자면 &lt;code&gt;SQLSessionFactory&lt;/code&gt;는 이름처럼 &lt;code&gt;SQLSession&lt;/code&gt; 객체를 생성해주는 역할을 하는 객체입니다.&lt;br&gt;&lt;code&gt;SQLSession&lt;/code&gt;은 해당 객체를 통해 &lt;code&gt;Connection&lt;/code&gt;을 생성하거나 원하는 SQL문을 전달하고, 결과를 리턴 받는 역할을 합니다.&lt;/p&gt;
&lt;p&gt;이제 해당 Bean이 정상적으로 Spring에 등록이 되었는지 테스트해보는 테스트 코드를 작성합니다. 기존에 작성된 &lt;code&gt;DBTest&lt;/code&gt; 클래스에 추가로 아래와 같이 작성을 해줍니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Test
@DisplayName(&amp;quot;myBatis 연결 테스트&amp;quot;)
void myBatisTest() {
    try(SqlSession session = sqlSessionFactory.openSession();
        Connection connection = session.getConnection();){
        log.info(session);
        log.info(connection);
    } catch (SQLException e) {
        log.error(e.getMessage());
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;실행 후 아래와 같은 결과가 나오는지 확인해봅니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;INFO : config.DataSourceTest - org.apache.ibatis.session.defaults.DefaultSqlSession@5a9d6f02 INFO : config.DataSourceTest - HikariProxyConnection@1839168128 wrapping oracle.jdbc.driver.T4CConnection@376a0d86 &lt;/code&gt;&lt;/pre&gt;&lt;p&gt;여기까지 동작이 완료되었다면, Mybatis까지 연동이 성공했습니다. 이제 실제 소스에 어떻게 사용하는지 사용방법에 대해서 소개를 하겠습니다.&lt;/p&gt;
&lt;h2&gt;스프링과 Mybatis 연동처리&lt;/h2&gt;
&lt;p&gt;스프링과 Mybatis에서 SQL문을 작성할 때 &lt;code&gt;Mapper&lt;/code&gt;을 사용합니다. &lt;code&gt;Mapper&lt;/code&gt;은 xml로 작성할 수도, 어노테이션으로 사용할 수 도 있습니다. 예제에선 두가지 방법 모두 사용해보겠습니다.&lt;/p&gt;
&lt;p&gt;우선 기본 구조는 Controller -&amp;gt; Service -&amp;gt; Mapper 인데 예제에선 Controller과 Service를 패스하고 바로 Mapper만 작성해보겠습니다.&lt;br&gt;Mapper은 클래스가 아닌 인터페이스로 아래와 같이 생성해줍니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package com.ljh.study.mapper;
import org.apache.ibatis.annotations.Select;

public interface TimeMapper {

    @Select(&amp;quot;select sysdate from dual&amp;quot;)
    public String getTime();

    public String getTimeForMapperXml();
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;우선 &lt;code&gt;@Select&lt;/code&gt;어노테이션을 사용한 메소드가 어노테이션을 이용한 쿼리 작성방법이고, 아래 &lt;code&gt;getTimeForMapperXml()&lt;/code&gt; 메소드가 xml을 이용한 방식입니다. 해당 방식은 메소드의 이름과, 리턴타입을 선언해주면 해당 Mapper 인터페이스에서 작성은 끝입니다.&lt;/p&gt;
&lt;p&gt;여기까지가 Mapper 인터페이스 작성이였고, 기존의 Spring가 Component를 인식하기 위해 &lt;code&gt;ComponentScan&lt;/code&gt;을 사용했던것과 비슷하게 Mybatis도 &lt;code&gt;MapperScan&lt;/code&gt;을 제공해준다. 그러면 Mybatis와 관련된 어노테이션들(&lt;code&gt;@Select&lt;/code&gt; 등)을 인식하고 등록하게 됩니다.&lt;br&gt;작성은 기존에 작성한 &lt;code&gt;RootConfig&lt;/code&gt; 클래스에 어노테이션을 추가해줍니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Configuration
@ComponentScan(basePackages = {&amp;quot;com.ljh.study&amp;quot;})
@MapperScan(basePackages = {&amp;quot;com.ljh.study.mapper&amp;quot;})
public class RootConfig { 
    ....
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;이제 Mapper 인터페이스 + xml을 같이 사용 하는 방법은 &lt;code&gt;src/main/resources&lt;/code&gt; 아래 적당하게 패키지를 구성해주고 패키지 안에 &lt;code&gt;TimeMapper.xml&lt;/code&gt;을 생성해주고 아래와 같이 작성해줍니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; ?&amp;gt; 
&amp;lt;!DOCTYPE mapper PUBLIC &amp;quot;-//mybatis.org//DTD Mapper 3.0//EN&amp;quot; &amp;quot;http://mybatis.org/dtd/mybatis-3-mapper.dtd&amp;quot;&amp;gt;

&amp;lt;mapper namespace=&amp;quot;com.ljh.study.mapper.TimeMapper&amp;quot;&amp;gt;
    &amp;lt;select id=&amp;quot;getTimeForMapperXml&amp;quot; resultType=&amp;quot;String&amp;quot;&amp;gt;
        select sysdate from dual
    &amp;lt;/select&amp;gt;
&amp;lt;/mapper&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;여기서 중요한 점은 우리가 생성한 Mapper 인터페이스를 &lt;code&gt;namespace&lt;/code&gt;에 연결을 해줍니다. 그리고 우리는 셀렉트문을 사용하기 때문에 &lt;code&gt;select id&lt;/code&gt;을 통해 해당 메소드와 연결을 시켜줍니다. 또한 파라미터를 받을 수도, 결과를 리스트로 반환할 수도 여러가지 방법이 존재하니 해당 방법에 대해서 모르신다면, 따로 검색을 해보시는걸 추천합니다.&lt;/p&gt;
&lt;p&gt;이제 다왔습니다. 해당 Mapper가 적상적으로 동작하는지 테스트를 아래와 같이 작성해줍니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@DisplayName(&amp;quot;Mapper 관련 테스트&amp;quot;)
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = RootConfig.class)
@Log4j
public class TimeMapperTest {

    private TimeMapper timeMapper;

    @Autowired
    public TimeMapperTest(TimeMapper timeMapper) {
        this.timeMapper = timeMapper;
    }

    @Test
    public void testGetTIme() {
        log.info(timeMapper.getTime());
    }

    @Test
    public void getTimeForMapperXmlTest() {
        log.info(timeMapper.getTimeForMapperXml());
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;해당 테스트를 실행 후, &lt;code&gt;log&lt;/code&gt;가 정상적으로 출력이 되면, 이제 기본 프로젝트 생성과 &lt;code&gt;Mybatis 3&lt;/code&gt;를 통한 DB 접속 연결까지 완료가 되었습니다. &lt;/p&gt;</description>
      <category>Spring/Spring</category>
      <category>Java</category>
      <category>project 생성</category>
      <category>spring</category>
      <category>xml 없이</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/118</guid>
      <comments>https://lee1535.tistory.com/118#entry118comment</comments>
      <pubDate>Sun, 1 Mar 2020 02:02:50 +0900</pubDate>
    </item>
    <item>
      <title>[Spring/Core] DI(의존성 주입)은 생성자 주입을 사용해라</title>
      <link>https://lee1535.tistory.com/117</link>
      <description>&lt;p&gt;이번 내용은 스터디를 진행하는 도중에 누군가가 요즘은 필드 주입을 사용하지 않는데 왜 사용했느냐라는 질문에 대한 내용을 정리하기 위해 스프링 공식 사이트의 &lt;a href=&quot;https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-beanfactory&quot;&gt;Spring Core&lt;/a&gt;의 내용을 참고해서 정리한 내용입니다.&lt;/p&gt;
&lt;h2&gt;사용 이유&lt;/h2&gt;
&lt;p&gt;아래는 Spring Document에 나와있는 원문입니다.&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;Constructor-based or setter-based DI?
Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use constructors for mandatory dependencies and setter methods or configuration methods for optional dependencies. Note that use of the @Required annotation on a setter method can be used to make the property be a required dependency; however, constructor injection with programmatic validation of arguments is preferable.

The Spring team generally advocates constructor injection, as it lets you implement application components as immutable objects and ensures that required dependencies are not null. Furthermore, constructor-injected components are always returned to the client (calling) code in a fully initialized state. As a side note, a large number of constructor arguments is a bad code smell, implying that the class likely has too many responsibilities and should be refactored to better address proper separation of concerns.

Setter injection should primarily only be used for optional dependencies that can be assigned reasonable default values within the class. Otherwise, not-null checks must be performed everywhere the code uses the dependency. One benefit of setter injection is that setter methods make objects of that class amenable to reconfiguration or re-injection later. Management through JMX MBeans is therefore a compelling use case for setter injection.

Use the DI style that makes the most sense for a particular class. Sometimes, when dealing with third-party classes for which you do not have the source, the choice is made for you. For example, if a third-party class does not expose any setter methods, then constructor injection may be the only available form of DI.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;뭐 사실 저 원문을 보려고 오신 건 아닐 거라 믿기 때문에 포스팅이 길어질걸 대비해 옆으로 길게 내용을 작성합니다.&lt;br /&gt;해당 내용을 간략하게 줄여보자면, 우선 필드 주입은 언급도 안 하고, ( 여태 사용하던 나는 무엇...)&lt;br /&gt;&lt;code&gt;Construcor Base Injection&lt;/code&gt;(생성자 기반 주입)과 &lt;code&gt;Setter Base Injection&lt;/code&gt;(수정자를 통한 주입)의 차이점에 대해서 설명합니다. 여담으로 스프링 진영도 &lt;b&gt;생성자 기반 주입&lt;/b&gt;을 옹호한다고 나와있네요.&lt;/p&gt;
&lt;h5&gt;둘의 차이점&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;생성자 주입은 필수 종속성, 수정자는 선택적 종속성에 사용하라&lt;/li&gt;
&lt;li&gt;생성자 주입은 &lt;code&gt;final&lt;/code&gt; 키워드를 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;생성자 주입은 생성자 인수가 많아지면. 코드가 더러워 보이므로 리팩토링을 하게 된다. 라는 식으로 적혀 있는데 구글 번역기를 돌리는 거라 대충 느낌만 적었습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;종속성&lt;/h2&gt;
&lt;p&gt;말 그대로 객체가 다른 객체에 종속되어 있다는 말입니다. 간단한 예제를 보면&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;class Book{    
    JavaBook javaBook = new JavaBook();

    ...
}

class JavaBook{
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같은 구성일 때 JavaBook 클래스는 Book 클래스가 변경이 되어도 영향이 없다.&lt;br /&gt;하지만 Book 클래스는 JavaBook 클래스가 변경되면 영향을 받게 된다 이러한 상태를 Book가 JavaBook에 종속되었다고 표현합니다.&lt;/p&gt;
&lt;p&gt;간단하게 종속성에 대해서 알아봤고, 그럼 생성자 주입은 필수 종속성, 수정자 주입은 선택적 종속성에 사용하라는 게 무슨 말일까?&lt;br /&gt;아래 코드를 예제로 보겠습니다. 해당 코드는 스프링 동작이 아닌 순수 자바 코드입니다.&lt;/p&gt;
&lt;h4&gt;Constructor Base&lt;/h4&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;public class Controller {

    private Service service;

    public Controller(Service service) {
        this.service = service;
    }
}

public class Service { }

public class Main {
    public static void main(String[] args) {

        Controller controller = new Controller(new Service());
        Controller controller2 = new Controller(null);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;보시는 바와 같이 생성자를 통한 주입의 경우 해당 의존 객체를 필수로 주입해주지 않는 한 객체를 생성할 수 없게 됩니다.&lt;br /&gt;즉, null을 직접적으로 주입하지 않는한 객체는 &lt;code&gt;NullPointerException&lt;/code&gt;을 발생하지 않습니다. 추가로 의존 객체에 &lt;code&gt;final&lt;/code&gt; 키워드를 사용할 수 있는 장점도 있습니다.&lt;/p&gt;
&lt;h4&gt;Setter Base&lt;/h4&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class Controller {

    private Service service;

    public void setService(Service service) {
        this.service = service;
    }

    public void servicePrint(){
        service.print();
    }
}

public class Service { 
    public void print(){
        System.out.println(&quot;someting to do...&quot;);
    }
}

public class Main {
    public static void main(String[] args) {

        Controller controller = new Controller();
        controller.setService(new Service());
        controller.servicePrint();

        Controller controller2 = new Controller();
        controller2.servicePrint(); // NullPointerException
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;반면 Setter 주입의 경우 객체 생성 시 의존관계를 주입해주지 않아도 객체 생성이 가능하게 됩니다.&lt;br /&gt;그렇기 때문에 사용 시 &lt;code&gt;NullPointerException&lt;/code&gt;이 발생할 수 있어 항상 객체의 참조가 &lt;code&gt;null&lt;/code&gt;인지 확인해야 하는 로직이 추가로 필요하게 됩니다.&lt;/p&gt;
&lt;h2&gt;순환참조&lt;/h2&gt;
&lt;p&gt;간단하게 생성자 기반 주입과, 수정자 기반 주입에 대해서 알아봤습니다. 이제 마지막으로 순환 참조에 대한 내용입니다.&lt;br /&gt;생성자를 통한 주입의 경우 순환 참조를 앱 구동 단계에서 스프링이 오류를 찾을 수 있고, 수정자 주입의 경우 런타임시, 해당 순환 참조가 되어있는 메소드를 호출하기 전까지 순환참조인지 알 수 있는 방법이 없습니다. 아래 예제를 보겠습니다.&lt;/p&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;@Service
@AllArgsConstructor
public class TestService1 {

    private TestService2 testService2; 
}

@Service
@AllArgsConstructor
public class TestService2 {
    private TestService1 testService1;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같이 간단하게 생성자 기반 주입으로 서로 순환참조를 하도록 설정하고 스프링을 실행하면 아래와 같은 오류가 발생합니다.&lt;br /&gt;&lt;code&gt;Error creating bean with name 'testService1': Requested bean is currently in creation: Is there an unresolvable circular reference?&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;그러나 수정자의 경우 빈 생성 자체는 문제없이 됩니다.&lt;br /&gt;위에서 설명한 바와 같이 서로 메소드가 순환을 참조하고 있든 아니든, 객체 생성 시엔 알 수 있는 방법이 없기 때문에 정상적으로 동작되는 것처럼 보이다 런타임 시에 오류가 발생하는 문제점이 있습니다.&lt;/p&gt;
&lt;h2&gt;정리&lt;/h2&gt;
&lt;p&gt;이렇게 스프링에서 의존성을 주입받는 방법 2가지를 비교해봤습니다. 내용을 간단하게 정리하면 아래와 같습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;생성자 기반 주입의 경우 NullPointException을 방지할 수 있다.&lt;/li&gt;
&lt;li&gt;생성자 기반 주입의 경우 객체에 final 키워드를 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;생성자 기반 주입의 경우 순환 참조를 앱 구동 시 검출할 수 있다.&lt;/li&gt;
&lt;li&gt;생성자 기반 주입의 경우 생성자의 인자가 많아지면 코드가 더러워져 리펙토링을 하게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;위 4개의 장점이 Spring에 소개된 생성자 기반 주입의 장점입니다.&lt;br /&gt;이렇게 장점이 많으니 앞으로 생성자 기반 주입만 사용해야겠습니다. 더불어 요즘은 lombok랑 연동해서 사용하면 어노 테이션 하나로 필드 주입과 비슷하게 작성이 가능하니 사용도 수정자 기반 주입보다 편리한 것 같습니다.&lt;/p&gt;</description>
      <category>Spring/Spring</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/117</guid>
      <comments>https://lee1535.tistory.com/117#entry117comment</comments>
      <pubDate>Fri, 28 Feb 2020 14:38:02 +0900</pubDate>
    </item>
    <item>
      <title>[TDD/테스트주도개발] JUnit5</title>
      <link>https://lee1535.tistory.com/116</link>
      <description>&lt;h1&gt;시작하며&lt;/h1&gt;
&lt;p&gt;해당 내용은 &lt;code&gt;JUnit 5 User Guide&lt;/code&gt;와 인프런의 &lt;code&gt;더 자바, 애플리케이션을 테스트하는 다양한 방법&lt;/code&gt;을 정리한 내용입니다. 잘못된 부분은 댓글로 피드백 부탁드립니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Junit5 User Guide : &lt;a href=&quot;https://junit.org/junit5/docs/current/user-guide/&quot;&gt;https://junit.org/junit5/docs/current/user-guide/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;인프런 : &lt;a href=&quot;https://www.inflearn.com/course/the-java-application-test/dashboard&quot;&gt;https://www.inflearn.com/course/the-java-application-test/dashboard&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;개요&lt;/h1&gt;
&lt;p&gt;이전 버전의 JUnit와는 다르게 JUnit5 부터는 모듈의 집합으로 구성되어 있음, 또한 JUnit5는 java8 이상의 버전을 필요로하나, 그 하위 버전도 JDK로 컴파일된 코드는 계속 테스트 가능&lt;br&gt;&lt;code&gt;JUnit 5 = Junit Platform + Junit Jupiter + JUnit Vintage&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;h5&gt;Junit Platform&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;TestEngine&lt;/code&gt; API를 제공해주며, 콘솔 실행 런처를 제공해줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;h5&gt;JUnit Jupiter&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;TestEngine&lt;/code&gt; API 구현체로 JUnit5 API를 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;h5&gt;JUnit Vintage&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;하위 버전과 호환을 위해 JUnit3, JUnit4 기반의 테스트 엔진을 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;359&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cV49Ml/btqByGGBCKP/JPD56yjx3eLq1ff3FaODx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cV49Ml/btqByGGBCKP/JPD56yjx3eLq1ff3FaODx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cV49Ml/btqByGGBCKP/JPD56yjx3eLq1ff3FaODx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcV49Ml%2FbtqByGGBCKP%2FJPD56yjx3eLq1ff3FaODx1%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;359&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;어노테이션&lt;/h1&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 420px;&quot; border=&quot;1&quot; data-ke-style=&quot;style4&quot;&gt;&lt;tbody&gt;&lt;tr style=&quot;height: 20px;&quot;&gt;&lt;td style=&quot;width: 23.1007%; height: 20px;&quot;&gt;JUnit5 어노테이션&lt;/td&gt;&lt;td style=&quot;width: 53.4496%; height: 20px;&quot;&gt;내용&lt;/td&gt;&lt;td style=&quot;width: 23.4496%; height: 20px;&quot;&gt;JUnit4 어노테이션&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 20px;&quot;&gt;&lt;td style=&quot;width: 23.1007%; height: 20px;&quot;&gt;@Test&lt;/td&gt;&lt;td style=&quot;width: 53.4496%; height: 20px;&quot;&gt;테스트 Method임을 선언&lt;/td&gt;&lt;td style=&quot;width: 23.4496%; height: 20px;&quot;&gt;@Test&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 20px;&quot;&gt;&lt;td style=&quot;width: 23.1007%; height: 20px;&quot;&gt;@ParameterizedTest&lt;/td&gt;&lt;td style=&quot;width: 53.4496%; height: 20px;&quot;&gt;매개변수를 받는 테스트를 작성할 수 있다.&lt;/td&gt;&lt;td style=&quot;width: 23.4496%; height: 20px;&quot;&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 20px;&quot;&gt;&lt;td style=&quot;width: 23.1007%; height: 20px;&quot;&gt;@RepeatedTest&lt;/td&gt;&lt;td style=&quot;width: 53.4496%; height: 20px;&quot;&gt;반복되는 테스트 작성 가능&lt;/td&gt;&lt;td style=&quot;width: 23.4496%; height: 20px;&quot;&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 20px;&quot;&gt;&lt;td style=&quot;width: 23.1007%; height: 20px;&quot;&gt;@TestFactory&lt;/td&gt;&lt;td style=&quot;width: 53.4496%; height: 20px;&quot;&gt;@Test로 선언된 정적 테스트가 아닌 동적으로 테스트를 사용&lt;/td&gt;&lt;td style=&quot;width: 23.4496%; height: 20px;&quot;&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 20px;&quot;&gt;&lt;td style=&quot;width: 23.1007%; height: 20px;&quot;&gt;@TestInstance&lt;/td&gt;&lt;td style=&quot;width: 53.4496%; height: 20px;&quot;&gt;테스트 클래스의 생명주기를 설정&lt;/td&gt;&lt;td style=&quot;width: 23.4496%; height: 20px;&quot;&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 20px;&quot;&gt;&lt;td style=&quot;width: 23.1007%; height: 20px;&quot;&gt;@TestTemplate&lt;/td&gt;&lt;td style=&quot;width: 53.4496%; height: 20px;&quot;&gt;공급자에 의해 여러 번 호출될 수 있도록 설계된 테스트 케이스 템플릿임을 나타낸다.&lt;/td&gt;&lt;td style=&quot;width: 23.4496%; height: 20px;&quot;&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 20px;&quot;&gt;&lt;td style=&quot;width: 23.1007%; height: 20px;&quot;&gt;@TestMethodOrder&lt;/td&gt;&lt;td style=&quot;width: 53.4496%; height: 20px;&quot;&gt;테스트 메소드 실행 순서를 구성하는데 사용&lt;/td&gt;&lt;td style=&quot;width: 23.4496%; height: 20px;&quot;&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 20px;&quot;&gt;&lt;td style=&quot;width: 23.1007%; height: 20px;&quot;&gt;@DisplayName&lt;/td&gt;&lt;td style=&quot;width: 53.4496%; height: 20px;&quot;&gt;테스트 클래스 또는 메소드의 사용자 정의 이름을 선언할 때 사용&lt;/td&gt;&lt;td style=&quot;width: 23.4496%; height: 20px;&quot;&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 20px;&quot;&gt;&lt;td style=&quot;width: 23.1007%; height: 20px;&quot;&gt;@DisplayNameGeneration&lt;/td&gt;&lt;td style=&quot;width: 53.4496%; height: 20px;&quot;&gt;&lt;p&gt;이름 생성기를 선언, 예를 들어 '_'를 공백 문자로 치환해주는 생성기가 있다. ex ) new_test -&amp;gt; new test&lt;/p&gt;&lt;/td&gt;&lt;td style=&quot;width: 23.4496%; height: 20px;&quot;&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 20px;&quot;&gt;&lt;td style=&quot;width: 23.1007%; height: 20px;&quot;&gt;@BeforeEach&lt;/td&gt;&lt;td style=&quot;width: 53.4496%; height: 20px;&quot;&gt;모든 테스트 실행 전에 실행할 테스트에 사용&lt;/td&gt;&lt;td style=&quot;width: 23.4496%; height: 20px;&quot;&gt;@Before&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 20px;&quot;&gt;&lt;td style=&quot;width: 23.1007%; height: 20px;&quot;&gt;@AfterEach&lt;/td&gt;&lt;td style=&quot;width: 53.4496%; height: 20px;&quot;&gt;모든 테스트 실행 후에 실행한 테스트에사용&lt;/td&gt;&lt;td style=&quot;width: 23.4496%; height: 20px;&quot;&gt;@After&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 20px;&quot;&gt;&lt;td style=&quot;width: 23.1007%; height: 20px;&quot;&gt;@BeforeAll&lt;/td&gt;&lt;td style=&quot;width: 53.4496%; height: 20px;&quot;&gt;현재 클래스를 실행하기 전 제일 먼저 실행할 테스트 작성 &lt;span style=&quot;color: #333333;&quot;&gt;static로 선언&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;width: 23.4496%; height: 20px;&quot;&gt;@BeforeClass&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 20px;&quot;&gt;&lt;td style=&quot;width: 23.1007%; height: 20px;&quot;&gt;@AfterAll&lt;/td&gt;&lt;td style=&quot;width: 53.4496%; height: 20px;&quot;&gt;현재 클래스 종료 후 해당 테스트를 실행 &lt;span style=&quot;color: #333333;&quot;&gt;static로 선언&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;width: 23.4496%; height: 20px;&quot;&gt;@AfterClass&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 20px;&quot;&gt;&lt;td style=&quot;width: 23.1007%; height: 20px;&quot;&gt;@Nested&lt;/td&gt;&lt;td style=&quot;width: 53.4496%; height: 20px;&quot;&gt;클래스를 정적이 아닌 중첩 테스트 클래스임을 나타냅니다.&lt;/td&gt;&lt;td style=&quot;width: 23.4496%; height: 20px;&quot;&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 20px;&quot;&gt;&lt;td style=&quot;width: 23.1007%; height: 20px;&quot;&gt;@Tag&lt;/td&gt;&lt;td style=&quot;width: 53.4496%; height: 20px;&quot;&gt;클래스또는 메소드 레벨에서 태그를 선언할 때 사용, 이를 메이븐을 사용할 경우 설정에서 테스트를 태그를 인식해 포함하거나 제외시킬 수 있다&lt;/td&gt;&lt;td style=&quot;width: 23.4496%; height: 20px;&quot;&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 20px;&quot;&gt;&lt;td style=&quot;width: 23.1007%; height: 20px;&quot;&gt;@Disabled&lt;/td&gt;&lt;td style=&quot;width: 53.4496%; height: 20px;&quot;&gt;이 클래스나 테스트를 사용하지 않음을 표시&lt;/td&gt;&lt;td style=&quot;width: 23.4496%; height: 20px;&quot;&gt;@Ignore&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 20px;&quot;&gt;&lt;td style=&quot;width: 23.1007%; height: 20px;&quot;&gt;@Timeout&lt;/td&gt;&lt;td style=&quot;width: 53.4496%; height: 20px;&quot;&gt;테스트 실행 시간을 선언 후 초과되면 실패하도록 설정&lt;/td&gt;&lt;td style=&quot;width: 23.4496%; height: 20px;&quot;&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 20px;&quot;&gt;&lt;td style=&quot;width: 23.1007%; height: 20px;&quot;&gt;@ExtendWith&lt;/td&gt;&lt;td style=&quot;width: 53.4496%; height: 20px;&quot;&gt;확장을 선언적으로 등록할 때 사용&lt;/td&gt;&lt;td style=&quot;width: 23.4496%; height: 20px;&quot;&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 20px;&quot;&gt;&lt;td style=&quot;width: 23.1007%; height: 20px;&quot;&gt;@RegisterExtension&lt;/td&gt;&lt;td style=&quot;width: 53.4496%; height: 20px;&quot;&gt;필드를 통해 프로그래밍 방식으로 확장을 등록할 때 사용&lt;/td&gt;&lt;td style=&quot;width: 23.4496%; height: 20px;&quot;&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 20px;&quot;&gt;&lt;td style=&quot;width: 23.1007%; height: 20px;&quot;&gt;@TempDir&lt;/td&gt;&lt;td style=&quot;width: 53.4496%; height: 20px;&quot;&gt;필드 주입 또는 매개변수 주입을 통해 임시 디렉토리를 제공하는데 사용&lt;/td&gt;&lt;td style=&quot;width: 23.4496%; height: 20px;&quot;&gt;&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;각각 어노테이션의 사용법은 추후 시간이 나면 포스팅하고, 참고할 만한 링크를 남깁니다. 위에 링크로 연결된 JUnit5 User Guide 또는 아래 링크에서 사용법 설명을 볼 수 있습니다.&lt;br&gt;baeldung : &lt;a href=&quot;https://www.baeldung.com/?s=Guide+JUnit5&quot;&gt;https://www.baeldung.com/?s=Guide+JUnit5&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;사용자 정의 어노테이션&lt;/h1&gt;
&lt;p&gt;JUnit Jupiter의 주석은 &lt;em&gt;메타 주석&lt;/em&gt; 으로 사용할 수 있습니다.&lt;br&gt;예를 들어 &lt;code&gt;@Tag(&amp;quot;fast&amp;quot;)&lt;/code&gt;를 매번 사용하는 대신 &lt;code&gt;@FAST&lt;/code&gt;로 정의하여 사용 가능&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;h5&gt;Fast Annotation&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Tag(&amp;quot;fast&amp;quot;)
public @interface Fast { }  &lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;h5&gt;Test Method&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Fast
@Test
void myFastTest() { 
...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;나아가 &lt;code&gt;@Fast&lt;/code&gt;, &lt;code&gt;@Test&lt;/code&gt;를 섞은 &lt;code&gt;@FastTest&lt;/code&gt;로도 선언가능&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Tag(&amp;quot;fast&amp;quot;)
@Test
public @interface FastTest {
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;테스트 클래스 및 메소드 작성&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;Test Class&lt;/strong&gt; : 최소한 하나의 테스트 메소드를 포함하는 최상위 클래스를 말하며, &lt;code&gt;abstract&lt;/code&gt;이면 안되고, &lt;code&gt;single constructor&lt;/code&gt;이어야 한다.&lt;br&gt;&lt;strong&gt;Test Method&lt;/strong&gt; : &lt;code&gt;@Test&lt;/code&gt;, &lt;code&gt;@RepeatedTest&lt;/code&gt;, &lt;code&gt;@ParameterizedTest&lt;/code&gt;, &lt;code&gt;@TestFactory&lt;/code&gt;, &lt;code&gt;@TestTemplate&lt;/code&gt;로 선언된 테스트 메소드&lt;br&gt;&lt;strong&gt;Lifecycle Method&lt;/strong&gt; : &lt;code&gt;@BeforeAll&lt;/code&gt;, &lt;code&gt;@AfterAll&lt;/code&gt;, &lt;code&gt;@BeforeEach&lt;/code&gt;, &lt;code&gt;@AfterEach&lt;/code&gt; 로 선언된 메소드&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;h5&gt;작성 예시&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;class MyTest{

@BeforeAll
static void initAll(){ }

@BeforeEach
void init(){ }

@Test
void standardTest() { }

@Test
@Disabled(&amp;quot;description 작성, 데모용 테스트&amp;quot;)
void disabledTest(){ }

@Test
void abortedTest() {
   assumeTrue(&amp;quot;abc&amp;quot;.contains(&amp;quot;Z&amp;quot;));
   fail(&amp;quot;test should have been aborted&amp;quot;);
}

@AfterEach
void tearDown() { } 

@AfterAll
static void testDownAll() { }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같이 간단하게 테스트를 작성했다고 가정하면 실행 순서는&lt;br&gt;&lt;code&gt;initAll() -&amp;gt; init() -&amp;gt; standardTest() -&amp;gt; tearDown() -&amp;gt; init() -&amp;gt; abortedTest() -&amp;gt; tearDown() -&amp;gt; testDownAll()&lt;/code&gt; 순으로 동작하게 된다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;JUnit5 Assertions&lt;/h1&gt;
&lt;p&gt;기본적으로 JUnit4의 Assertions를 포함하며 java 8 람다와 함께 사용하기 위해 몇가지를 추가했습니다. 모든 JUnit Jupiter 어셜션은 클래스의 &lt;code&gt;static&lt;/code&gt; 메소드입니다. &lt;code&gt;org.junit.jupiter.api.Assertions&lt;/code&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 221px;&quot; border=&quot;1&quot; data-ke-style=&quot;style4&quot;&gt;&lt;tbody&gt;&lt;tr style=&quot;height: 19px;&quot;&gt;&lt;td style=&quot;width: 28.8372%; height: 19px;&quot;&gt;메소드&lt;/td&gt;&lt;td style=&quot;width: 71.1628%; height: 19px;&quot;&gt;설명&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 68px;&quot;&gt;&lt;td style=&quot;width: 28.8372%; height: 68px;&quot;&gt;assertAll ( &lt;span style=&quot;color: #333333;&quot;&gt;executables...)&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;width: 71.1628%; height: 68px;&quot;&gt;&lt;p&gt;구문 오류시 예외를 발생시키지 않으면서 한번에 모든 구문을 확인 할 수 있습니다.&amp;nbsp;&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 39px;&quot;&gt;&lt;td style=&quot;width: 28.8372%; height: 39px;&quot;&gt;assertEquals( &lt;span style=&quot;color: #333333;&quot;&gt;expected, &lt;span style=&quot;color: #333333;&quot;&gt;actual )&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;width: 71.1628%; height: 39px;&quot;&gt;실제 값과 예상 값이 같은지 확인, 이 외 assertArrayEquals(), assertNotEquals() 도 존재&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 19px;&quot;&gt;&lt;td style=&quot;width: 28.8372%; height: 19px;&quot;&gt;assertNotNull( actual )&lt;/td&gt;&lt;td style=&quot;width: 71.1628%; height: 19px;&quot;&gt;값이 null인지 아닌지 확인&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 19px;&quot;&gt;&lt;td style=&quot;width: 28.8372%; height: 19px;&quot;&gt;assertTrue( boolean )&lt;/td&gt;&lt;td style=&quot;width: 71.1628%; height: 19px;&quot;&gt;다음 조건이 참인지 확인&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 19px;&quot;&gt;&lt;td style=&quot;width: 28.8372%; height: 19px;&quot;&gt;assertThrows( &lt;span style=&quot;color: #333333;&quot;&gt;expectedType,&amp;nbsp; &lt;span style=&quot;color: #333333;&quot;&gt;executable )&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;width: 71.1628%; height: 19px;&quot;&gt;예외를 발생 시키는지 확인&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 19px;&quot;&gt;&lt;td style=&quot;width: 28.8372%; height: 19px;&quot;&gt;assertTimeout ( &lt;span style=&quot;color: #333333;&quot;&gt;timeout, &lt;span style=&quot;color: #333333;&quot;&gt;executable )&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;width: 71.1628%; height: 19px;&quot;&gt;특정 시간안에 실행하는지 확인&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;height: 19px;&quot;&gt;&lt;td style=&quot;width: 28.8372%; height: 19px;&quot;&gt;assertTimeoutPreemptively( timeout, executable )&amp;nbsp;&lt;/td&gt;&lt;td style=&quot;width: 71.1628%; height: 19px;&quot;&gt;특정 시간안에 실행하는지 확인 후, 시간을 초과하면 실행 파일의 실행이 중단되도록 설정. 단, executable와 다른 스레드에서 실행하기 때문에, 원치 않는 결과가 발생할 수 있다. ex ) 트랜잭션이 적용이 안되서 롤백이 안되는 경우&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;이 외 assertSame()등, 많은 메소드가 존재하니 자세한 내용은 아래 API 링크를 통해 참고하시면 될 것 같습니다.&lt;/p&gt;
&lt;p&gt;JUnit5 Assertions API : &lt;a href=&quot;https://junit.org/junit5/docs/current/api/org.junit.jupiter.api/org/junit/jupiter/api/Assertions.html&quot;&gt;https://junit.org/junit5/docs/current/api/org.junit.jupiter.api/org/junit/jupiter/api/Assertions.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;그 외 써드파티 라이브러리로 &lt;code&gt;AssertJ&lt;/code&gt;, &lt;code&gt;Hamcrest&lt;/code&gt;, &lt;code&gt;Truth&lt;/code&gt;등을 사용할 수 있습니다.&lt;/p&gt;
&lt;h5&gt;작성 예시&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;객체 생성 테스트&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Test
void create_new_member{
  Member member = Member.builder()
                  .name(&amp;quot;Lee&amp;quot;)
                  .build();
  assertNotNull(member);
  assertEquals(&amp;quot;Lee&amp;quot;, member.getName());
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같이 객체 생성이 정상적으로 되었는지, 값이 원하는 값인지 확인하는 테스트를 작성할 수 있습니다.&lt;br&gt;또한 assert에는 마지막 인자로 &lt;code&gt;String&lt;/code&gt; 또는 &lt;code&gt;Supplier&amp;lt;String&amp;gt;&lt;/code&gt;를 통해 메세지를 출력할 수 있습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;테스트 결과 오류메세지 설정&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Test
void create_new_member{
  Member member = Member.builder()
                  .name(&amp;quot;Lee&amp;quot;)
                  .build();
  // assertEquals(&amp;quot;Park&amp;quot;, member.getName(), &amp;quot;생성된 member의 name이 Lee가 아닙니다.&amp;quot;);
  assertEquals(&amp;quot;Park&amp;quot;, member.getName(), () -&amp;gt; &amp;quot;생성된 member의 name이 Lee가 아닙니다.&amp;quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Exception 확인&lt;br&gt;Member에 age라는 필드를 추가해주고 생성자를 통해 생성 시 음수가 들어오면 Exception을 발생하도록 로직을 만들어 줍니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;public Class Member {
  private int age;

  public Member(int age) {
      if( age &amp;lt; 0 ) throw new IllegalArgumentException();
      this.age = age;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같이 Member 클래스가 있을 경우 아래와 같이 테스트 작성 가능&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Test
void create_new_member{
  assertThrows(IllegalArgumentException.class, () -&amp;gt; new Member(-100));
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;나아가 Exception 타입으로 리턴값을 받을 경우 해당 exception을 활용가능&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Test
void create_new_member{
  IllegalArgumentException exception = 
      assertThrows(IllegalArgumentException.class, () -&amp;gt; new Member(-100));

  // excetpion 활용..
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;assertTimeout&lt;br&gt;시간에 대한 제한을 줄 경우 사용&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;void create_new_member{
  assertTimeout(Duration.ofSeconds(2), () -&amp;gt; {
      new  Member();
      Thread.sleep(3000);
  });
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;해당 assertion의 경우 시간제한을 2초로 주었지만, 실제 실행인 3초 이상까지 테스트가 실패하는 경우에도 실행을 하게 됩니다. 이럴 경우 사용하는 assertion이 &lt;code&gt;assertTimeoutPreemptively&lt;/code&gt;이며 사용법은 동일합니다.&lt;br&gt;다만 &lt;code&gt;ThreadLocal&lt;/code&gt;을 사용하는 경우 예상치 못한 예외를 발생할 수 있기 때문에 사용에 주의해야 합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Agile/TDD(Test Driven Development)</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/116</guid>
      <comments>https://lee1535.tistory.com/116#entry116comment</comments>
      <pubDate>Thu, 30 Jan 2020 10:11:56 +0900</pubDate>
    </item>
    <item>
      <title>[web] HTTP란 HTTP의 구조 및 핵심 요소</title>
      <link>https://lee1535.tistory.com/111</link>
      <description>&lt;h1&gt;HTTP&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;HYPERTEXT TRANSFER PROTOCOL의 약자&lt;/li&gt;
&lt;li&gt;클라이언트와 서버 사이에 이루어지는 요청/응답 프로토콜.&lt;/li&gt;
&lt;li&gt;80번 포트를 사용하며, TCP와 UDP를 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;여기까지가 대학생활에서 내가 이해하고 그냥 넘어갔던 부분이다. 그냥 서버와 클라이언트 상의 어떠한 규약이 있구나라고...&lt;/p&gt;
&lt;p&gt;아래 관련 내용이 길게 나와있는데 쉽게 설명하면 클라이언트와 서버가 데이터를 일정한 규칙 ( 헤더,바디) 를 통해서 정보를 주고받는 방식이라고 생각하면 될 것 같다.&lt;/p&gt;
&lt;h1&gt;HTTP 통신 방식&lt;/h1&gt;
&lt;hr /&gt;
&lt;h5&gt;1. 요청(request) - 응답(response) 방식&lt;/h5&gt;
&lt;p&gt;클라이언트(웹브라우저)가 요청을 서버에 보내면, 서버는 요청에 따른 처리 후 결과에 따른 HTTP 응답을 클라이언트에 보낸다.&lt;/p&gt;
&lt;h5&gt;2. 비상태연결(Stateless, Connectless)&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;HTTP 통신은 state라는 개념이 없다. 요청하고 응답을 받으면 연결을 끊어버린다. -&amp;gt; 서버와 클라이언트는 독립적
&lt;ul&gt;
&lt;li&gt;장점 : 접속유지 최소화, 연결상태 처리, 정보의 저장관리가 불필요해 서버 디자인이 간단하다.&lt;/li&gt;
&lt;li&gt;단점 : 접속이 유지되지 않기 때문에 이전 통신에 정보를 알 수 없음, 따라서 로그인등과 같이 정보를 유지해야 하는 경우에도 정보 유지 불가. 이를 해결하기 위해 쿠키, 세션등을 이용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;HTTP 요청(request), 응답(response)의 구조&lt;/h1&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li&gt;요청 내용 : 요청 또는 요청 수행에 대한 성공 또는 실패가 기록되며, 이 줄은 항상 한줄로 끝납니다.&lt;/li&gt;
&lt;li&gt;헤더 : 옵션으로 헤더 세트가 들어갑니다. 여기에는 요청에 대한 설명, 혹은 메세지 본문에 대한 설명이 들어갑니다.&lt;/li&gt;
&lt;li&gt;빈줄 : 요청에 대한 모든 메타 정보가 전송되었음을 알리는 빈줄입니다.&lt;/li&gt;
&lt;li&gt;바디(body) : 요청과 관련된 내용(HTML form 컨텐츠 등)이 옵션으로 들어가거나, 응답과 관련된 문서(document)가 들어갑니다. 본문의 존재 유무 및 크기는 요청 헤더에 명시됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;1번과 2번을 묶어서 요청 헤드라고 부르며, 4번을 본문(body)라고 부릅니다.&lt;/p&gt;
&lt;h5&gt;요청(request) 구조&lt;/h5&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;#1
POST / HTTP/1.1
#2
Host: localhost:8080       
Accept: text/html,application/xhtml+xml,application/xml;...
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)...
Content-Length: 1000
Content-Type: text/html,application/xhtml+xml,application/xml;...
#3                            
#4
{                            
    &quot;user_name&quot;: &quot;lee&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;응답(response) 구조&lt;/h5&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;#1
HTTP/1.1 404 Not Found
#2
Connection: close     
Content-Lenght:2000
Content-Type: text/html,application/xhtml+xml,application/xml;...
#3                            
#4
&amp;lt;DOCTYPE html&amp;gt;
&amp;lt;html lang=ko&amp;gt;
    .....
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;HTTP 요청 메소드&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;HTTP 메소드란 HTTP 통신 요청이 이루어질 때 어떠한 액션을 요청하는지 알려준다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 200px;&quot; border=&quot;1&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 12.5581%; height: 20px;&quot;&gt;HTTP 메소드&lt;/td&gt;
&lt;td style=&quot;width: 14.4186%; height: 20px;&quot;&gt;요청 Body 여부&lt;/td&gt;
&lt;td style=&quot;width: 14.6512%; height: 20px;&quot;&gt;응답 Body 여부&lt;/td&gt;
&lt;td style=&quot;width: 28.7209%; height: 20px;&quot;&gt;전송형태&lt;/td&gt;
&lt;td style=&quot;width: 29.6512%; height: 20px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 12.5581%; height: 20px;&quot;&gt;GET&lt;/td&gt;
&lt;td style=&quot;width: 14.4186%; height: 20px;&quot;&gt;x&lt;/td&gt;
&lt;td style=&quot;width: 14.6512%; height: 20px;&quot;&gt;o&lt;/td&gt;
&lt;td style=&quot;width: 28.7209%; height: 20px;&quot;&gt;GET [request-uri] HTTP/1.1&lt;/td&gt;
&lt;td style=&quot;width: 29.6512%; height: 20px;&quot;&gt;요청받은 정보를 검색하여 응답&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 12.5581%; height: 20px;&quot;&gt;HEAD&lt;/td&gt;
&lt;td style=&quot;width: 14.4186%; height: 20px;&quot;&gt;x&lt;/td&gt;
&lt;td style=&quot;width: 14.6512%; height: 20px;&quot;&gt;x&lt;/td&gt;
&lt;td style=&quot;width: 28.7209%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;HEAD&lt;/span&gt;[request-uri] HTTP/1.1&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 29.6512%; height: 20px;&quot;&gt;GET과 동일하지만 응답에 BODY없이 응답코드, HEAD만 응답&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 12.5581%; height: 20px;&quot;&gt;POST&lt;/td&gt;
&lt;td style=&quot;width: 14.4186%; height: 20px;&quot;&gt;o&lt;/td&gt;
&lt;td style=&quot;width: 14.6512%; height: 20px;&quot;&gt;o&lt;/td&gt;
&lt;td style=&quot;width: 28.7209%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;POST&lt;/span&gt;[request-uri] HTTP/1.1&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 29.6512%; height: 20px;&quot;&gt;자원 생성(CREATE)에 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 12.5581%; height: 20px;&quot;&gt;PUT&lt;/td&gt;
&lt;td style=&quot;width: 14.4186%; height: 20px;&quot;&gt;o&lt;/td&gt;
&lt;td style=&quot;width: 14.6512%; height: 20px;&quot;&gt;o&lt;/td&gt;
&lt;td style=&quot;width: 28.7209%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;PUT&lt;/span&gt;[request-uri] HTTP/1.1&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 29.6512%; height: 20px;&quot;&gt;자원 전체 수정(UPDATE)에 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 12.5581%; height: 20px;&quot;&gt;PATCH&lt;/td&gt;
&lt;td style=&quot;width: 14.4186%; height: 20px;&quot;&gt;x&lt;/td&gt;
&lt;td style=&quot;width: 14.6512%; height: 20px;&quot;&gt;o&lt;/td&gt;
&lt;td style=&quot;width: 28.7209%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;PATCH&lt;/span&gt;[request-uri] HTTP/1.1&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 29.6512%; height: 20px;&quot;&gt;PUT과 동일하게 수정에 사용되지만, 해당 자원의 일부 수정시 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 12.5581%; height: 20px;&quot;&gt;DELETE&lt;/td&gt;
&lt;td style=&quot;width: 14.4186%; height: 20px;&quot;&gt;o&lt;/td&gt;
&lt;td style=&quot;width: 14.6512%; height: 20px;&quot;&gt;o&lt;/td&gt;
&lt;td style=&quot;width: 28.7209%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;DELETE&lt;/span&gt;[request-uri] HTTP/1.1&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 29.6512%; height: 20px;&quot;&gt;자원 삭제(DELETE)에 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 12.5581%; height: 20px;&quot;&gt;CONNECT&lt;/td&gt;
&lt;td style=&quot;width: 14.4186%; height: 20px;&quot;&gt;선택사항&lt;/td&gt;
&lt;td style=&quot;width: 14.6512%; height: 20px;&quot;&gt;o&lt;/td&gt;
&lt;td style=&quot;width: 28.7209%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;CONNECT&lt;/span&gt;[request-uri] HTTP/1.1&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 29.6512%; height: 20px;&quot;&gt;동적으로 터널 모드 교환, 프록시 기능을 요청시에 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 12.5581%; height: 20px;&quot;&gt;TRACE&lt;/td&gt;
&lt;td style=&quot;width: 14.4186%; height: 20px;&quot;&gt;x&lt;/td&gt;
&lt;td style=&quot;width: 14.6512%; height: 20px;&quot;&gt;o&lt;/td&gt;
&lt;td style=&quot;width: 28.7209%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;TRACE&lt;/span&gt;[request-uri] HTTP/1.1&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 29.6512%; height: 20px;&quot;&gt;원격ㅣ 서버에 프백 메세지 호출을 위해 테스트용으로 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 12.5581%; height: 20px;&quot;&gt;OPTIONS&lt;/td&gt;
&lt;td style=&quot;width: 14.4186%; height: 20px;&quot;&gt;o&lt;/td&gt;
&lt;td style=&quot;width: 14.6512%; height: 20px;&quot;&gt;o&lt;/td&gt;
&lt;td style=&quot;width: 28.7209%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;OPTIONS&lt;/span&gt;[request-uri] HTTP/1.1&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 29.6512%; height: 20px;&quot;&gt;웹서버에서 지원되는 메소드 종류를 확인할 경우 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;참고
&lt;ul&gt;
&lt;li&gt;POST / PUT : POST는 멱등하지 않고, PUT는 멱등하다. 즉, 동일한 자원을 여러번 POST할 경우 서버 자원에 변화가 생기지만 PUT는 변화가 생기지 않는다.&lt;/li&gt;
&lt;li&gt;PUT / PATCH : PUT는 전체 자원을 수정하기 동일한 수정일 경우 멱등하고, PATCH의 경우 일부가 변경되기 때문에 멱등하지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;멱등성 : 같은 작업을 반복해도 같은 결과가 나오는지 여부&lt;/p&gt;
&lt;h1&gt;HTTP 응답 코드&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;클라이언트가 요청하면 서버는 결과를 응답 코드와 함께 응답하게 된다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;코드&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;메세지&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;1XX (ex 100,101)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;Informational(정보)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;정보 교환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;2XX &lt;span style=&quot;color: #333333;&quot;&gt;(ex 200,202,203)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;Success(성공)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;데이터 전송이 성공적으로 이루어졌거나, 이해되었거나, 수락되었음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;3XX &lt;span style=&quot;color: #333333;&quot;&gt;(ex 300,301,302)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;Redirection(방향 변경)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;자료의 위치가 변경되었음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;4XX &lt;span style=&quot;color: #333333;&quot;&gt;(ex 400,404)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;Client Error(클라이언트 오류)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;클라이언트 측 오류&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;5XX &lt;span style=&quot;color: #333333;&quot;&gt;(ex 500,505)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;Server Error(서버 오류)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;서버 측의 오류&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;HTTL 주요 헤더 종류&lt;/h1&gt;
&lt;hr /&gt;
&lt;h5&gt;공통 헤더 - 요청(request), 응답(response) 둘다 사용&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;Date : HTTP 메세지를 생성할 일시&lt;/li&gt;
&lt;li&gt;Connection : 클라이언트와 서버 연결에 대한 설정
&lt;ul&gt;
&lt;li&gt;Connection: close : 통신 직후 TCP 접속 종료&lt;/li&gt;
&lt;li&gt;Connection: Keep-Alice : 현재 TCP 커넥션 유지&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Cache-Control
&lt;ul&gt;
&lt;li&gt;Cache-Control: no-store : 캐시 미사용&lt;/li&gt;
&lt;li&gt;Cache-Control: no-cache : 서버에게 확인 후 사용&lt;/li&gt;
&lt;li&gt;Cache-Control: must-revalidate : 만료된 캐시만 서버에서 확인&lt;/li&gt;
&lt;li&gt;Cache-Control: public : 공유 캐시에 저장가능&lt;/li&gt;
&lt;li&gt;Cache-Control: private : '브라우저' 같은 특정 사용자 환경에만 저장&lt;/li&gt;
&lt;li&gt;Cache-Control: max-age : 캐시 유효시간을 명시&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Pragma : HTTP/1.0에서 사용하던 캐시 제어&lt;/li&gt;
&lt;li&gt;Content-Type, Content-Encoding, Content-Length, Content-Language : 본문 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;요청 헤더&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;Host : 요청하려는 uri 정보&lt;/li&gt;
&lt;li&gt;User-agnet : 클라이언트 프로그램 정보 ex) 브라우저 정보&lt;/li&gt;
&lt;li&gt;Referer : 직전에 머물러 있던 페이지 정보&lt;/li&gt;
&lt;li&gt;Accept, Accept-charset, Accept-language, Accept-encoding : 클라이언트 정보&lt;/li&gt;
&lt;li&gt;Authorization : 인증 토큰 정보&lt;/li&gt;
&lt;li&gt;Origin : 맨 처음 시작 요청 주소값&lt;/li&gt;
&lt;li&gt;Cookie : 쿠기 값&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;응답 헤더&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;Location : 301,302 에 사용되는 해더로, 변경된 주소를 지정&lt;/li&gt;
&lt;li&gt;Server : 웹서버의 종류&lt;/li&gt;
&lt;li&gt;Age : max-age 시간에서 얼마나 지났는지 (초단위)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;그 외 헤더 자료들은 많기 때문에 추가로 필요한 정보는 검색을 통해서 알아보시면 될 것 같습니다.&lt;/p&gt;
&lt;h1&gt;참고 자료&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/HTTP&quot;&gt;https://ko.wikipedia.org/wiki/HTTP&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://jeong-pro.tistory.com/181?category=822281&quot;&gt;https://jeong-pro.tistory.com/181?category=822281&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://javaplant.tistory.com/18&quot;&gt;https://javaplant.tistory.com/18&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTTP/&quot;&gt;https://developer.mozilla.org/ko/docs/Web/HTTP/&lt;/a&gt;&lt;/p&gt;</description>
      <category>Web/web</category>
      <category>HTTP</category>
      <category>RESTful API</category>
      <category>web</category>
      <category>요청</category>
      <category>웹</category>
      <category>응답</category>
      <category>통신</category>
      <category>프로토콜</category>
      <category>헤더 정보</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/111</guid>
      <comments>https://lee1535.tistory.com/111#entry111comment</comments>
      <pubDate>Wed, 8 Jan 2020 12:42:18 +0900</pubDate>
    </item>
    <item>
      <title>[독서리뷰] Head First Design Pattern 스토리가 있는 패턴 학습법</title>
      <link>https://lee1535.tistory.com/110</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;다운로드 (1).jpg&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/owfdq/btqAQOrnmQW/TYi7Bn7a98xRF0jzJEusS0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/owfdq/btqAQOrnmQW/TYi7Bn7a98xRF0jzJEusS0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/owfdq/btqAQOrnmQW/TYi7Bn7a98xRF0jzJEusS0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fowfdq%2FbtqAQOrnmQW%2FTYi7Bn7a98xRF0jzJEusS0%2Fimg.jpg&quot; data-filename=&quot;다운로드 (1).jpg&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;이전에 &lt;code&gt;JAVA 언어로 배우는 디자인 패턴 입문&lt;/code&gt; 이라는 책을 공부하면서 말그대로 입문 서적이였기 때문에 가끔 부족한 설명이 느껴져서 매번 관련 래퍼런스를 검색해가며 공부를 병행했었다 자주 방문한 래퍼런스는 &lt;a href=&quot;https://refactoring.guru/design-patterns&quot;&gt;https://refactoring.guru/design-patterns&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1578038892912&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Design Patterns&quot; data-og-description=&quot;&quot; data-og-host=&quot;refactoring.guru&quot; data-og-source-url=&quot;https://refactoring.guru/design-patterns&quot; data-og-url=&quot;https://refactoring.guru/design-patterns&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/e1zMQ/hyEq3Jj1ib/423m5FUpHuTc85kT069VI1/img.png?width=476&amp;amp;height=249&amp;amp;face=0_0_476_249,https://scrap.kakaocdn.net/dn/cR5HZh/hyEqYBfeRH/WQHPhwKdZroHgeZ5aleLbk/img.png?width=960&amp;amp;height=1410&amp;amp;face=0_0_960_1410,https://scrap.kakaocdn.net/dn/xjXvo/hyEqXI7GcY/JNt4yAzGiWlmcf2B4oU3Tk/img.png?width=200&amp;amp;height=242&amp;amp;face=0_0_200_242&quot;&gt;&lt;a href=&quot;https://refactoring.guru/design-patterns&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://refactoring.guru/design-patterns&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/e1zMQ/hyEq3Jj1ib/423m5FUpHuTc85kT069VI1/img.png?width=476&amp;amp;height=249&amp;amp;face=0_0_476_249,https://scrap.kakaocdn.net/dn/cR5HZh/hyEqYBfeRH/WQHPhwKdZroHgeZ5aleLbk/img.png?width=960&amp;amp;height=1410&amp;amp;face=0_0_960_1410,https://scrap.kakaocdn.net/dn/xjXvo/hyEqXI7GcY/JNt4yAzGiWlmcf2B4oU3Tk/img.png?width=200&amp;amp;height=242&amp;amp;face=0_0_200_242');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Design Patterns&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;refactoring.guru&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h1&gt;각종 찬사들&lt;/h1&gt;
&lt;ul&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&gt;위와같은 인용구로 책을 시작합니다.&lt;/p&gt;
&lt;h1&gt;저자/개발자 소개&lt;/h1&gt;
&lt;ul&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;h1&gt;목차&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;디자인 패턴의 세계에 오신 것을 환영합니다 : 디자인 패턴 소개&lt;/li&gt;
&lt;li&gt;객체들에게 연락망을 돌립시다 : 옵저버 패턴&lt;/li&gt;
&lt;li&gt;객체 꾸미기 : 데코레이터 패턴&lt;/li&gt;
&lt;li&gt;객체지향 빵 굽기 : 팩토리 패턴&lt;/li&gt;
&lt;li&gt;세상에 단 하나뿐인 특별한 객체 : 싱글턴 패턴&lt;/li&gt;
&lt;li&gt;호출 캡술화 : 커맨드 패턴&lt;/li&gt;
&lt;li&gt;적응 시키기 : 어댑터 패턴과 퍼사드 패턴&lt;/li&gt;
&lt;li&gt;알고리즘 캡슐화 : 템플릿 메소드 패턴&lt;/li&gt;
&lt;li&gt;잘 관리된 컬렉션 : 이터레이터와 컴포지트 패턴&lt;/li&gt;
&lt;li&gt;객체의 상태 : 스테이트 패턴&lt;/li&gt;
&lt;li&gt;객체 접근 제어 : 프록시 패턴&lt;/li&gt;
&lt;li&gt;패턴들로 이루어진 패턴 : 컴파운드 패턴&lt;/li&gt;
&lt;li&gt;실전에서의 디자인 패턴 : 패턴과 함께 하는 행복한 ㅅ람&lt;/li&gt;
&lt;li&gt;부록 : 기타 패턴&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;마치며&lt;/h1&gt;
&lt;p&gt;확실히 인용구에 나와 있는 말처럼 처음에 책을 읽을 때 정신이없고, 전혀 눈에 들어오지 않아서 고생이 많았다.&lt;br /&gt;&amp;nbsp; 그러나 여러 그림, 계속되는 질문, 연관되어 있는 스토리를 통한 설계 등 여러 신박한 방식으로 책을 풀어가고 해당 패턴에 대한 설명도 엄청 자세하게 설명되어 있고 객체 지향의 근본적인 접근과, 디자인 패턴의 원칙으로 설명을 하니까 왜 하는지에 대한 이해가 확실한 것 같다.&lt;br /&gt;&amp;nbsp; 다만 아쉬운 점으론 해당 패터 하나하나 자세히 설명하다 보니 전부다 설명을 못하고...그래도 670페이지 가량 된다.&lt;br /&gt;기타 패턴으로 간략하게 설명만 하고 넘어가는데 그 부분은 추가로 공부가 필요할 것 같다&lt;br /&gt;&amp;nbsp; 전체적으로 엄청 만족하고 강추하는 책이다.. 기타 부록에 있는 패턴도 2탄으로 나왔으면 좋겠다는 생각이 드는 책.....&lt;/p&gt;
&lt;p&gt;마지막으로 자세한 내용은 해당 책을 구매하는것을 추천합니다. 강추!!하며, 관련 내용은 저의 블로그&amp;nbsp; &lt;a href=&quot;https://lee1535.tistory.com/category/JAVA/%EB%94%94%EC%9E%90%EC%9D%B8%ED%8C%A8%ED%84%B4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;디자인패턴 카테고리&lt;/a&gt;를 통해 확인이 가능합니다.&lt;/p&gt;</description>
      <category>일상/독서</category>
      <category>Design Pattern</category>
      <category>Head First Design Pattern</category>
      <category>Java</category>
      <category>디자인패턴</category>
      <category>자바</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/110</guid>
      <comments>https://lee1535.tistory.com/110#entry110comment</comments>
      <pubDate>Fri, 3 Jan 2020 17:10:02 +0900</pubDate>
    </item>
    <item>
      <title>[독서리뷰] JAVA 언어로 배우는 디자인 패턴 입문 - 유키 히로시</title>
      <link>https://lee1535.tistory.com/109</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;다운로드.jpg&quot; data-origin-width=&quot;200&quot; data-origin-height=&quot;251&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GohEw/btqARYzOLhC/4ujBZg1tyz0rKLLpa8Fk30/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GohEw/btqARYzOLhC/4ujBZg1tyz0rKLLpa8Fk30/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GohEw/btqARYzOLhC/4ujBZg1tyz0rKLLpa8Fk30/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGohEw%2FbtqARYzOLhC%2F4ujBZg1tyz0rKLLpa8Fk30%2Fimg.jpg&quot; data-filename=&quot;다운로드.jpg&quot; data-origin-width=&quot;200&quot; data-origin-height=&quot;251&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;자바 공부를 진행하는 도중 여러 서적에서 심심치 않게 등장하는 디자인 패턴 특히 스프링을 공부하다 보면 많이 접하게 되는 것 같습니다. 그래서 도대체 &lt;b&gt;디자인 패턴이 뭔데?라는&lt;/b&gt; 생각에 google의 여러 지식인 분들의 도움을 받아 하나하나 포스팅을 보게 되었지만, 내용이 생각보다 방대해서 책으로 공부를 해야겠다고 마음먹었습니다.&lt;br /&gt;여러 서적 중 많은 고민이 있었지만, &lt;code&gt;okky&lt;/code&gt;에 나와 같은 고민을 한 사람들이 상당히 존재했고, 초보 개발자가 보기엔 해당 책이 설명이 좋다는 글을 보고 알아보니 구성이 괜찮아 보여서 구매를 진행하였다.&lt;/p&gt;
&lt;h1&gt;이 책의 특징&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Java 언어에 의해 실제로 움직이는 예제 프로그램&lt;/li&gt;
&lt;li&gt;패턴 이름의 해설&lt;/li&gt;
&lt;li&gt;패턴 간의 관련과 연습문제&lt;/li&gt;
&lt;li&gt;Java 언어의 관련 정보&lt;/li&gt;
&lt;li&gt;패턴의 일러스트&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;이 책의 독자&lt;/h1&gt;
&lt;p&gt;해당 책은 아래와 같은 독자를 대상으로 합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;객체 지향에 관심이 있는 사람&lt;/li&gt;
&lt;li&gt;디자인 패턴에 관심이 있는 사람( 특히, GoF의 책을 보고 어렵다고 느낀 사람 )&lt;/li&gt;
&lt;li&gt;Java 프로그래머( 특히, 추상 클래스나 인터페이스의 이해가 부족한 사람 )&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;그 외&lt;/h1&gt;
&lt;p&gt;해당 책의 예제 프로그램도 제공해주고 모든 프로그램은 &lt;code&gt;public static void main(String[] args)&lt;/code&gt; 즉 매인 메소드를 통해서 예제를 풀어가는 방식으로 진행되는 책입니다.&lt;/p&gt;
&lt;h1&gt;마치며&lt;/h1&gt;
&lt;p&gt;책의 간단한 소개는 마무리하고, 자세한 내용은 저의 &lt;a href=&quot;https://lee1535.tistory.com/category/JAVA/%EB%94%94%EC%9E%90%EC%9D%B8%ED%8C%A8%ED%84%B4&quot;&gt;디자인 패턴 카테고리&lt;/a&gt;를 이용하시거나 제일 좋은 방법은 관련 서적을 구매해서 공부해보시는 것을 추천합니다.&lt;br /&gt;&amp;nbsp; 입문 난이도를 기준으로 잡았기 때문에 해당 패턴에 대한 개념과 원리에 대한 설명은 충분하지만, 좀 더 구체적인 내용은 다른 서적을 이용하거나 관련 적용된 &lt;code&gt;Open Source&lt;/code&gt;를 보면서 이해를 해야겠다는 생각이 들었습니다.&lt;br /&gt;&amp;nbsp;그래도 &lt;b&gt;디자인 패턴&lt;/b&gt;이 무엇인지 어떤 게 있는지 각각의 사용 이유와 어느 정도 객체지향에 대해서 조금은 친근해진 느낌이 드는 책이었습니다. 전체적으로 초보자에게 추천하는 책입니다.&lt;/p&gt;</description>
      <category>일상/독서</category>
      <category>Java</category>
      <category>study</category>
      <category>공부</category>
      <category>독서</category>
      <category>독서리뷰</category>
      <category>디자인패턴</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/109</guid>
      <comments>https://lee1535.tistory.com/109#entry109comment</comments>
      <pubDate>Fri, 3 Jan 2020 16:45:44 +0900</pubDate>
    </item>
    <item>
      <title>[TDD/테스트주도개발] TDD 개념</title>
      <link>https://lee1535.tistory.com/108</link>
      <description>&lt;p&gt;&lt;code&gt;테스트 주도 개발 TDD 실천법과 도구&lt;/code&gt; 정리한 내용입니다. 해당 내용은 Junit4 버전을 기준으로 설명합니다.&lt;br /&gt;책이 절판됨에 따라 저자인 채수원님께서 무료로 PDF를 공개하셨으니 블로그에서 관련 자료 다운로드가 가능합니다.&lt;br /&gt;또한 책이 2010년에 출간되었다는 점에서 저자분이 해당 내용에 보충할 만한 내용도 같이 정리해서 올려주시니 관련 링크를 통해서 참고하시는게 제일 좋은 방법일 것 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://repo.yona.io/doortts/blog/issue/1&quot;&gt;https://repo.yona.io/doortts/blog/issue/1&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;목차&lt;/h1&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li&gt;테스트 주도 개발&lt;/li&gt;
&lt;li&gt;JUnit과 Hamcrest&lt;/li&gt;
&lt;li&gt;TDD 좀 더 잘하기&lt;/li&gt;
&lt;li&gt;한계 돌파를 위한 노력, Mock을 이용한 TDD&lt;/li&gt;
&lt;li&gt;데이터베이스 테스트 : DbUnit&lt;/li&gt;
&lt;li&gt;단위 테스트 지원 라이브러리 : Unitils&lt;/li&gt;
&lt;li&gt;개발 영역에 따른 TDD 작성 패턴&lt;/li&gt;
&lt;li&gt;TDD에 대한 다양한 시작&lt;/li&gt;
&lt;li&gt;자주 접하게 되는 질문들, FAQ&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;h1&gt;1. 테스트 주도 개발&lt;/h1&gt;
&lt;h5&gt;1-1. TDD란?&lt;/h5&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;code&gt;Test Driven Development&lt;/code&gt;의 약자로 말 그대로 테스트 주도 개발이라는 언어입니다.&lt;br /&gt;즉 기존의 SW를 개발하고 테스트를 하는 방식이 아닌, 테스트부터 작성하면서 코드를 작성하는 방법을 말합니다.&lt;/p&gt;
&lt;h5&gt;1-2. TDD 개발의 진행 방식&lt;/h5&gt;
&lt;hr /&gt;
&lt;p&gt;해당 책에서는 TDD를 크게 3가지의 단계가 반복적으로 이루어진다고 설명하고 있습니다.&lt;/p&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;* 질문 : 테스트 작성을 통해 시스템에 질문 ( 테스트 실패 )  
* 응답 : 테스트를 통과하는 코드를 작성해서 질문에 대답한다 ( 테스트 성공 )
* 정체 : 통합, 불필요한 부분 제거 등의 리팩토링
* 반복 : 위 3가지를 반복을 통해 계속 작성해 나간다.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5kpyq/btqARiSWD9g/OQX32kaNqyvnUTptucem41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5kpyq/btqARiSWD9g/OQX32kaNqyvnUTptucem41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5kpyq/btqARiSWD9g/OQX32kaNqyvnUTptucem41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5kpyq%2FbtqARiSWD9g%2FOQX32kaNqyvnUTptucem41%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h5&gt;1-3. TDD의 간단한 실습 예제&lt;/h5&gt;
&lt;hr /&gt;
&lt;p&gt;아래와 같은 테스트가 필요하다고 정의합니다.&lt;/p&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;1. Member 클래스 필요
2. Member의 기능
    * ID 받아오기
    * 비밀번호 암호화하기
    * 기타등등..
3. 기타 등..&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;최초로 프로젝트를 생성 후, 임시로 Test 클래스를 하나 작성해봅니다. 그리고 annotation으로 @Test를 선언해주고 메소드를 하나 만들어줍니다. 그 후 아래와 같은 질문을 통해서 테스트 케이스를 작성합니다.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;public class TestAccount() {
    @Teest
    public void testMember() {
           Member member = new Member();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와같이 작성 후 &lt;code&gt;JUnit4&lt;/code&gt;으로 실행을 합니다. &lt;code&gt;Membmer&lt;/code&gt; 클래스가 정의되어 있지 않은 상태에서 인스턴스화 하려고 하니 당연히 오류가 발생합니다. &lt;b&gt;이 단계가 질문에 해당합니다.&lt;/b&gt;&lt;br /&gt;&amp;nbsp; &lt;b&gt;이제 응답 단계입니다.&lt;/b&gt; 어려울거 없이 &lt;code&gt;Member&lt;/code&gt;클래스를 생성해주면 그만입니다. 그리고 임의의 요구에 따라서 &lt;code&gt;null&lt;/code&gt;이면 안되는 객체이기 때문에 조건을 추가해줍니다.&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;public class TestAccount {
    @Test
    public void testMember() throws Exception {
        Member member = new Member();
        if(member == null) {
            throw new Exception(&quot;member 생성 실패!&quot;);
        }
        // 또는
        assertNotNull(member);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;마지막으로 &lt;b&gt;정제(리팩토링) 단계입니다.&lt;/b&gt; 통상적으로 아래와 같은 고민 후 소스를 리팩토링해줍니다.&lt;/p&gt;
&lt;ul&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&gt;자 이제 저희는 위 예제에서 개선이 필요한 부분은 없는가? 에서 한가지 제거할 코드가 존재합니다.&lt;br /&gt;사실 &lt;code&gt;new&lt;/code&gt; 연산자를 통해 인스턴스 생성 시 오류가 발생하면 자동으로 &lt;code&gt;Exception&lt;/code&gt;이 발생하고, 그 상황을 JUnit가 처리하기 때문에 &lt;code&gt;null&lt;/code&gt;인지 체크하는 부분은 더 이상 필요가 없어집니다.&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;public class TestAccount {
    @Test
    public void testMember() throws Exception {
        Member member = new Member();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;여기까지가 질문 1인 Member 클래스 검증 부분을 끝마쳤습니다. 사실 예제가 간단해서 억지스러운 부분도 존재하지만, TDD를 어떤식으로 진행하는지에 대한 감익히기가 목표이기 때문에 전체적은 느낌을 이해하셨다면 성공이라고 생각합니다.&lt;/p&gt;
&lt;h5&gt;1-4. TDD 장점&lt;/h5&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;개발의 방향을 잃지 않게 유지해준다.&lt;/li&gt;
&lt;li&gt;품질 높은 소프트웨어 모듈 보유, 시스템 결함이 줄어든다.&lt;/li&gt;
&lt;li&gt;자동화된 단위 테스트 케이스를 갖게 된다. 유지보수 용이&lt;/li&gt;
&lt;li&gt;사용설명서 &amp;amp; 의사소통의 수단, 테스트 문서로 사용 가능&lt;/li&gt;
&lt;li&gt;설계 개선. 필자가 제일 강조하며, 본인이 얼마나 의존적이고 즉흥적인 설계를 하고 있는지 체감할 수 있다고 한다...&lt;/li&gt;
&lt;li&gt;TDD는 주기를 짧게 설정하도록 권장해서, 성공했다는 성취감을 얻음으로써 능률을 향상 시킨다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;1-5. 엉클 밥의 TDD 원칙&lt;/h5&gt;
&lt;hr /&gt;
&lt;p&gt;엉클 밥은 로버트 마틴(Robert C. Martin)으로 객체 지향 개발의 선구자로 유명하다. 이 분이 권장하는 TDD의 원칙 3가지를 소개합니다.&lt;/p&gt;
&lt;ol&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;3번은 의외인것 같다. 추후 사용해보면서 체감을 할 수 있기를 바라면서&lt;/p&gt;</description>
      <category>Agile/TDD(Test Driven Development)</category>
      <category>Java</category>
      <category>TDD</category>
      <category>애자일</category>
      <category>엉클밥</category>
      <category>자바</category>
      <category>테스트주도개발</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/108</guid>
      <comments>https://lee1535.tistory.com/108#entry108comment</comments>
      <pubDate>Fri, 3 Jan 2020 16:17:47 +0900</pubDate>
    </item>
    <item>
      <title>[자바/알고리즘] 프로그래머스 탑</title>
      <link>https://lee1535.tistory.com/107</link>
      <description>&lt;h1&gt;문제 설명&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;수평 직선에 탑 N대를 세웠습니다. 모든 탑의 꼭대기에는 신호를 송/수신하는 장치를 설치했습니다. 발사한 신호는 신호를 보낸 탑보다 높은 탑에서만 수신합니다. 또한, 한 번 수신된 신호는 다른 탑으로 송신되지 않습니다.&lt;br /&gt;$nbsp;예를 들어 높이가 6, 9, 5, 7, 4인 다섯 탑이 왼쪽으로 동시에 레이저 신호를 발사합니다. 그러면, 탑은 다음과 같이 신호를 주고받습니다. 높이가 4인 다섯 번째 탑에서 발사한 신호는 높이가 7인 네번째 탑이 수신하고, 높이가 7인 네 번째 탑의 신호는 높이가 9인 두 번째 탑이, 높이가 5인 세 번째 탑의 신호도 높이가 9인 두 번째 탑이 수신합니다. 높이가 9인 두 번째 탑과 높이가 6인 첫 번째 탑이 보낸 레이저 신호는 어떤 탑에서도 수신 할 수 없습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-style=&quot;style8&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;b&gt;송신 탑(높이)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;b&gt;수신 탑(높이)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;5(4)&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;4(7)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;4(7)&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;2(9)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;3(5)&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;2(9)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;2(9)&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;1(6)&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;맨 왼쪽부터 순서대로 탑의 높이를 담은 배열 heights가 매개변수로 주어질 때 각 탑이 쏜 신호를 어느 탑에서 받았는지 기록하는 배열을 &lt;code&gt;return&lt;/code&gt;하도록 &lt;code&gt;solution&lt;/code&gt; 함수를 작성해주세요.&lt;/p&gt;
&lt;h1&gt;제한 사항&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;heights는 길이 2 이상 100 이하인 정수 배열입니다.&lt;/li&gt;
&lt;li&gt;모든 탑의 높이는 1 이상 100 이하입니다.&lt;/li&gt;
&lt;li&gt;신호를 수신하는 탑이 없으면 0으로 표시합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;입출력 예&lt;/h1&gt;
&lt;hr /&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-style=&quot;style8&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;b&gt;heights&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;b&gt;return&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span&gt;[6,9,5,7,4]&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span&gt;[0,0,2,2,4]&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span&gt;[3,9,9,3,5,7,2]&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span&gt;[0,0,0,3,3,3,6]&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span&gt;[1,5,3,6,7,6,5]&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span&gt;[0,0,2,0,0,5,6]&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;입출력 예 설명&lt;/h1&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;입출력 예 #1&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;앞서 설명한 예와 같습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;입출력 예 #2&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[1,2,3]&lt;/code&gt; 번째 탑이 쏜 신호는 아무도 수신하지 않습니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[4,5,6]&lt;/code&gt; 번째 탑이 쏜 신호는 3번째 탑이 수신합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[7]&lt;/code&gt; 번째 탑이 쏜 신호는 6번째 탑이 수신합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;입출력 예 #3&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[1,2,4,5]&lt;/code&gt; 번째 탑이 쏜 신호는 아무도 수신하지 않습니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[3]&lt;/code&gt; 번째 탑이 쏜 신호는 2번째 탑이 수신합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[6]&lt;/code&gt; 번째 탑이 쏜 신호는 5번째 탑이 수신합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[7]&lt;/code&gt; 번째 탑이 쏜 신호는 6번째 탑이 수신합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;나의 풀이&lt;/h1&gt;
&lt;hr /&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;class Solution {
    public int[] solution(int[] heights) {
       int[] answer = new int[heights.length];
        for (int i = 1; i &amp;lt; heights.length; i++) {
            for (int j = i; j &amp;gt;= 0; j--) {
                if(heights[i] &amp;lt; heights[j]) {
                    answer[i] = j+1;
                    break;
                }
            }
        }
        return answer;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;풀이 설명&lt;/h5&gt;
&lt;p&gt;정답 배열을 순차적으로 기록하기 위해 바깥(i) 반복문은 1 ~ 배열의 크기 까지 반복문을 돌렸고&lt;br /&gt;몇번째 탑에서 송신하는지는 왼쪽으로 신호를 보내기 위해서 i ~ 0 까지 반복문을 돌려서 정답이 될 배열에 기록 후 리턴하는 방식으로 문제를 풀었습니다.&lt;/p&gt;</description>
      <category>알고리즘/프로그래머스</category>
      <category>Java</category>
      <category>알고리즘</category>
      <category>자바</category>
      <category>탑</category>
      <category>프로그래머스</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/107</guid>
      <comments>https://lee1535.tistory.com/107#entry107comment</comments>
      <pubDate>Thu, 2 Jan 2020 14:17:35 +0900</pubDate>
    </item>
    <item>
      <title>[디자인패턴/Design Pattern]  Flyweight Pattern / 플라이웨이트 패턴</title>
      <link>https://lee1535.tistory.com/106</link>
      <description>&lt;p&gt;관련 내용은 &lt;code&gt;[자바 언어로 배우는 디자인 패턴 입문]&lt;/code&gt;,&lt;code&gt;[Head First Design Pattern]&lt;/code&gt;의 내용을 참고해서 정리한 글입니다.&lt;br /&gt;잘못된 부분은 댓글로 피드백 부탁드립니다.&lt;/p&gt;
&lt;h1&gt;1. Flyweight 패턴이란?&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;어떤 클래스의 인스턴스 한 개만 가지고 여러 개의 &quot;가상 인스턴스&quot;를 제공하고 싶을 때 사용하는 패턴입니다.&lt;br /&gt;즉 인스턴스를 가능한 대로 공유시켜 쓸데없이 &lt;code&gt;new&lt;/code&gt;연산자를 통한 메모리 낭비를 줄이는 방식입니다.&lt;/p&gt;
&lt;h1&gt;2. Flyweight 패턴의 등장인물&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;Flyweight(플라이급)의 역할
&lt;ol&gt;
&lt;li&gt;공유에 사용할 클래스들의 인터페이스(API)를 선언합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;ConcreteFlyweight(구체적인 플라이급)의 역할
&lt;ol&gt;
&lt;li&gt;Flyweight의 내용을 정의합니다. 실제 공유될 객체입니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;FlyweightFactory(플라이급의 공장)의 역할
&lt;ol&gt;
&lt;li&gt;해당 공장을 사용해서 Flyweight의 인스턴스를 생성 또는 공유해주는 역할을 합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Client(클라이언트)의 역할
&lt;ol&gt;
&lt;li&gt;해당 패턴의 사용자 입니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Flyweight 패턴의 클래스 다이어그램&lt;/h5&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bt9WYm/btqAQOwAvEa/mnGiDFwmuKMUaOiNyamLF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bt9WYm/btqAQOwAvEa/mnGiDFwmuKMUaOiNyamLF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bt9WYm/btqAQOwAvEa/mnGiDFwmuKMUaOiNyamLF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbt9WYm%2FbtqAQOwAvEa%2FmnGiDFwmuKMUaOiNyamLF0%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;3. 예제&lt;/h1&gt;
&lt;hr /&gt;
&lt;h5&gt;3-1. Shape 인터페이스&lt;/h5&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public interface Shape {
    public void draw();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;해당 패턴을 적용할(공유로 사용될) 클래스들의 인터페이스(API)를 작성합니다.&lt;/p&gt;
&lt;h5&gt;3-2. Circle 클래스&lt;/h5&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;public class Circle implements Shape {
    private String color;
    private int x;
    private int y;
    private int radius;

    public Circle(String color) {
        this.color = color;
    }

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

    public void setX(int x) {
        this.x = x;
    }

    public void setY(int y) {
        this.y = y;
    }

    public void setRadius(int radius) {
        this.radius = radius;
    }

    @Override
    public void draw() {
        System.out.println(&quot;Circle [color=&quot; + color + &quot;, x=&quot; + x + &quot;, y=&quot; + y + &quot;, radius=&quot; + radius + &quot;]&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;ConcreteFlyweight&lt;/code&gt;에 해당하며 인터페이스(API)의 내용을 정의하고, 필요한 속성을 가질 수 있습니다.&lt;/p&gt;
&lt;h5&gt;3-3. ShapeFactory 클래스&lt;/h5&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;public class ShapeFactory {
    private static final HashMap&amp;lt;String, Circle&amp;gt; circleMap = new HashMap&amp;lt;&amp;gt;();

    public static Shape getCircle(String color) {
        Circle circle = (Circle)circleMap.get(color);

        if(circle == null) {
            circle = new Circle(color);
            circleMap.put(color,circle);
            System.out.println(&quot;==== 새로운 객체 생성 : &quot; + color + &quot;색 원 ====&quot; );
        } 

        return circle;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;getCircle()&lt;/code&gt;메소드를 통해 객체의 생성 또는 공유의 역할을 담당하며 클라이언트에게 응답해줍니다.&lt;/p&gt;
&lt;h5&gt;3-4. Main 클래스&lt;/h5&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {
        String[] colors = {&quot;Red&quot;,&quot;Green&quot;,&quot;Blue&quot;,&quot;Yellow&quot;};

        for (int i = 0; i &amp;lt; 10; i++) {
            Circle circle = (Circle)ShapeFactory.getCircle(colors[(int) (Math.random()*4)]);
            circle.setX((int) (Math.random()*100));
            circle.setY((int) (Math.random()*4));
            circle.setRadius((int) (Math.random()*10));
            circle.draw();
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;실행 결과&lt;/h5&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;==== 새로운 객체 생성 : Yellow색 원 ====
Circle [color=Yellow, x=76, y=2, radius=4]
Circle [color=Yellow, x=19, y=2, radius=8]
==== 새로운 객체 생성 : Red색 원 ====
Circle [color=Red, x=38, y=2, radius=2]
Circle [color=Red, x=41, y=0, radius=1]
Circle [color=Yellow, x=58, y=3, radius=2]
Circle [color=Yellow, x=31, y=0, radius=6]
==== 새로운 객체 생성 : Blue색 원 ====
Circle [color=Blue, x=7, y=3, radius=7]
Circle [color=Blue, x=84, y=2, radius=1]
Circle [color=Yellow, x=90, y=2, radius=2]
==== 새로운 객체 생성 : Green색 원 ====
Circle [color=Green, x=34, y=0, radius=2]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;로직에 의해 같은 색상의 원은 1개만 생성되며 생성된 객체를 공유하는걸 확인할 수 있습니다.&lt;/p&gt;
&lt;h5&gt;그렇다면 왜 사용할까?&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;실행시에 객체 인스턴스의 개수를 줄여서 메모리를 절약할 수 있습니다,&lt;/li&gt;
&lt;li&gt;여러 &quot;가상&quot; 객체의 상태를 한 곳에 집중시켜놓을 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;즉 어떤 클래스의 인스턴스가 아주 많이 필요하지만 모두 똑같은 방식으로 제어할 수 있는 경우에 유용하게 사용됩니다,&lt;br /&gt;그러나 아래와 같은 단점이 존재합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;특정 인스턴스만 다른 인스턴스처럼 동작하도록 하는 것이 불가능&lt;/li&gt;
&lt;li&gt;객체의 값을 변경하면 공유받은 &quot;가상&quot; 객체를 사용하는 곳에 영향을 줄 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;4. 관련 패턴&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;Proxy 패턴 : Flyweight 패턴에서는 인스턴스의 생성에 시간이 걸리는 경우, 인스턴스의 공유에 따라서 처리 속도가 향상됩니다. &lt;a href=&quot;https://lee1535.tistory.com/101?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Composite 패턴 : Flyweight 패턴을 사용해서 Composite 패턴의 Leaf 역할을 공유시킬 수 있는 경우가 있습니다. &lt;a href=&quot;https://lee1535.tistory.com/99?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Singleton 패턴 : FlyweightFactory를 Singleton으로 구현하는 경우가 있습니다. &lt;a href=&quot;https://lee1535.tistory.com/75?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>PROGRAMMING/디자인패턴</category>
      <category>Design Pattern</category>
      <category>flyweight</category>
      <category>Java</category>
      <category>디자인패턴</category>
      <category>자바</category>
      <category>플라이웨이트</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/106</guid>
      <comments>https://lee1535.tistory.com/106#entry106comment</comments>
      <pubDate>Tue, 31 Dec 2019 14:31:16 +0900</pubDate>
    </item>
    <item>
      <title>[디자인패턴/Design Pattern] Chain of Responsibility 역할 사슬 패턴</title>
      <link>https://lee1535.tistory.com/105</link>
      <description>&lt;p&gt;관련 내용은 &lt;code&gt;[자바 언어로 배우는 디자인 패턴 입문]&lt;/code&gt;,&lt;code&gt;[Head First Design Pattern]&lt;/code&gt;의 내용을 참고해서 정리한 글입니다.&lt;br /&gt;잘못된 부분은 댓글로 피드백 부탁드립니다.&lt;/p&gt;
&lt;h1&gt;1. Chain of Responsibility 패턴이란?&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;요청이 주어질때, 사슬에 속해있는 각 객체는 자기가 받은 요청을 검사하여 직접 처리하거나 사슬에 들어있는 다른 객체에 넘기게 되는 방식. 즉 책임을 넘기는 구조입니다.&lt;/p&gt;
&lt;h1&gt;2. Chain of Responsibility 패턴의 등장인물&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;Handler(처리자)의 역할
&lt;ol&gt;
&lt;li&gt;요구를 처리하는 인터페이스(API)를 결정하는 역할을 합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;ConcreteHandler(구체적인 처리자)의 역할
&lt;ol&gt;
&lt;li&gt;요구를 처리하는 구체적인 역할을 합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Clinet(요구자)의 역할
&lt;ol&gt;
&lt;li&gt;최초의 ConcreteHandler 역할에 요구하는 일을 합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Chain of Responsibility 클래스 다이어 그램&lt;/h5&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcNa0M/btqAPdp2yOt/MkA0GSRFl9Tmyu8YTBrwc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcNa0M/btqAPdp2yOt/MkA0GSRFl9Tmyu8YTBrwc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcNa0M/btqAPdp2yOt/MkA0GSRFl9Tmyu8YTBrwc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcNa0M%2FbtqAPdp2yOt%2FMkA0GSRFl9Tmyu8YTBrwc1%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;3. 예제&lt;/h1&gt;
&lt;hr /&gt;
&lt;h5&gt;3-1. Trouble 클래스&lt;/h5&gt;
&lt;p&gt;무언가 요청을 표현할 클래스입니다.&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;public class Trouble {
    private int number;

    public Trouble(int number) {
        this.number = number;
    }

    public int getNumber() {
        return number;
    }

    @Override
    public String toString() {
        return &quot;Trouble [number=&quot; + number + &quot;]&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;3-2. Support 추상 클래스&lt;/h5&gt;
&lt;p&gt;트러블(요청)을 해결할 사슬을 만들기 위한 추상 클래스입니다. &lt;code&gt;next&lt;/code&gt;라는 필드를 통해서 떠넘기는 곳을 지정하고, 필요하면 트러블(요청)을 떠넘기는 곳을 &lt;code&gt;setNext()&lt;/code&gt; 메소드로 설정합니다.&lt;/p&gt;
&lt;pre class=&quot;gradle&quot;&gt;&lt;code&gt;public abstract class Support {
    private String name;
    private Support next;

    public Support(String name) {
        this.name = name;
    }

    public Support setNext(Support next) {
        this.next = next;
        return next;
    }

    public final void support(Trouble trouble) {
        if (resolve(trouble)) {
            done(trouble);
        } else if (next != null) {
            next.support(trouble);
        } else {
            fail(trouble);
        }
    }

    @Override
    public String toString() {
        return &quot;Support [name=&quot; + name + &quot;]&quot;;
    }

    protected abstract boolean resolve(Trouble trouble);

    protected void done(Trouble trouble) {
        System.out.println(trouble + &quot; is resolved by &quot; + this);
    }

    protected void fail(Trouble trouble) {
        System.out.println(trouble + &quot; cannot be resolved&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;support()&lt;/code&gt; 메소드를 통해서 트러블(요청)에 대한 처리 수순을 정의했습니다. 또한 실제 처리 부분인 &lt;code&gt;resolve()&lt;/code&gt;메소드는 추상 메소드로 선언해 하위 클래스에서 구체적인 구현을 위임합니다.&lt;/p&gt;
&lt;h5&gt;3-3. NoSupport, LimitSupport, OddSupport, SpecialSupport 추상 클래스&lt;/h5&gt;
&lt;p&gt;각각 Support 추상 클래스의 하위 클래스입니다. 필요한 로직을 수행합니다.&lt;/p&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;public class NoSupport extends Support {
    public NoSupport(String name) {
        super(name);
    }

    @Override
    protected boolean resolve(Trouble trouble) {
        return false;
    }
}

public class OddSupport extends Support {

    public OddSupport(String name) {
        super(name);
    }

    @Override
    protected boolean resolve(Trouble trouble) {
        if(trouble.getNumber() % 2 == 1) {
            return true;
        } 
        return false;
    }
}

public class SpecialSupport extends Support {
    private int number;

    public SpecialSupport(String name, int number) {
        super(name);
        this.number = number;
    }

    @Override
    protected boolean resolve(Trouble trouble) {
        if(trouble.getNumber() == number) {
            return true;
        }
        return false;
    }
}

public class LimitSupport extends Support {
    private int limit;

    public LimitSupport(String name, int limit) {
        super(name);
        this.limit = limit;
    }

    @Override
    protected boolean resolve(Trouble trouble) {
        if (trouble.getNumber() &amp;lt; limit) {
            return true;
        }
        return false;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;3-4. Main 클래스&lt;/h5&gt;
&lt;p&gt;Support 클래스를 통해 사슬을 생성하고, 트러블(요청)을 수행하는 매인 클래스입니다.&lt;/p&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;public class main {
    public static void main(String[] args) {
        Support alice = new NoSupport(&quot;Alice&quot;);
        Support bob = new LimitSupport(&quot;Bob&quot;, 100);
        Support charlie = new SpecialSupport(&quot;Charlie&quot;, 429);
        Support diana = new LimitSupport(&quot;Diana&quot;,200);
        Support elmo = new OddSupport(&quot;Elomo&quot;);
        Support fred = new LimitSupport(&quot;Fred&quot;,300);

        alice.setNext(bob).setNext(charlie).setNext(diana).setNext(elmo).setNext(fred);

        for (int i = 0; i &amp;lt; 500; i++) {
            alice.support(new Trouble(i));    
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;실행 결과&lt;/h5&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;Trouble [number=0] is resolved by Support [name=Bob]
Trouble [number=1] is resolved by Support [name=Bob]
Trouble [number=2] is resolved by Support [name=Bob]
....
Trouble [number=498] cannot be resolved
Trouble [number=499] is resolved by Support [name=Elomo]&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;그렇다면 왜 사용할까?&lt;/h5&gt;
&lt;ul&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;/p&gt;
&lt;ul&gt;
&lt;li&gt;실행시에 과정을 살펴보거나 디버깅하기가 힘들 수 있다는 단점이 있습니다.&lt;/li&gt;
&lt;li&gt;요청이 반드시 수행된다는 보장이 없습니다. 사슬의 끝이여도 어느 객체에서도 처리를 못하는 경우 ( 장점이 될 수도 )&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;4. 관련 패턴&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;Composite 패턴 : Handler 역할에 Composite 패턴이 자주 등장합니다. &lt;a href=&quot;https://lee1535.tistory.com/99&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Command 패턴 : Hanlder 역할에 대해서 제공되는 '요구'에는 Command 패턴이 사용되는 경우가 있습니다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>PROGRAMMING/디자인패턴</category>
      <category>Design Pattern</category>
      <category>Java</category>
      <category>디자인패턴</category>
      <category>역할 사슬 패턴</category>
      <category>자바</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/105</guid>
      <comments>https://lee1535.tistory.com/105#entry105comment</comments>
      <pubDate>Tue, 31 Dec 2019 10:46:24 +0900</pubDate>
    </item>
    <item>
      <title>[디자인패턴/Design Pattern] Builder 패턴 / 빌더 패턴</title>
      <link>https://lee1535.tistory.com/104</link>
      <description>&lt;p&gt;관련 내용은 &lt;code&gt;[자바 언어로 배우는 디자인 패턴 입문]&lt;/code&gt;,&lt;code&gt;[Head First Design Pattern]&lt;/code&gt;,&lt;code&gt;[Effective Java 3 개정판]&lt;/code&gt;의 내용을 참고해서 정리한 내용입니다.&lt;br /&gt;잘못된 부분은 댓글로 피드백 부탁드립니다.&lt;/p&gt;
&lt;h1&gt;1. Builder 패턴이란?&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;객체의 생성 단계들을 캡슐화 하여 객체의 생성을 유연하게 해주는 패턴입니다. 즉 객체의 생성과정과 객체의 표현 방법을 분리합니다.&lt;/p&gt;
&lt;h1&gt;2. Builder 패턴의 등장인물&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;Builder(건축자)의 역할
&lt;ol&gt;
&lt;li&gt;인스턴스 생성을 위한 인터페이스(API)를 선언합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;ConcreteBuilder(구체적인 건축자)의 역할
&lt;ol&gt;
&lt;li&gt;Builder 인터페이스를 구현하는 역할을 합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Director(감독자)의 역할
&lt;ol&gt;
&lt;li&gt;Builder 인터페이스(API)를 사용해 인스턴스를 사용합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Productor(제품)의 역할
&lt;ol&gt;
&lt;li&gt;만들어질 제품의 속성과 기능을 가집니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Builder 패턴의 클래스 다이어그램&lt;/h5&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5qpI2/btqAPehLl2e/qzvbFnYMhHV265k04U3gDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5qpI2/btqAPehLl2e/qzvbFnYMhHV265k04U3gDk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5qpI2/btqAPehLl2e/qzvbFnYMhHV265k04U3gDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5qpI2%2FbtqAPehLl2e%2FqzvbFnYMhHV265k04U3gDk%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;3. 예제&lt;/h1&gt;
&lt;hr /&gt;
&lt;h5&gt;3-1. Builder 추상 클래스&lt;/h5&gt;
&lt;p&gt;제품을 필드로 가지며 객체 생성시 필요한 메소드를 선언하는 추상 클래스입니다.&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public abstract class Builder {
    protected House house;

    public void createHouse() {
        house = new House();
    }

    public abstract void buildWalls();

    public abstract void buildDoors();

    public abstract void bouildRoof();

    public abstract void buildWindoes();

    public abstract House getHouse();
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;3-2. House 클래스&lt;/h5&gt;
&lt;p&gt;제품 클래스입니다. 생성될 제품의 속성과 기능을 가집니다.&lt;/p&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;public class House {
    private String roof;
    private String doors;
    private String windows;
    private String walls;

    public void setRoof(String roof) {
        this.roof = roof;
    }

    public void setDoors(String doors) {
        this.doors = doors;
    }

    public void setWindows(String windows) {
        this.windows = windows;
    }

    public void setWalls(String walls) {
        this.walls = walls;
    }

    @Override
    public String toString() {
        return &quot;이집은 [&quot; + roof + &quot; 지붕과, &quot; + walls + &quot; 벽과, &quot; + windows + &quot;창문과 ,&quot; + doors + &quot;문으로로 지어진 집입니다.]&quot;;
    }    
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;3-3. ConcreteHouseBuilder, WoodHouseBuilder 클래스&lt;/h5&gt;
&lt;p&gt;각각 Builder 추상 클래스의 기능을 재정의합니다.&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;public class ConcreteHouseBuilder extends Builder {

    @Override
    public void buildWalls() {
        house.setWalls(&quot;콘트리트&quot;);
    }

    @Override
    public void buildDoors() {
        house.setDoors(&quot;철제&quot;);
    }

    @Override
    public void bouildRoof() {
        house.setRoof(&quot;빨간 &quot;);
    }

    @Override
    public void buildWindoes() {
        house.setWindows(&quot;일반 &quot;);
    }

    @Override
    public House getHouse() {
        return house;
    }
}

public class WoodHouseBuilder extends Builder {

    @Override
    public void buildWalls() {
        house.setWalls(&quot;통나무&quot;);
    }

    ....

    @Override
    public House getHouse() {

        return house;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;3-4. Director 클래스&lt;/h5&gt;
&lt;p&gt;Builder을 속성으로 가지며, Builder 클래스의 메소드를 사용해 객체를 생성하고, 반환해줍니다.&lt;/p&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;public class Director {
    private Builder builder;

    public Director(Builder builder) {
        this.builder = builder;
    }

    public void build() {
        builder.createHouse();
        builder.buildWalls();
        builder.buildWindoes();
        builder.buildDoors();
        builder.bouildRoof();
    }

    public House getHouse() {
        return builder.getHouse();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;3-5. Main 클래스&lt;/h5&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {
        Builder concreteHouseBuilder = new ConcreteHouseBuilder();
        Director director = new Director(concreteHouseBuilder);
        director.build();

        House house1 = director.getHouse();
        System.out.println(house1);

        Builder woodHouseBuilder = new WoodHouseBuilder();
        director = new Director(woodHouseBuilder);
        director.build();

        House house2 = director.getHouse();
        System.out.println(house2);

    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;실행 결과&lt;/h5&gt;
&lt;pre class=&quot;accesslog&quot;&gt;&lt;code&gt;이집은 [빨간 철제 지붕과, 콘트리트 벽과, 일반 창문과 ,철제문으로 지어진 집입니다.]
이집은 [기와장  지붕과, 통나무 벽과, 나무 창문과 ,원목 나무문으로 지어진 집입니다.]&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;그렇다면 왜 사용할까?&lt;/h5&gt;
&lt;p&gt;이렇게 객체의 생성과정과 객체의 표현 방법을 분리하여 사용함으로써 다음과 같은 조합으로 객체 생성이 가능해집니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-style=&quot;style8&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;콘크리트를 사용하는 Builder&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;나무를 사용하는 Builder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;집을 만드는 Director&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;콘크리트 집&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;나무 집&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;학교를 만드를 Director&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;콘크리트 학교&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;나무 학교&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;사실 예제가 억지에 가깝지만.. 대충 이해한 내용을 코드로 작성해봤습니다.&lt;br /&gt;이제 &lt;code&gt;[Effective java]&lt;/code&gt;에서 소개하는 Builder Pattern을 소개하겠습니다.&lt;/p&gt;
&lt;h1&gt;4. Effective Builder 패턴&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;책에는 &lt;code&gt;생성자 인자가 많을 경우 Builder 패턴 적용을 고려하라&lt;/code&gt; 라고 안내합니다. 즉 해당 책에서는 Builder 패턴을 객체 생성을 깔끔하고, 유연하게 할 수 있는 방법을 소개해줍니다.&lt;/p&gt;
&lt;h5&gt;4-1. 점층적 생성자 패턴&lt;/h5&gt;
&lt;pre class=&quot;fortran&quot;&gt;&lt;code&gt;public class Member {
    private final String name ;
    private final Integer age;

    public Member(String name) {
        this(name, null);
    }

    public Member(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위 코드와 같은 클래스에서 새로운 필드인 주소, 이메일, 핸드폰 번호가 추가 되었을 경우 생성자를 어떻게 만들어야 할까? 생각만해도 머리가 아픕니다.. 이름과 이메일만 가지는 생성자, 이름과 핸드폰 번호만 가지는 생성자.......&lt;br /&gt;또한, &lt;code&gt;Member m = new Member(&quot;Lee&quot;,10,2)&lt;/code&gt;와 같이 생성자를 사용할 경우 각각의 인자가 무엇을 의미하는지 직관적으로 파악하기가 힘듭니다.&lt;br /&gt;&amp;nbsp;그래서 등장한 방식이 자바빈 패턴입니다.&lt;/p&gt;
&lt;h5&gt;4-2 JavaBeans Pattern&lt;/h5&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public class Member {
    private String name;
    private Integer age;

    public String getName() {
        return name;
    }

    public Integer getAge() {
        return age;
    }

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

    public void setAge(Integer age) {
        this.age = age;
    }
}

public class Main {
    public static void main(String[] args) {
        Member m = new Member();
        m.setName(&quot;Lee&quot;);
        m.setAge(20);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;해당 패턴을 통해 객체를 생성함으로써 불필요한 생성자가 필요가 없어졌고, 각각 메소드의 인자가 어떤 인자인지 메소드명을 통해서 파악하기 쉬워졌습니다.&lt;br /&gt;그러나 setter을 통해 객체의 값이 변경 가능하기 때문에 immutable 클래스를 만들 수가 없고, 객체의 호출을 1번이 아닌 여러번을 하게 되는 단점이 있습니다&lt;/p&gt;
&lt;h5&gt;4-2 Effective java Builder Pattern&lt;/h5&gt;
&lt;p&gt;마지막으로 대망의 Effective java에서 소개하는 Builder Pattern의 방식입니다.&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;public class Member {

    private final String name;
    private final int age;
    private final String address;

    public static class Builder {
        // 필수 인자
        private final String name;

        private int age = 0;
        private String address = &quot;&quot;;

        public Builder(String name) {
            this.name = name;
        }

        public Builder age(int age) {
            this.age = age;
            return this;
        }

        public Builder address(String address) {
            this.address = address;
            return this;
        }

        public Member build() {
            return new Member(this);
        }
    }

    private Member(Builder builder) {
        name = builder.name;
        age = builder.age;
        address = builder.address;
    }

    @Override
    public String toString() {
        return &quot;Member [name=&quot; + name + &quot;, age=&quot; + age + &quot;, address=&quot; + address + &quot;]&quot;;
    }
}

public class Main {
    public static void main(String[] args) {
        Member member = new Member
                .Builder(&quot;Lee&quot;) // 필수 인자
                .age(20)
                .address(&quot;Korea&quot;)
                .build(); // 객체 생성

        System.out.println(member);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위 코드와 같이 객체를 생성할 수 있는 방식을 제공합니다. 해당 방식을 사용하면 아래와 같은 이점이 있습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;각 인자를 파악하기 쉽다.&lt;/li&gt;
&lt;li&gt;setter 메소드가 없으므로 변경 불가능 클래스 작성 가능&lt;/li&gt;
&lt;li&gt;객체의 일관성이 깨지지 않습니다. 한번만 호출&lt;/li&gt;
&lt;li&gt;build() 메소드를 통해 값이 잘못 되었는지 검증 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;Lombok&lt;/code&gt;이라는 라이브러리의 &lt;a href=&quot;https://lee1535.tistory.com/27?category=816289&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;link&lt;/a&gt; @Builder 도 해당 방식의 빌더를 자동으로 생성해줍니다.&lt;/p&gt;
&lt;h1&gt;5. 관련 패턴&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;Template Method 패턴 : Builder 패턴에서는 Director이 Builder을 제어합니다. 반면 해당 패턴은 사위 클래스가 하위 클래스를 제어합니다. &lt;a href=&quot;https://lee1535.tistory.com/73?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Composite 패턴 : Builder 패턴에 의해 만들어진 생성물은 해당 패턴이 되는 경우가 있습니다. &lt;a href=&quot;https://lee1535.tistory.com/99?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Abstract Factory 패턴 : 동일하게 복잡한 인스턴스 생성을 담당합니다,&lt;/li&gt;
&lt;li&gt;Facade 패턴 : Builder는 인스턴스 생성을 단순한 인터페이스(API)를 제공. 해당 패턴은 내부 모듈을 간단하게 사용하기 위한 인터페이스(API)를 제공합니다. &lt;a href=&quot;https://lee1535.tistory.com/98?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>PROGRAMMING/디자인패턴</category>
      <category>Design Pattern</category>
      <category>Java</category>
      <category>디자인패턴</category>
      <category>빌더패턴</category>
      <category>이펙티브자바</category>
      <category>자바</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/104</guid>
      <comments>https://lee1535.tistory.com/104#entry104comment</comments>
      <pubDate>Mon, 30 Dec 2019 15:46:23 +0900</pubDate>
    </item>
    <item>
      <title>[디자인패턴/Design Pattern] Bridge Pattern / 브리지 패턴</title>
      <link>https://lee1535.tistory.com/102</link>
      <description>&lt;p&gt;관련 내용은 &lt;code&gt;[자바 언어로 배우는 디자인 패턴 입문]&lt;/code&gt;,&lt;code&gt;[Head First Design Pattern]&lt;/code&gt;의 내용을 참고해서 정리한 내용입니다. 잘못된 부분은 댓글로 피드백 부탁드립니다.&lt;/p&gt;
&lt;h1&gt;1. Bridge 패턴이란?&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;'기능 클래스 계층'과 '구현 클래스 계층'을 연결해주는 패턴입니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;기능 클래스 계층이란 ?
&lt;ul&gt;
&lt;li&gt;A라는 상위 클래스를 상속받는 B라는 하위 클래스에서 새로운 기능을 추가하는 계층을 말합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;구현 클래스 계층이란 ?
&lt;ul&gt;
&lt;li&gt;A라는 인터페이스(API)를 구현한 B라는 객체가 존재할 때 구현 클래스 계층이라고 말합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;2. Bridge 패턴의 등장인물&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;Abstraction(추상화)의 역할
&lt;ol&gt;
&lt;li&gt;기능 클래스 계층의 상위 클래스입니다. 기본 기능만 정의되어 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;RefinedAbstaction(개선된 추상화)의 역할
&lt;ol&gt;
&lt;li&gt;기능 클래스 계층의 하위 클래스입니다. 기능을 추가한 역할입니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Implementor(구현자)의 역할
&lt;ol&gt;
&lt;li&gt;구현 클래스 계층의 상의 클래스입니다. 인터페이스(API)를 규정합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Concrete Implementor(구체적인 구현자)의 역할
&lt;ol&gt;
&lt;li&gt;구현 클래스 계층의 하위 클래스입니다. 인터페이스를(API)를 정의합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Bridge 패턴의 클래스 다이어그램&lt;/h5&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;250&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOZ3QR/btqADHFL8Tr/2DqEKEhJFchCCy163DjN0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOZ3QR/btqADHFL8Tr/2DqEKEhJFchCCy163DjN0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOZ3QR/btqADHFL8Tr/2DqEKEhJFchCCy163DjN0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOZ3QR%2FbtqADHFL8Tr%2F2DqEKEhJFchCCy163DjN0K%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;250&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;3. 예제&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;예제를 통해 내용을 구체화하겠습니다.&lt;/p&gt;
&lt;h5&gt;3-1. 예제 클래스 다이어그램&lt;/h5&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mvDsO/btqALu7XyUG/y4e2yZERTVdeVVjkoNtQzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mvDsO/btqALu7XyUG/y4e2yZERTVdeVVjkoNtQzk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mvDsO/btqALu7XyUG/y4e2yZERTVdeVVjkoNtQzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmvDsO%2FbtqALu7XyUG%2Fy4e2yZERTVdeVVjkoNtQzk%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h5&gt;3-2. Display 클래스&lt;/h5&gt;
&lt;p&gt;기능 클래스 계층의 상위 클래스로써 , 구현 클래스 계층의 상위클래스를 인스턴스로 가지며, 공통된 기능을 정의합니다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class Display  {
    private DisplayImpl impl;

    public Display(DisplayImpl impl) {
        this.impl = impl;
    }

    public void open() {
        impl.rawOpen();
    }

    public void print() {
        impl.rawPrint();
    }

    public void close() {
        impl.rawClose();
    }

    public final void display() {
        open();
        print();
        close();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;3-3. CountDisplay 클래스&lt;/h5&gt;
&lt;p&gt;기능 클래스 계층의 하위 클래스로써 기능을 확장하는 역할을 합니다. 말 그대로 구현은 관계없이 기능만 추가하는 역할을 합니다.&lt;/p&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;public class CountDisplay extends Display {

    public CountDisplay(DisplayImpl impl) {
        super(impl);
    }

    public void multiDisplay(int times) {
        open();
        for(int i = 0; i &amp;lt; times; i ++) {
            print();
        }
        close();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;3-4. DisplayImpl 인터페이스&lt;/h5&gt;
&lt;p&gt;구현 클래스 계층의 최상위에 해당하며 구현할 메소드를 정의한 인터페이스(API)입니다.&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public interface DisplayImpl {
    public void rawOpen();
    public void rawPrint();
    public void rawClose();
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;3-5. StringDisplayImpl 클래스&lt;/h5&gt;
&lt;p&gt;구현 클래스의 하위에 해당하며, 상위 인터페이스 또는 클래스의 메소드를 규현합니다.&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public class StringDisplayImpl implements DisplayImpl {

    private String string;
    private int width;

    public StringDisplayImpl(String string) {
        this.string = string;
        this.width = string.getBytes().length;
    }

    @Override
    public void rawClose() {
        printLine();
    }

    @Override
    public void rawOpen() {
        printLine();
    }

    @Override
    public void rawPrint() {
        System.out.println(&quot;|&quot; + string + &quot;|&quot;);
    }

    private void printLine() {
        System.out.print(&quot;+&quot;);
        for (int i = 0; i &amp;lt; width; i++) {
            System.out.print(&quot;-&quot;);
        }
        System.out.println(&quot;+&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;3-6. Main 클래스&lt;/h5&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {
        Display d1 = new Display(new StringDisplayImpl(&quot;Hello, Lee&quot;));
        Display d2 = new CountDisplay(new StringDisplayImpl(&quot;Hello, world&quot;));

        CountDisplay d3 = new CountDisplay(new StringDisplayImpl(&quot;Hello, Universe&quot;));

        d1.display();
        d2.display();
        d3.display();
        d3.multiDisplay(5);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;실행 결과&lt;/h5&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;+----------+
|Hello, Lee|
+----------+
+------------+
|Hello, world|
+------------+
+---------------+
|Hello, Universe|
+---------------+
+---------------+
|Hello, Universe|
|Hello, Universe|
|Hello, Universe|
|Hello, Universe|
|Hello, Universe|
+---------------+&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;그렇다면 왜 사용할까?&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;두 계층을 분리함으로써 확장이 편리해집니다. 서로 변경이 되어도 클라이은트 쪽에는 영향이 없습니다.&lt;/li&gt;
&lt;li&gt;여러 플랫폼에서 사용해야 할 그래픽스 및 윈도우처리 시스템에서 유용하게 쓰입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;단 단점으로 패턴을 매우 응집력있는 클래스에 적용하면 코드가 더 복잡해질 수 있습니다.&lt;/p&gt;
&lt;h1&gt;4. 관련 패턴&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;Template Method 패턴 : 해당 패턴에서 구현의 클래스 계층을 이용합니다. &lt;a href=&quot;https://lee1535.tistory.com/73?category=819409&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Abstract Factory 패턴 : Bridge 패턴의 ConcreteImplementor 역할을 해당 패턴이 이용되는 경우가 있습니다. link&lt;/li&gt;
&lt;li&gt;Adapter 패턴 : 해당 패턴은 Bridge와 비슷하지만, 인터페이스(API)가 다른 클래스를 결합시키는 패턴입니다. &lt;a href=&quot;https://lee1535.tistory.com/72?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;5. 비교하기&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;Adapter 패턴 : 서로 다른 인터페이스(API)를 연결해줍니다. &lt;a href=&quot;https://lee1535.tistory.com/72?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Bridge 패턴 : 구현 계층과 기능(추상) 계층을 연결해줍니다. link&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>PROGRAMMING/디자인패턴</category>
      <category>Bridge</category>
      <category>Design Pattern</category>
      <category>Java</category>
      <category>디자인패턴</category>
      <category>브리지</category>
      <category>브릿지</category>
      <category>자바</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/102</guid>
      <comments>https://lee1535.tistory.com/102#entry102comment</comments>
      <pubDate>Thu, 26 Dec 2019 07:52:12 +0900</pubDate>
    </item>
    <item>
      <title>[디자인패턴/Design Pattern] Proxy Pattern / 프록시 패턴</title>
      <link>https://lee1535.tistory.com/101</link>
      <description>&lt;p&gt;관련 내용은 &lt;code&gt;[자바 언어로 배우는 디자인 패턴 입문]&lt;/code&gt;,&lt;code&gt;[Head First Design Pattern]&lt;/code&gt;의 내용을 참고해서 정리한 내용입니다.&lt;br /&gt;잘못된 부분은 댓글로 피드백 부탁드립니다.&lt;/p&gt;
&lt;h1&gt;1. Proxy 패턴이란?&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;어떤 객체에 대한 접근을 제어하기 위한 용도로 대리인이나 대변인에 해당하는 객체를 제공하는 패턴&lt;/p&gt;
&lt;h1&gt;2. Proxy 패턴의 등장인물&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;Subject(주체)의 역할
&lt;ol&gt;
&lt;li&gt;Proxy 역할과 RealSubject 역할을 동일시하기 위한 인터페이스(API)를 결정합니다. 이 덕분에 클라이언트는 둘의 역할 차이를 몰라도 됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Proxy(대리인)의 역할
&lt;ol&gt;
&lt;li&gt;Client의 요구를 할 수 있을 만큼 처리하고, 필요할 경우 RealSubject에게 처리를 맡깁니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;RealSubject(실제의 주체)의 역할
&lt;ol&gt;
&lt;li&gt;Proxy에서 요청이 들어왔을때 요청에 대한 응답을 합니다.&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lvSOZ/btqAz2P95pL/XOqULiRJKjnyRzaKRmnvZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lvSOZ/btqAz2P95pL/XOqULiRJKjnyRzaKRmnvZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lvSOZ/btqAz2P95pL/XOqULiRJKjnyRzaKRmnvZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlvSOZ%2FbtqAz2P95pL%2FXOqULiRJKjnyRzaKRmnvZK%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;3. 예제&lt;/h1&gt;
&lt;hr /&gt;
&lt;h5&gt;3-1. 예제 클래스 다이어그램&lt;/h5&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dxB3DO/btqAxNmvltf/jVvf0yIojftyPIkOMrqMz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dxB3DO/btqAxNmvltf/jVvf0yIojftyPIkOMrqMz1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dxB3DO/btqAxNmvltf/jVvf0yIojftyPIkOMrqMz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdxB3DO%2FbtqAxNmvltf%2FjVvf0yIojftyPIkOMrqMz1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h5&gt;3-2. PritableSubject 인터페이스&lt;/h5&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public interface PrintableSubject {
    void setPrinterName(String name);
    String getPrinterName();
    void print(String string);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;역할 설명에서 언급했던것처럼 &lt;code&gt;Proxy&lt;/code&gt;와 &lt;code&gt;RealSubject&lt;/code&gt;역할의 인터페이스(API)를 정의해줍니다.&lt;/p&gt;
&lt;h5&gt;3-3. PrinterRealSubject 클래스&lt;/h5&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class PrinterRealSubject implements PrintableSubject {
    private String name;

    public PrinterRealSubject(String name) {
        this.name = name;
        heavyJob(&quot;PrinterRealSubject[&quot; + name + &quot;] 인스턴스 생성중..&quot;);
    }

    private void heavyJob(String string) {
        // TODO Auto-generated method stub
        System.out.println(string);
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println(&quot;생성 완료...&quot;);
    }

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

    public String getPrinterName() {
        return name;
    }

    public void print(String string) {
        System.out.println(string);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;인터페이스를 구현하기 위해 &lt;code&gt;setPrinterName()&lt;/code&gt;, &lt;code&gt;getPrinterName()&lt;/code&gt;, &lt;code&gt;print()&lt;/code&gt; 를 재정의해주고, 객체의 인스턴스 생성의 비용을 무겁게 하기 위해 &lt;code&gt;heavyJob()&lt;/code&gt; 이란 메소드를 통해 3초를 지연시킵니다.&lt;/p&gt;
&lt;h5&gt;3-4. PrinterProxy 클래스&lt;/h5&gt;
&lt;pre class=&quot;d&quot;&gt;&lt;code&gt;public class PrinterProxy implements PrintableSubject {

    private String name;
    private PrinterRealSubject real;

    public PrinterProxy(String name) {
        this.name = name;
    }

    @Override
    public synchronized void setPrinterName(String name) {
        if (real != null) {
            real.setPrinterName(name);
        }
        this.name = name;

    }

    @Override
    public String getPrinterName() {
        return name;
    }

    @Override
    public synchronized void print(String string) {
        realize();
        real.print(string);
    }

    private synchronized void realize() {
        if (real == null) {
            real = new PrinterRealSubject(name);
        }
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;대리인으로써 처리가 가능한 부분은 객체가 맡아서 처리를 해줍니다. ex ) &lt;code&gt;getPrinterName()&lt;/code&gt;&lt;br /&gt;그리고 실제 RealJubject가 필요한 시점에 해당 객체에게 요청을 위임합니다.&lt;/p&gt;
&lt;h5&gt;3-5. Main 클래스&lt;/h5&gt;
&lt;hr /&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {
        PrintableSubject p = new PrinterProxy(&quot;Simple&quot;);

        // 프록시가 실행 됨
        System.out.println(p.getPrinterName());

        // realSubject가 실행 
        p.print(&quot;프린트 요청&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;실행 결과&lt;/h5&gt;
&lt;pre class=&quot;prolog&quot;&gt;&lt;code&gt;Simple
PrinterRealSubject[Simple] 인스턴스 생성중..
생성 완료...
프린트 요청&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;왜 사용할까 ?&lt;/h5&gt;
&lt;p&gt;시작하기에 앞서 Proxy Pattern의 정의를 아래와 같이 설명했습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;어떤 객체에 대한 접근을 제어하기 위한 용도로 대리인이나 대변인에 해당하는 객체를 제공하는 패턴&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;그런데 예제만 보고는 왜? 라는 생각이 드실 수 있습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;로직에 많은 비용이 필요하면 처음부터 &lt;code&gt;Printer&lt;/code&gt; 클래스에서 분리해서 사용하면 되는거 아니야?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;라는 의문에는 디자인의 원칙에 의해서 객체들의 역할을 분리해서 개별적으로 수정이 가능하게 하기 위함입니다. 즉 유지보수가 용이하고 클라이언트 입장에서는 지연이 필요할경우 &lt;code&gt;Proxy&lt;/code&gt;객체를 사용 필요없이 사용할 경우 &lt;code&gt;PrinterRealSubject&lt;/code&gt;를 사용할 수 있습니다.&lt;br /&gt;&lt;br /&gt;마지막으로 &lt;code&gt;Proxy Pattern&lt;/code&gt;의 정의를 비용이 많이 필요한 경우 역할을 나눠서 지연시킬 수 있는 패턴이라고 정의하지 않고, 본문처럼 포괄적으로 설명한 이유는 무엇일까? &lt;code&gt;Proxy Pattern&lt;/code&gt;은 여러 종류 존재하기 때문에 포괄적인 의미만 전달했습니다.&lt;/p&gt;
&lt;h5&gt;Proxy Pattern의 종류&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;Virtual Proxy(가상 프록시) : 예제에 해당하는 프록시이며, 인스턴스가 필요한 시점에 생성, 초기화를 실행합니다.&lt;/li&gt;
&lt;li&gt;Remote Proxy(원격 프록시 ) : 네트워크가 연결된 상황에서 원격으로 로컬 객체를 원격 객체처럼 사용할 수 있게 해줍니다. &lt;b&gt;Java RMI&lt;/b&gt; 등을 사용&lt;/li&gt;
&lt;li&gt;Access Proxy(보호 프록시) : RealSubject 기능에 대해서 엑세스 제한을 설정합니다.&lt;/li&gt;
&lt;li&gt;Caching Proxy(캐싱 프록시) : 지연이 많이 드는 작업을 임시로 저장, 여러 클라이언트에게 공유합니다.&lt;/li&gt;
&lt;li&gt;기타 : 방화벽 프록시, 스마트 레퍼런스 프록시, 동기화 프록시, 복잡도 숨김 프록시, 지연 복사 프록시 등.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;4. 관련 패턴&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Adapter&lt;/code&gt; 패턴 : 연결 해준다는 관점은 같지만 Adapter는 서로 다른 인터페이스를 연결해줍니다. &lt;a href=&quot;https://lee1535.tistory.com/72?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Decorator&lt;/code&gt; 패턴 : 구현은 비슷하지만 목적이 다릅니다. 새로운 기능을 추가할 때 사용합니다. &lt;a href=&quot;https://lee1535.tistory.com/95?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;5. 비교하기&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;객체를 감싸는 패턴이 많은데 구분을 하기 위해 차이점을 정리했습니다,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Decorator&lt;/code&gt; 패턴 : 다른 객체를 감싸서 새로운 행동을 추가해줍니다. &lt;b&gt;기능 확장 &lt;a href=&quot;https://lee1535.tistory.com/95?category=819409&quot;&gt;link&lt;/a&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Facade&lt;/code&gt; 패턴 : 여러 객체를 감싸서 인터페이스를 단순화시킵니다. &lt;b&gt;기능 단순화&amp;nbsp;&lt;/b&gt;&lt;a href=&quot;https://lee1535.tistory.com/98?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Adapter&lt;/code&gt; 패턴 : 다른 객체를 감싸서 다른 인터페이스를 제공합니다. &lt;b&gt;호환성 &lt;/b&gt;&lt;a href=&quot;https://lee1535.tistory.com/72?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Proxy&lt;/code&gt; 패턴 : 다른 객체를 감싸서 접근을 제어합니다. &lt;b&gt;접근제어 &lt;/b&gt;&lt;a href=&quot;https://lee1535.tistory.com/101&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>PROGRAMMING/디자인패턴</category>
      <category>Java</category>
      <category>대리자</category>
      <category>디자인패턴</category>
      <category>자바</category>
      <category>접근제어</category>
      <category>프록시패턴</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/101</guid>
      <comments>https://lee1535.tistory.com/101#entry101comment</comments>
      <pubDate>Thu, 19 Dec 2019 14:37:59 +0900</pubDate>
    </item>
    <item>
      <title>[디자인패턴/Design Pattern] State Pattern / 스태이트 패턴</title>
      <link>https://lee1535.tistory.com/100</link>
      <description>&lt;p&gt;관련 내용은 &lt;code&gt;[자바 언어로 배우는 디자인 패턴 입문]&lt;/code&gt;,&lt;code&gt;[Head First Design Pattern]&lt;/code&gt;의 내용을 참고해서 정리한 내용입니다. 잘못된 부분은 댓글로 피드백 부탁드립니다.&lt;/p&gt;
&lt;h1&gt;1. State 패턴이란?&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;객체의 내부 &lt;b&gt;상태&lt;/b&gt;가 바뀜에 따라서 객체의 &lt;b&gt;행동&lt;/b&gt;을 변경할 수 있도록 해주는 패턴&lt;/p&gt;
&lt;h1&gt;2. State 패턴의 등장인물&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;State(상태)의 역할
&lt;ol&gt;
&lt;li&gt;상태가 변할 때마다 다른 동작을 하는 인터페이스(API)를 결정합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;ConcreteState(구체적인 상태)의 역할
&lt;ol&gt;
&lt;li&gt;State의 인터페이스(API)를 구체적으로 구현합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Context(상황)의 역할
&lt;ol&gt;
&lt;li&gt;현재의 상태를 나타내는 ConcreteState 역할을 가집니다. 또한 State 패턴의 이용자에게 필요한 인터페이스(API)를 결정합니다.
&lt;h5&gt;State 패턴의 클래스 다이어그램&lt;/h5&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baWw81/btqAyGSZai1/7kcLwaP8KzVEetz1bVZhr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baWw81/btqAyGSZai1/7kcLwaP8KzVEetz1bVZhr0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baWw81/btqAyGSZai1/7kcLwaP8KzVEetz1bVZhr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaWw81%2FbtqAyGSZai1%2F7kcLwaP8KzVEetz1bVZhr0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;3. 예제&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;어렸을적 동전을 넣고 레버를 돌리면 장난감 캡슐을 주던 기계를 구현한다고 가정해봅니다.&lt;br /&gt;이때, 해당 기계가 가지는 &lt;b&gt;상태&lt;/b&gt;를 대충 정리해보면&lt;/p&gt;
&lt;ol&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;/p&gt;
&lt;h5&gt;3-1. 예제 GumballMachin 클래스&lt;/h5&gt;
&lt;pre class=&quot;pf&quot;&gt;&lt;code&gt;public class GumballMachin {
    enum State {
        HAS_QUARTER, NO_QUARTER, SOLD_OUT, SOLD
    }

    private State state = State.NO_QUARTER;

    // 동전 넣기
    public void insertQuarter() {
        if(state == State.HAS_QUARTER) {
            System.out.println(&quot;이미 동전이 있습니다.&quot;);
        } else if ( state == State.NO_QUARTER) {
            state = State.HAS_QUARTER;
            System.out.println(&quot;동전을 추가하셨습니다.&quot;);
        } else if ( state == State.SOLD_OUT) {
            System.out.println(&quot;캡슐이 매진되었습니다.&quot;);
        } else if ( state == State.SOLD) {
            System.out.println(&quot;캡슐이 나오고 있습니다. 잠시만 기다려주세요.&quot;);
        }
    }

    // 동전 반환하기
    public void ejectQuarter() {
        if(state == State.HAS_QUARTER) {
            System.out.println(&quot;동전이 반환됩니다.&quot;);
            state = State.NO_QUARTER;
        } else if ( state == State.NO_QUARTER) {
            System.out.println(&quot;동전을 추가해주세요.&quot;);
        } else if ( state == State.SOLD_OUT) {
            System.out.println(&quot;동전을 넣지 않으셨습니다.&quot;);
        } else if ( state == State.SOLD) {
            System.out.println(&quot;이미 캡슐을 뽑으셨습니다.&quot;);
        }
    }
    // 손잡이 돌리기
    // 캡슐 꺼내기
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같이 코드를 작성했다고 했을 경우, 행동이 생략된 손잡이 돌리기, 캡슐 꺼내기 외 여러가지가 더 있는 상황이라고 가정해봅니다.&lt;br /&gt;이때 전혀 새로운 &lt;b&gt;상태&lt;/b&gt;가 추가 된다면? 새로운 이프문을 추가하고... 검증하고... 생각만해도 머리가 아픕니다.&lt;br /&gt;이럴경우 사용하는 패턴이 &lt;code&gt;State&lt;/code&gt; 패턴입니다.&lt;/p&gt;
&lt;h1&gt;4. 해결방법&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;해결방법은 상태라는 인터페이스를 구현하고 각각의 상태에서 행동을 정의하는 방식으로 설계를 합니다.&lt;/p&gt;
&lt;h5&gt;4-1. 클래스 다이어그램&lt;/h5&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UIzcC/btqAyF7DS1W/S1j0Fz1wl5a8maLfHGtKg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UIzcC/btqAyF7DS1W/S1j0Fz1wl5a8maLfHGtKg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UIzcC/btqAyF7DS1W/S1j0Fz1wl5a8maLfHGtKg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUIzcC%2FbtqAyF7DS1W%2FS1j0Fz1wl5a8maLfHGtKg1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h5&gt;4-2. GumballMachine 클래스&lt;/h5&gt;
&lt;pre class=&quot;axapta&quot;&gt;&lt;code&gt;public class GumballMachin {

    State soldState;
    State soldOutState;
    State hasQuarterState;
    State noQuarterState;

    State state = soldOutState;
    int count = 0;

    public GumballMachin(int count) {
        this.soldState = new SoldState(this);
        this.soldOutState = new SoldOutState(this);
        this.hasQuarterState = new HasQuarterstate(this);
        this.noQuarterState = new NoQuarterState(this);
        this.count = count;
        if(count &amp;gt; 0) {
            state = noQuarterState;
        }
    }

    public void insertQuarter() {
        state.insertQuarter();
    }

    // 기타 필요 메소드
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같이 객체들을 구성으로 가지며, 생성자를 통해 초기화를 합니다. 이때 본인을 매개변수로 넘겨서 해당 &lt;code&gt;State&lt;/code&gt; 클래스에서 참조할 수 있도록 합니다.&lt;/p&gt;
&lt;h5&gt;4-2. State 인터페이스&lt;/h5&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public interface State {
    public void insertQuarter();
    public void ejectQuarter();
    public void turnCrank();
    public void dispense();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;공통된 행동을 정의합니다.&lt;/p&gt;
&lt;h5&gt;4-3. NoQuarterState 클래스&lt;/h5&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;public class NoQuarterState implements State {
    GumballMachin gumballMachine;

    public NoQuarterState(GumballMachin gumballMachine) {
        this.gumballMachine = gumballMachine;
    }

    @Override
    public void dispense() {
        System.out.println(&quot;동전을 넣어주세요.&quot;);
    }

    @Override
    public void ejectQuarter() {
        System.out.println(&quot;동전을 넣어주세요.&quot;);
    }

    @Override
    public void insertQuarter() {
        System.out.println(&quot;동전을 넣으셨습니다.&quot;);

    }

    public void turnCrank() {
        System.out.println(&quot;동전을 넣어주세요.&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;해당 클래스와 같이 각각의 &lt;b&gt;상태&lt;/b&gt;에 따라 &lt;b&gt;행동&lt;/b&gt;을 정의해줍니다.&lt;br /&gt;다른 &lt;code&gt;HasQuarterstate&lt;/code&gt;, &lt;code&gt;SoldOutState&lt;/code&gt;, &lt;code&gt;SoldState&lt;/code&gt; 도 알맞게 정의해줍니다.&lt;/p&gt;
&lt;h5&gt;4-4. Main 클래스&lt;/h5&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {

        GumballMachin gumballMachin = new GumballMachin(5);
        // 동전을 넣고 래버 당기기
        gumballMachin.insertQuarter();
        gumballMachin.turnCrank();

        // 동전을 넣고 동전 반환 받기
        gumballMachin.insertQuarter();
        gumballMachin.ejectQuarter();

        // 필요한 로직 작성...
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;왜 사용할까?&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;클라이언트가 직접 상태를 조작하지 않아도, 객체의 상태를 각 ConcreteState 클래스들이 컨트롤 해주기 때문에 별도의 상태 조작 없이 객체를 사용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;5. 관련 패턴&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Singleton&lt;/code&gt; 패턴 : ConcreteState 역할은 Singleton 패턴으로 구현되는 경우가 있습니다. &lt;a href=&quot;https://lee1535.tistory.com/75?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Flyweight&lt;/code&gt; 패턴 : 상태를 표시하는 클래스는 인스턴스를 갖지 않습니다. 따라서 해당 패턴을 사용해서 ConcreteState 역할을 복수의 Context 역할에서 공유할 수 있는 경우가 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;6. 비교하기&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;얼핏 보면 클레스 다이어그램이 &lt;code&gt;Strategy&lt;/code&gt; 패턴과 차이가 없어 보입니다. 하지만 이 두 패턴은 &lt;b&gt;용도&lt;/b&gt;에 있어서 차이가 있습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Strategy&lt;/code&gt; 패턴 : 클라이언트가 어떤 전략을 사용할지 지정해줘야 합니다. 즉 사용자가 쉽게 알고리즘 전략을 바꿀 수 있도록 유연성 제공 &lt;a href=&quot;https://lee1535.tistory.com/93?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;State&lt;/code&gt; 패턴 : 상태 객체의 일련의 행동이 캡슐화 되고, 그 객체의 내부 상태에 따라 현재 상태를 나타내는 객체가 바뀌게 되고, 자연스럽게 행동도 변경됩니다. 즉 클라이언트는 객체의 상태에 대해서 아무것도 몰라도 됩니다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>PROGRAMMING/디자인패턴</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/100</guid>
      <comments>https://lee1535.tistory.com/100#entry100comment</comments>
      <pubDate>Tue, 17 Dec 2019 16:56:37 +0900</pubDate>
    </item>
    <item>
      <title>[디자인패턴/Design Pattern] Composite Pattern / 컴포지트 패턴</title>
      <link>https://lee1535.tistory.com/99</link>
      <description>&lt;p&gt;관련 내용은 &lt;code&gt;[자바 언어로 배우는 디자인 패턴 입문]&lt;/code&gt;,&lt;code&gt;[Head First Design Pattern]&lt;/code&gt;의 내용을 참고해서 정리한 내용입니다. 잘못된 부분은 댓글로 피드백 부탁드립니다.&lt;/p&gt;
&lt;h1&gt;1. Composite 패턴이란?&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;개별 객체와 복합 객체를 똑같은 방법으로 취급하는 것, 해당 패턴을 사용하면 객체들을 트리 구조로 구성하여 부분과 전체를 나타내는 계층 구조로 만들 수 있습니다.&lt;/p&gt;
&lt;h1&gt;2. Composite 패턴의 등장인물&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;Leaf(나뭇잎)의 역할
&lt;ol&gt;
&lt;li&gt;'단일객체'을 표시하는 역할을 수행하며, 내부에는 다른 것을 넣을 수 없습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Composite(복합체)의 역할
&lt;ol&gt;
&lt;li&gt;'복합객체'를 나타내는 역할을 하며, Leaf나 Composite 역할을 넣을 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Component의 역할
&lt;ol&gt;
&lt;li&gt;Leaf, Composite의 역할을 동일시하는 역할이며, 둘의 상위 클래스입니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Composite 패턴의 클래스 다이어그램&lt;/h5&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b57H6R/btqAvkcRvvT/BLl3T83PZJWK69lDU56UdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b57H6R/btqAvkcRvvT/BLl3T83PZJWK69lDU56UdK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b57H6R/btqAvkcRvvT/BLl3T83PZJWK69lDU56UdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb57H6R%2FbtqAvkcRvvT%2FBLl3T83PZJWK69lDU56UdK%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;3. 예제&lt;/h1&gt;
&lt;hr /&gt;
&lt;h5&gt;3-1. MenuComponent 클래스&lt;/h5&gt;
&lt;p&gt;우선 &lt;code&gt;Component&lt;/code&gt;역할인 &lt;code&gt;MenuComponent&lt;/code&gt; 클래스입니다.&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public abstract class MenuComponent {

    public void add(MenuComponent menuComponent) {
        throw new UnsupportedOperationException();
    }

    // 기타 필요한 메소드 정의

    public void print() {
        throw new UnsupportedOperationException();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;디자인의 원칙에 의해서 인터페이스로 선언하지 않고 추상 클래스로 선언한 이유는&lt;br /&gt;&lt;code&gt;Leaf&lt;/code&gt;, &lt;code&gt;Composite&lt;/code&gt;는 역할이 달라서 각 역할에 맞는 기본 메소드를 구현하기 불가능 하기 때문에 예외처리 라는 기본 구현을 제공하기 위해서 추상 클래스를 사용하였습니다.&lt;/p&gt;
&lt;h5&gt;3-2. MenuItem 클래스&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;Leaf&lt;/code&gt; 역할입니다.&lt;/p&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;public class MenuItem extends MenuComponent {
    private String name;
    private String description;
    double price;

    // 생성자, 게터 생략

    public void print() {
        System.out.println(&quot; - &quot; + getName() + &quot; : &quot; + getPrice());
        System.out.println(&quot;    -- &quot; + getDescription());
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;단일 객체로써 필요한 동작을 하면 역할은 끝입니다.&lt;/p&gt;
&lt;h5&gt;3-3. Menu 클래스&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;Composite&lt;/code&gt; 역할입니다.&lt;/p&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;public class Menu extends MenuComponent {
    ArrayList menuComponents = new ArrayList();
    String name;
    String description;

    // 생성자, 게터 생략

    public void print() {
        System.out.println(getName() + &quot;, &quot; + getDescription());
        System.out.println(&quot;-----------------------------------------&quot;);
        Iterator iterator = menuComponents.iterator();
        while(iterator.hasNext()) {
            MenuComponent menuComponent = 
                    (MenuComponent) iterator.next();
            menuComponent.print();
        }
        System.out.println();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Composite&lt;/code&gt; 요소는 &lt;code&gt;Compoent&lt;/code&gt; 요소를 자식으로 가집니다. 그래서 자식들을 관리하기 위한 &lt;code&gt;print()&lt;/code&gt; 메소드를 재정의 합니다.&lt;/p&gt;
&lt;h5&gt;3-4. Main 클래스&lt;/h5&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {
        MenuComponent pancakeHouseMenu = new Menu (&quot;팬케이크 하우스 메뉴&quot;, &quot;런치 메뉴&quot;);

        MenuComponent cafeMenu = new Menu (&quot;카페메뉴&quot;, &quot;브런치 메뉴&quot;);

        MenuComponent dessertMenu = new Menu (&quot;디저트 메뉴&quot;, &quot;디저트를 즐겨 보세요!&quot;);

        MenuComponent allMenus = new Menu(&quot;전체 메뉴&quot; , &quot; 전체 메뉴&quot;);

        allMenus.add(pancakeHouseMenu);
        allMenus.add(cafeMenu);
        allMenus.add(dessertMenu);

        pancakeHouseMenu.add(new MenuItem(&quot;기본 팬케이크&quot;, &quot;고소한 기본 팬 케이크&quot;, 4400));
        pancakeHouseMenu.add(new MenuItem(&quot;블루베리 팬케이크&quot;, &quot;달콤한 블루베리 시럽이 추가된 팬 케이크&quot;, 6400));

        // 기타 메뉴 추가 생략

        allMenus.print();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;전체 트리의 맨 위구조를 가질 &lt;b&gt;allEmnus&lt;/b&gt; 에 &lt;code&gt;Composite&lt;/code&gt;역할을 하는 &lt;b&gt;{ pancakeHouseMenu&lt;/b&gt;, &lt;b&gt;cafeMenu&lt;/b&gt;, &lt;b&gt;dessertMenu }&lt;/b&gt;를 담아주고 각각의 집합체에 &lt;code&gt;Leaf&lt;/code&gt;역을 하는 &lt;b&gt;MenuItem&lt;/b&gt;을 추가해줍니다.&lt;/p&gt;
&lt;h5&gt;실행 결과&lt;/h5&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;전체 메뉴,  전체 메뉴
-----------------------------------------
팬케이크 하우스 메뉴, 런치 메뉴
-----------------------------------------
 - 기본 팬케이크 : 4400.0
    -- 고소한 기본 팬 케이크
 - 블루베리 팬케이크 : 6400.0
    -- 달콤한 블루베리 시럽이 추가된 팬 케이크

카페메뉴, 브런치 메뉴
-----------------------------------------
 - 치즈 케이크 : 23000.0
    -- 이달의 인기 치즈 케이크입니다.
 - 초코 쿠키 : 2000.0
    -- 바삭한 초코 쿠키입니다.

디저트 메뉴, 디저트를 즐겨 보세요!
-----------------------------------------
 - 팥빙수 : 4500.0
    -- 여름철 더위를 책임질 오리지널 팥빙수입니다.
 - 우유 : 1500.0
    -- 고소한 소화가 잘되는 우유입니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boPhtJ/btqAwJiKo5L/kUvcVfLa3ImM5hSkjD8FoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boPhtJ/btqAwJiKo5L/kUvcVfLa3ImM5hSkjD8FoK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boPhtJ/btqAwJiKo5L/kUvcVfLa3ImM5hSkjD8FoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboPhtJ%2FbtqAwJiKo5L%2FkUvcVfLa3ImM5hSkjD8FoK%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;전체 트리 구조의 간략한 모양입니다.&lt;/p&gt;
&lt;h5&gt;3-5. 왜 사용할까?&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;위 트리구조 예시에서 처럼 복합 객체와 단일 객체의 &lt;b&gt;처리 방법이 다르지 않을 경우&lt;/b&gt;, 전체 - 부분 관계로 정의할 수 있다.&lt;br /&gt;즉 &lt;b&gt;트리 구조로&lt;/b&gt; 표현하고 싶은 경우 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;4. 관련 패턴&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Command&lt;/code&gt; 패턴 : '매크로 커맨드'를 만들 때 Composite 패턴이 사용됩니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Visitor&lt;/code&gt; 패턴 : Composite를 순환하면서 처리하는데 사용합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Decorator&lt;/code&gt; 패턴 : 장식과 내용물을 동일시합니다. 동일시 한다는 공통점이 있습니다. &lt;a href=&quot;https://lee1535.tistory.com/95?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>PROGRAMMING/디자인패턴</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/99</guid>
      <comments>https://lee1535.tistory.com/99#entry99comment</comments>
      <pubDate>Tue, 17 Dec 2019 15:06:22 +0900</pubDate>
    </item>
    <item>
      <title>[디자인패턴/Design Pattern] Facade Pattern / 퍼사드 패턴</title>
      <link>https://lee1535.tistory.com/98</link>
      <description>&lt;p&gt;관련 내용은 &lt;code&gt;[자바 언어로 배우는 디자인 패턴 입문]&lt;/code&gt;,&lt;code&gt;[Head First Design Pattern]&lt;/code&gt;의 내용을 참고해서 정리한 내용입니다. 잘못된 부분은 댓글로 피드백 부탁드립니다.&lt;/p&gt;
&lt;h1&gt;1. Facade 패턴이란?&lt;/h1&gt;
&lt;hr&gt;
&lt;p&gt;어떤 서브시스템의 일련의 인터페이스에 대한 통합된 인터페이스를 제공합니다. 즉, 서브시스템들을 사용하기 쉽게 통합해주는 역할을 합니다.&lt;/p&gt;
&lt;h1&gt;2. Facade 패턴의 등장인물&lt;/h1&gt;
&lt;hr&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Facade(정면)의 역할&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;수만은 서브기능들에 대한 &amp;#39;창구&amp;#39;가 됩니다. 높은 레벨에서 단순한 인터페이스(API)를 외부에 제공합니다.&lt;/p&gt;
&lt;h5&gt;Facade 패턴의 클래스 다이어그램&lt;/h5&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7BPtp/btqAs3QlP7Z/Xw0XAeVEsxREMEr1RTzfMK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7BPtp/btqAs3QlP7Z/Xw0XAeVEsxREMEr1RTzfMK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7BPtp/btqAs3QlP7Z/Xw0XAeVEsxREMEr1RTzfMK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7BPtp%2FbtqAs3QlP7Z%2FXw0XAeVEsxREMEr1RTzfMK%2Fimg.jpg&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;3. 예제&lt;/h1&gt;
&lt;hr&gt;
&lt;p&gt;여러분들이 집에서 영화를 보려고 자동화 시스템을 만들기로 합니다. 이때 준비해야할 목록들을 생각해봅니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;팝콘 또는 간식 준비&lt;/li&gt;
&lt;li&gt;음료 준비&lt;/li&gt;
&lt;li&gt;스크린 내리기&lt;/li&gt;
&lt;li&gt;엠프 준비&lt;/li&gt;
&lt;li&gt;빔프로젝터 가동&lt;/li&gt;
&lt;li&gt;기타 등등등..&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;위 예시와 같이 영화를 보기 위해서 복잡한 서브시스템들을 동작해야 합니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public static void main(String[] args) {
        Screen screen = new Screen();
        screen.down();

        new Projector projector = new Projector();
        projector.on();

        // 등등 기타 필요한 서브프로그램 동작
    }&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;위와 같이 동작한다고 가정했을 경우 영화가 끝나고 각종 서브 시스템들을 종료해야 할 경우, 위와 같은 과정의 반대과정을 또 수행해야 할까요? 서브 시스템에 수정이 생기면 클라이언트는 또 다른 수정이 필요하게 됩니다.&lt;br&gt;&lt;strong&gt;이와 같은 문제에서 &lt;code&gt;Facade&lt;/code&gt; 패턴을 사용합니다.&lt;/strong&gt;&lt;/p&gt;
&lt;h1&gt;4. 해결방법&lt;/h1&gt;
&lt;hr&gt;
&lt;p&gt;위와 같은 문제를 해결하는 방법은 간단합니다. 서브시스템들의 사용을 정의한 인터페이스(API) 클래스를 하나 만들어주고, 클라이언트는 해당 클래스를 통해서 영화를 볼 수 있게 설계하면 됩니다.&lt;/p&gt;
&lt;h5&gt;4-1. HomeTheaterFacade 클래스 ( API )&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;public class HomeTheaterFacade {
    DvdPlayer dvd;
    Projector projector;
    Screen screen;
    Amplifier amp;

    public HomeTheaterFacade(DvdPlayer dvd, Projector projector, Screen screen, Amplifier amp) {
        super();
        this.dvd = dvd;
        this.projector = projector;
        this.screen = screen;
        this.amp = amp;
    }

    public void watchMovie(String movie) {
        System.out.println(movie +&amp;quot; 영화를 보기 위한 준비중입니다.&amp;quot;);
        screen.down();
        projector.on();
        amp.on();
        dvd.on();
        dvd.play(movie);

    }
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;위와 같이 서브 시스템의 사용을 정의합니다. 만약 추가 기능이 필요하면 메소드를 추가해주면 되고, 수정이 발생할 경우 클라이언트쪽 소스가 아닌 해당 클래스의 수정이 있으면 됩니다.&lt;/p&gt;
&lt;h5&gt;4-2. Main 클래스&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {
        HomeTheaterFacade homeTheatherFacade = new HomeTheaterFacade(
                new DvdPlayer(),new Projector(), new Screen(), new Amplifier());

        homeTheatherFacade.watchMovie(&amp;quot;The Thirteenth Floor( 13층 )&amp;quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;h5&gt;4-3. 실행 결과&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;The Thirteenth Floor( 13층 ) 영화를 보기 위한 준비중입니다.
스크린을 내립니다.
프로젝터 실행
엠프 동작
DVD 인식 완료
------The Thirteenth Floor( 13층 ) 내용 -------&lt;/code&gt;&lt;/pre&gt;&lt;h5&gt;4-4 왜 사용할까?&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;사용 예제와 같이 클라이언트는 복잡한 서비스시템의 동작을 관리하지 않아도 됩니다.&lt;ul&gt;
&lt;li&gt;즉 단순화된 인터페이스를 통해서 서브시스템을 더 쉽게 사용할 수 있도록 하기 위해 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;서비시스템에 변경이 있어도 클라이언트의 수정은 필요가 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;5. 관련 패턴&lt;/h1&gt;
&lt;hr&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Abstract Factory&lt;/code&gt; 패턴 : 오브젝트 생성이라는 복잡한 작업을 &lt;code&gt;Facade&lt;/code&gt; 패턴으로 간주할 수 있습니다. &lt;a href=&quot;https://lee1535.tistory.com/74?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Singleton&lt;/code&gt; 패턴 : &lt;code&gt;Facade&lt;/code&gt;는 싱글톤으로 만들어지는 경우가 있습니다. &lt;a href=&quot;https://lee1535.tistory.com/75?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Mediator&lt;/code&gt;패턴 :&lt;code&gt;Facade&lt;/code&gt;는 단방향이지만, 해당 패턴은 양방향으로, 중개자역할을 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;6. 비교하기&lt;/h1&gt;
&lt;hr&gt;
&lt;p&gt;디자인 패턴을 배우다 보니까 &lt;code&gt;Adapter&lt;/code&gt; , &lt;code&gt;Decorator&lt;/code&gt;, &lt;code&gt;Facade&lt;/code&gt; 가 얼핏 보면 비슷하다고 느낌이 들어서 차이점을 정리합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Adapter&lt;/code&gt; : 관계가 없는 인터페이스(API)를 연결할 때 사용, &lt;strong&gt;호환성&lt;/strong&gt; &lt;a href=&quot;https://lee1535.tistory.com/72?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Decorator&lt;/code&gt; : 인터페이스(API)를 바꾸지 않고 기능을 추가. &lt;strong&gt;확장성&lt;/strong&gt; &lt;a href=&quot;https://lee1535.tistory.com/95?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Facade&lt;/code&gt; : 인터페이스(API)를 간편하게 사용. &lt;strong&gt;간편함&lt;/strong&gt; &lt;a href=&quot;https://lee1535.tistory.com/98&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>PROGRAMMING/디자인패턴</category>
      <category>DesignPattern</category>
      <category>facade</category>
      <category>Java</category>
      <category>자바</category>
      <category>퍼사드</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/98</guid>
      <comments>https://lee1535.tistory.com/98#entry98comment</comments>
      <pubDate>Mon, 16 Dec 2019 15:58:03 +0900</pubDate>
    </item>
    <item>
      <title>[자바/알고리즘] 프로그래머스 주식가격</title>
      <link>https://lee1535.tistory.com/97</link>
      <description>&lt;h1&gt;문제 설명&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;초 단위로 기록된 주식가격이 담긴 배열 prices가 매개변수로 주어질 때, 가격이 떨어지지 않은 기간은 몇 초인지를 return 하도록 sulution 함수를 완성하세요.&lt;/p&gt;
&lt;h1&gt;제한사항&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;prices의 각 가격은 1 이상 10,000 이하인 자연수입니다.&lt;/li&gt;
&lt;li&gt;prices의 길이는 2 이상 100,000 이하입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;입출력 예&lt;/h1&gt;
&lt;hr /&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-style=&quot;style8&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;b&gt;prices&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;b&gt;return&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span&gt;[1, 2, 3, 2, 3]&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span&gt;[4, 3, 1, 1, 0]&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;입출력 예 설명&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;1초 시점의 \1은 끝까지 가격이 떨어지지 않았습니다,&lt;/li&gt;
&lt;li&gt;2초 시점의 \2은 끝까지 가격이 떨어지지 않았습니다.&lt;/li&gt;
&lt;li&gt;3초 시점의 \3은 1뒤에 가격이 떨어집니다. 따라서 1초간 가격이 떨어지지 않은것으로 봅니다.&lt;/li&gt;
&lt;li&gt;4초 시점의 \2은 1초간 가격이 떨어지지 않았습니다,&lt;/li&gt;
&lt;li&gt;5초 시점의 \3은 0초간 가격이 떨어지지 않았습니다,&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;나의 풀이&lt;/h1&gt;
&lt;hr /&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;class Solution {
    public int[] solution(int[] prices) {
        int[] answer = new int[prices.length];

        for (int i = 0; i &amp;lt; answer.length; i++) {
            int sec = 0;
            int su = prices[i];
            for (int j = i+1; j &amp;lt; prices.length; j++) {
                sec ++;
                if(su &amp;gt; prices[j]) {
                    break;
                }
            }
            answer[i] = sec;
        }
        return answer;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;풀이 설명&lt;/h5&gt;
&lt;p&gt;각 시점 즉 &lt;code&gt;prices[]&lt;/code&gt;의 인덱스마다 가격이 떨어지는 시점을 기억하기 위해서 su라는 변수에 해당 시점의 가격을, sec라고해서 유지한 시간을 기록하기 위한 변수를 선언했습니다.&lt;br /&gt;그 후, 가격이 떨어지는지 배교해가면서 break 문으로 반복문을 컨트롤하면서 값을 리턴해줍니다.&lt;/p&gt;</description>
      <category>알고리즘/프로그래머스</category>
      <category>Java</category>
      <category>알고리즘</category>
      <category>자바</category>
      <category>주식가격</category>
      <category>프로그래머스</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/97</guid>
      <comments>https://lee1535.tistory.com/97#entry97comment</comments>
      <pubDate>Mon, 16 Dec 2019 13:32:44 +0900</pubDate>
    </item>
    <item>
      <title>[자바/알고리즘] 프로그래머스 문자열 내림차순으로 배치하기</title>
      <link>https://lee1535.tistory.com/96</link>
      <description>&lt;h1&gt;문제 설명&lt;/h1&gt;
&lt;hr&gt;
&lt;p&gt;문자열 s에 나타나는 문자를 큰것부터 작은 순으로 정렬해 새로운 문자열을 리턴하는 함수, solution을 완성해주세요.&lt;br&gt;s는 영문 대소문자로만 구성되어 있으며, 대문자는 소문자보다 작은 것으로 간주합니다.&lt;/p&gt;
&lt;h1&gt;제한 사항&lt;/h1&gt;
&lt;hr&gt;
&lt;ul&gt;
&lt;li&gt;str은 길이 1 이상인 문자열입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;입출력 예&lt;/h1&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-style=&quot;style8&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;width: 50%;&quot;&gt;&lt;b&gt;S&lt;/b&gt;&lt;/td&gt;&lt;td style=&quot;width: 50%;&quot;&gt;&lt;b&gt;return&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width: 50%;&quot;&gt;&quot;&lt;span&gt;Zbcdefg&lt;/span&gt;&quot;&lt;/td&gt;&lt;td style=&quot;width: 50%;&quot;&gt;&quot;&lt;span&gt;gfedcbZ&lt;/span&gt;&quot;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;

&lt;h2&gt;람다를 활용한 풀이&lt;/h2&gt;
&lt;p&gt;최근 람다식을 공부하고 있어서 시간날 때 기존의 풀이를 람다로 변경해보는 연습을 진행중입니다.&lt;br&gt;기존 아래의 코드를 람다식으로 풀어본 결과입니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Solution {
  public String solution(String s) {

      return Stream.of(s.split(&amp;quot;&amp;quot;))
                .sorted(Collections.reverseOrder())
                .collect(Collectors.joining());
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;h1&gt;나의 풀이&lt;/h1&gt;
&lt;hr&gt;
&lt;pre&gt;&lt;code&gt;class Solution {
  public String solution(String s) {

      char[] cArr = s.toCharArray();

      for (int i = 1; i &amp;lt; cArr.length; i++) {    
            for (int j = 0; j &amp;lt; cArr.length; j++) {
                if(cArr[i]&amp;gt;cArr[j]) {
                    char temp = cArr[j];
                    cArr[j] = cArr[i];
                    cArr[i] = temp;
                    i--;
                    break;
                }
            }
        }
      return new String(cArr);
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;h5&gt;풀이 설명&lt;/h5&gt;
&lt;p&gt;기본적으로 다른사람들은 &lt;code&gt;Arrays.sort()&lt;/code&gt; 를 사용해 정렬 후, 리버스 하는 방식으로 풀이를 접근했습니다.&lt;br&gt;저는 이와 비슷한 문제에서 자주 사용했기 때문에 정렬 자체를 구현해보는게 목적이였습니다.&lt;/p&gt;</description>
      <category>알고리즘/프로그래머스</category>
      <category>Java</category>
      <category>문자열 내림차순</category>
      <category>알고리즘</category>
      <category>자바</category>
      <category>정렬</category>
      <category>프로그래머스</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/96</guid>
      <comments>https://lee1535.tistory.com/96#entry96comment</comments>
      <pubDate>Fri, 13 Dec 2019 16:58:58 +0900</pubDate>
    </item>
    <item>
      <title>[디자인패턴/Design Pattern] Decorator Pattern / 데코레이터 패턴</title>
      <link>https://lee1535.tistory.com/95</link>
      <description>&lt;p&gt;관련 내용은 &lt;code&gt;[자바 언어로 배우는 디자인 패턴 입문]&lt;/code&gt;,&lt;code&gt;[Head First Design Pattern]&lt;/code&gt;의 내용을 참고해서 정리한 내용입니다. 잘못된 부분은 댓글로 피드백 주시면 감사하겠습니다.&lt;/p&gt;
&lt;h1&gt;1. Docorator 패턴이란?&lt;/h1&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;객체에 추가적인 요건을 동적으로 첨가할때 사용하는 방식으로, 서브클래스를 만드는 것을 통해서 기능을 유연하게 확장할 수 있는 방법을 제공합니다.&lt;/p&gt;
&lt;h1&gt;2. Decorator 패턴의 등장인물&lt;/h1&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ul&gt;
&lt;li&gt;Component
&lt;ol&gt;
&lt;li&gt;기능을 추가할 때 핵심이 되는 역할로, 해당 기능의 인터페이스(API)만을 결정합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;ConcreteCompoent
&lt;ol&gt;
&lt;li&gt;Component를 실제로 구현하는 역할입니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Decorator(장식자)
&lt;ol&gt;
&lt;li&gt;Component와 동일한 인터페이스(API)를 가지며, 구체적인 장식자의 Component 역할을 합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;ConcreteDecorator(구체적인 장식자)
&lt;ol&gt;
&lt;li&gt;Decorator를 시렞로 구현하는 역할입니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;2-1. Decorator 패턴의 클래스 다이어그램&lt;/h5&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-origin-width=&quot;566&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/v1s4x/btqAo57cIus/26FyNJSWTtdKSyvYkzprpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/v1s4x/btqAo57cIus/26FyNJSWTtdKSyvYkzprpK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/v1s4x/btqAo57cIus/26FyNJSWTtdKSyvYkzprpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fv1s4x%2FbtqAo57cIus%2F26FyNJSWTtdKSyvYkzprpK%2Fimg.png&quot; data-origin-width=&quot;566&quot; data-origin-height=&quot;483&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;3. 예제&lt;/h1&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;여러분이 스타OO과 같은 음료회사의 주문시스템을 만들어야 하는 상황이 생겼다고 가정했을 때, 음료라는 큰 슈퍼클래스를 두고 음료들을 서브클래스로 두어서 구현을 하려고 할 것입니다.&lt;br /&gt;그런데 음료의 갯수가 너무 많아진다면? 또한 휘핑크림 추가나 우유 추가등 첨가물에 따라서 동작이나 가격이 달라진다면? 엄청나게 많은 클래스가 필요할것이고, 휘핑크림의 가격이 변동되면 수정해야 될 클래스들도 상당할 것이다.&lt;/p&gt;
&lt;h5&gt;3-1. 예제 클래스 다이어그램&lt;/h5&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/710Fj/btqAmsCJXCL/x2vwK1THskcrPkRNsyS540/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/710Fj/btqAmsCJXCL/x2vwK1THskcrPkRNsyS540/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/710Fj/btqAmsCJXCL/x2vwK1THskcrPkRNsyS540/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F710Fj%2FbtqAmsCJXCL%2Fx2vwK1THskcrPkRNsyS540%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;이와 같은 상황에 여러분들은 공통되는 부분을 추출하고자 첨가물인 밀크, 휘핑크림등을 슈퍼클래스의 구성으로 가지면 밀크가 들어간 에스프레소, 휘핑크림이 들어간 에스프레소 등을 하나의 에스프레소 클래스로 줄일 수 있지 않을까라는 생각이 들 수도 있습니다.&lt;/p&gt;
&lt;h5&gt;3-2. 첨가물을 구성으로 가지는 슈퍼 클래스&lt;/h5&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public abstract class Beverage {
    private Milk milk ;
    private Whip whip;
    // 기타 필요한 필드 및 생성자는 생략

    public void addMilk() { 
        // 우유 추가 동작 구현
    }
    // milk 관련 메소드 게터세터 등등
    // 나머지 메소드도 생략

}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;대충 슈퍼클래스가 위와 같은 방식으로 정의되어 있을 때, 첨가물을 구성으로 사용하여 클래스 개수도 줄이는 등 괜찮아 보일 수 있지만 아직도 아래와 같은 문제점이 존재합니다.&lt;/p&gt;
&lt;h5&gt;3-2 클래스의 문제점&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;첨가물에 대한 수정이 있을 경우 super 클래스의 수정이 필요 ( 추가, 수정, 삭제 등 )&lt;/li&gt;
&lt;li&gt;새로운 클래스가 우유가 들어가면 안되는 경우 서브클래스에서 &lt;code&gt;addMilk()&lt;/code&gt; 메소드가 동작 안하도록 추가 구현 필요&lt;/li&gt;
&lt;li&gt;우유를 2번 추가하는 동작이 필요하면 &lt;code&gt;doubleAddMilk()&lt;/code&gt; 메소드가 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;등과 같은 여러 문제가 아직 발생합니다. 이렇게 동적으로 객체에 요건을 추가할 상황이 많을 경우 &lt;b&gt;데코레이터 패턴&lt;/b&gt;을 사용합니다.&lt;/p&gt;
&lt;h1&gt;4. Decorator 패턴을 사용한 해결&lt;/h1&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h5&gt;4-1. 예제에 사용 될 클래스 다이어그램&lt;/h5&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cpO7QP/btqAnn8W1Hy/uuzTxTK6tepDvAaWjQsfh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cpO7QP/btqAnn8W1Hy/uuzTxTK6tepDvAaWjQsfh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cpO7QP/btqAnn8W1Hy/uuzTxTK6tepDvAaWjQsfh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcpO7QP%2FbtqAnn8W1Hy%2FuuzTxTK6tepDvAaWjQsfh0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h5&gt;4-2. BeverageComponent 클래스&lt;/h5&gt;
&lt;p&gt;Compoent 역할로써 전체의 핵심 역할로 인터페이스(API)를 정의하는 클래스입니다. 여기서 전체 구현하는 클래스들의 '형식'을 정해줍니다. 사실상 좀 더 발전된 디자인의 방식으로는 해당 클래스도 abstract가 아닌 interface로 '형식'만 정의해주는 방식이 가장 이상적이지만&lt;br /&gt;예제에서는 기존에 &lt;code&gt;BeverageComponent&lt;/code&gt;라는 추상클래스가 존재할 때 변경방법을 소개하는 방향이여서 추상 클래스를 써야 하는 상황이라면 그냥 추상클래스로 구성하는게 더 나을수도 있습니다. 즉 &lt;b&gt;구현하는 시점에 좀 더 비용이 저렴한 방식을 사용하면 됩니다.&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public abstract class BeverageComponent {
    protected String name;

    public String getName() {
        return name;
    }
    public abstract int cost();
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;4-3. CondimentDecorator 클래스&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;Decorator&lt;/code&gt;의 역할로, &lt;code&gt;Compoent&lt;/code&gt;역할인 &lt;code&gt;BeverageComponent&lt;/code&gt;를 상속받으며, &lt;code&gt;ConcreteDecorator&lt;/code&gt;의 &lt;code&gt;Compoent&lt;/code&gt;를 역할을 수행합니다.&lt;/p&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;public abstract class CondimentDecorator extends BeverageComponent {
    public abstract String getName();
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;4-4. Hazelnut 클래스&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;ConcreteDecorator&lt;/code&gt;의 역할로 &lt;code&gt;CondimentDecorator&lt;/code&gt;를 상속받아 내용을 정의해줍니다.&lt;br /&gt;핵심은 필드로 &lt;code&gt;BeverageComponent&lt;/code&gt; 클래스를 가지며, &lt;b&gt;확장의 대상이 될 객체를 참조&lt;/b&gt;시킵니다.&lt;br /&gt;나머지 &lt;code&gt;Milk&lt;/code&gt;, &lt;code&gt;Mocha&lt;/code&gt; 도 필요에 따라 정의해주시면 됩니다.&lt;/p&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;public class Hazelnut extends CondimentDecorator {
    BeverageComponent beverage;

    public Hazelnut(BeverageComponent beverage) {
        this.beverage = beverage;
    }

    @Override
    public String getName() {
        return &quot;헤이즐넛 시럽 추가, &quot; + beverage.getName() ;
    }

    @Override
    public int cost() {
        return 500 + beverage.cost();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;4-5. Main 클래스&lt;/h5&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {

        BeverageComponent beverage = new Americano();
        System.out.println(beverage.getName() +&quot; 가격 : &quot; + beverage.cost());

        BeverageComponent beverage2 = new Americano();
        beverage2 = new Mocha(beverage2);
        beverage2 = new Hazelnut(beverage2);
        System.out.println(beverage2.getName() +&quot; 가격 : &quot; + beverage2.cost());

    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;beverage2&lt;/code&gt;를 보시면 생성자를 통해 확장시키고 싶은 객체를 참조시키며 자신으로 감싸는 모습이 보입니다.&lt;br /&gt;이렇게 확장이 필요할 경우 원하는 만큼 객체를 감싸면서 객체를 확장해 갈 수 있는 방식입니다.&lt;/p&gt;
&lt;h5&gt;4-5 실행결과&lt;/h5&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;아메리카노 가격 : 2000
헤이즐넛 시럽 추가, 모카 추가,  아메리카노 가격 : 3300
우유 추가 , 아메리카노 가격 : 3500&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;왜 사용할까?&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;추가 첨가물(휘핑크림)인 &lt;code&gt;Whip&lt;/code&gt; 클래스가 추가 된다고 가정했을 때, 그냥 &lt;code&gt;Whip&lt;/code&gt; 클래스를 생성해주고, &lt;code&gt;CondimentDecorator&lt;/code&gt; 클래스를 상속받아 내용만 정의해주면 기존 코드에 수정없이 클라이언트는 &lt;code&gt;Whip&lt;/code&gt; 첨가물을 사용할 수 있게 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;5. 관련 패턴&lt;/h1&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Adapter&lt;/code&gt; 패턴 : Decorator 패턴은 내용을 변경없이 장식을 추가하는 패턴이고, 해당 패턴은 다른 두개의 인터페이스를 연결해줍니다. &lt;a href=&quot;https://lee1535.tistory.com/72?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Strategy&lt;/code&gt; 패턴 : 알고리즘 자체를 변경해서 기능을 확장이 아닌 변경합니다. &lt;a href=&quot;https://lee1535.tistory.com/93&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;6. 비교하기&lt;/h1&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;디자인 패턴을 배우다 보니까&lt;span&gt;&amp;nbsp;&lt;/span&gt;Adapter&lt;span&gt;&amp;nbsp;&lt;/span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;Decorator,&lt;span&gt;&amp;nbsp;&lt;/span&gt;Facade&lt;span&gt;&amp;nbsp;&lt;/span&gt;가 얼핏 보면 비슷하다고 느낌이 들어서 차이점을 정리합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Adapter&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 관계가 없는 인터페이스(API)를 연결할 때 사용,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;호환성&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://lee1535.tistory.com/72?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Decorator&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 인터페이스(API)를 바꾸지 않고 기능을 추가.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;확장성&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://lee1535.tistory.com/95?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Facade&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 인터페이스(API)를 간편하게 사용.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;간편함&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;a href=&quot;https://lee1535.tistory.com/98&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>PROGRAMMING/디자인패턴</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/95</guid>
      <comments>https://lee1535.tistory.com/95#entry95comment</comments>
      <pubDate>Thu, 12 Dec 2019 14:03:46 +0900</pubDate>
    </item>
    <item>
      <title>[디자인패턴/Design Pattern] Observer 패턴 / 관찰자 패턴 / Publish-Subscribe 패턴</title>
      <link>https://lee1535.tistory.com/94</link>
      <description>&lt;p&gt;관련 내용은 &lt;code&gt;[자바 언어로 배우는 디자인 패턴 입문]&lt;/code&gt;,&lt;code&gt;[Head First Design Pattern]&lt;/code&gt; 의 내용을 정리해서 작성한 내용입니다. 잘못된 부분이 있으면 댓글로 알려주시면 감사하겠습니다.&lt;/p&gt;
&lt;h1&gt;1. Observer 패턴이란?&lt;/h1&gt;
&lt;hr&gt;
&lt;p&gt;한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체들에게 변화를 알려주고 자동으로 내용이 갱신되는 방식으로 일대다의 의존성을 정의합니다.&lt;br&gt;즉 상태 변화에 따른 처리를 기술할 때 사용합니다. 또한 느슨한 결합을 통해 의존성을 제거해줍니다.&lt;/p&gt;
&lt;h1&gt;2. Observer 패턴의 등장 인물&lt;/h1&gt;
&lt;hr&gt;
&lt;ul&gt;
&lt;li&gt;Subject(관찰 대상자)의 역할&lt;ol&gt;
&lt;li&gt;&amp;#39;관찰되는 대상&amp;#39;을 관리하는 요소&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;ConcreteSubject(구체적인 관찰 대상자)의 역할&lt;ol&gt;
&lt;li&gt;구체적으로 Subject를 표현하는 역할이며, 통보하는 클래스&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Observer(관찰자)의 역할&lt;ol&gt;
&lt;li&gt;&amp;#39;상태가 변화됨&amp;#39;을 전달 받는 역할을 합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;ContreteObserver(구체적인 관찰자)의 역할&lt;ol&gt;
&lt;li&gt;Observer를 구체적으로 표현하며, &amp;#39;변화를 통보 받는&amp;#39; 클래스&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BP41b/btqAkSH9IJV/Fi3JmKuYWXVydViZZgVLdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BP41b/btqAkSH9IJV/Fi3JmKuYWXVydViZZgVLdk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BP41b/btqAkSH9IJV/Fi3JmKuYWXVydViZZgVLdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBP41b%2FbtqAkSH9IJV%2FFi3JmKuYWXVydViZZgVLdk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;3. 예제&lt;/h1&gt;
&lt;p&gt;그렇다면 ConcreteSubject와 ContreteObserver를 바로 연관관계를 맺고 사용하면 되지 왜 Subject와 Observer 인터페이스를 구현하면서 사용하는 것일까 ?&lt;/p&gt;
&lt;h5&gt;3-1. WeatherDataSubject 클래스&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;public class WeatherDataSubject {

    // 인스턴스 변수 
    ...

    public void weatherUpdate() {

        float temp = getTemperature(); // 온도 가져오기

        // 변화를 알려주기
        currentWeatherDisplay.update(temp, humidiry,);
        forecastDisplay.update(temp, humidiry,);
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;위와 같이 존재하고 각각 &lt;code&gt;CurrentWeatherDisplay&lt;/code&gt; 클래스와, &lt;code&gt;ForecastDisplay&lt;/code&gt; 클래스가 있을 때 여러가지 문제점이 발생합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;첫째로, 통계를 보고 싶어서 &lt;code&gt;StatisticsDisplay&lt;/code&gt; 라는 클래스를 추가하고 싶은 경우, &lt;code&gt;weatherUpdate()&lt;/code&gt; 메서드 부분에 수정이 필요합니다.&lt;/li&gt;
&lt;li&gt;둘째로, 각 클래스마다 행동이 다를 수 있기 때문에 캡슐화를 해야 합니다.&lt;/li&gt;
&lt;li&gt;셋째로, 공통적으로 사용하는 메소드 update()를 인터페이스로 정의합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;이렇게 객체 간 의존성이 존재하게 됩니다.&lt;/strong&gt;&lt;/p&gt;
&lt;h1&gt;3. 해결법&lt;/h1&gt;
&lt;p&gt;위와 같은 문제를 해결하기 위해 Observer 패턴을 사용합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;각 객체는 언제든지 옵저버로 추가되고 삭제될 수 있어야 합니다.&lt;/li&gt;
&lt;li&gt;변화될 수 있는 행동은 구현이 아닌 인터페이스를 사용해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;3-1. 예제 클래스 다이어그램&lt;/h5&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-filename=&quot;이미지 21.png&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;399&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dtIBKw/btqAovYTIxn/KyD60kac4GONEkktryxTBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dtIBKw/btqAovYTIxn/KyD60kac4GONEkktryxTBK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dtIBKw/btqAovYTIxn/KyD60kac4GONEkktryxTBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdtIBKw%2FbtqAovYTIxn%2FKyD60kac4GONEkktryxTBK%2Fimg.png&quot; data-filename=&quot;이미지 21.png&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;399&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h5&gt;3-2. interface ( Subject, Observer, DisplayElement )&lt;/h5&gt;
&lt;p&gt;여기서 &lt;code&gt;DisplayElement&lt;/code&gt;는 행동을 캡슐화할 목적인 인터페이스로 디자인의 원칙에 따라 디자인하기 위해서 추가된 인터페이스입니다. 가장 핵심은 &lt;strong&gt;&lt;code&gt;Subject&lt;/code&gt;, &lt;code&gt;Observer&lt;/code&gt;&lt;/strong&gt; 인터페이스입니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public interface Subject {
    public void registerObserver(Observer o); // 옵저버 등록
    public void removeObserver(Observer o);      // 옵저버 삭제
    public void notifyObservers();               // 변화를 알려주기 위한 메소드
}

public interface Observer {
    public void update(float temp, float humidity);
}

public interface DisplayElement {
    public void display();
}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Subject&lt;/code&gt; : &amp;#39;관찰되는 대상&amp;#39;을 관리하는 요소 인터페이스. &lt;strong&gt;Observer&lt;/strong&gt;를 저장, 삭제, 알려주는 메소드를 선언합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Observer&lt;/code&gt; : &amp;#39;상태가 변화됨&amp;#39;을 관리하는 요소 인터페이스. 통보당했을 때 처리할 메소드를 선언합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DisplayElement&lt;/code&gt; 인터페이스는 행동을 추상화하기 위한 인터페이스로 화면에 그려줄 &lt;code&gt;display()&lt;/code&gt; 메소드를 선언합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;3-3. WeatherData 클래스&lt;/h5&gt;
&lt;p&gt;이제 처음에 3번에서 나온 예제의 문제점을 보였던 WeatherData 클래스입니다. 아래는 옵저버 패턴을 사용한 클래스의 변경 내용입니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public class WeatherDataSubject implements Subject {
    private ArrayList&amp;lt;Observer&amp;gt; observers; // 옵저버들을 저장
    private float temperature;                
    private float humidity;

    public WeatherDataSubject() {
        observers = new ArrayList&amp;lt;Observer&amp;gt;(); 
    }

    @Override
    public void registerObserver(Observer o) {
        observers.add(o);
    }

    @Override
    public void removeObserver(Observer o) {
        observers.remove(observers.indexOf(o));
    }

    // 변화된 상태를 알려주는 메소드
    @Override
    public void notifyObservers() {
        for (Observer o : observers) {
            o.update(temperature, humidity);
        }
    }

    // 상태가 변화됨을 감지하는 메소드
    public void measurementsChanged() {
        notifyObservers();
    }

    // 상태를 변화 시키는 메소드
    public void setMeasurments(float temperature, float humidity) {
        this.temperature = temperature;
        this.humidity = humidity;
        measurementsChanged();
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;우선 문제였던 옵저버의 추가 삭제를 쉽게 하기 위해서 &lt;strong&gt;observers&lt;/strong&gt; 라는 List 컬렉션을 필드로 가지고, 생성자를 통해 초기화를 해줍니다.&lt;br&gt;그리고 &lt;code&gt;Subject&lt;/code&gt; 인터페이스의 메소드들을 정의해줍니다. 마지막으로 변경된 정보를 받아들일 메소드들을 차례로 정의해줍니다.&lt;/p&gt;
&lt;h5&gt;3-4. CurrentWeatherDisplay 클래스&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;public class CurrentWeatherDisplay implements Observer, DisplayElement {
    private float temperature;
    private float humidity;
    private Subject weatherData;

    public CurrentWeatherDisplay( WeatherDataSubject weatherData) {
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }

    @Override
    public void update(float temperature, float humidity) {
        this.temperature = temperature;
        this.humidity = humidity;
        display();
    }

    @Override
    public void display( ) {
        System.out.println(&amp;quot;최근 기온은 : &amp;quot; + temperature + &amp;quot; / 습도는 : &amp;quot; + humidity +&amp;quot;% 입니다.&amp;quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;ol&gt;
&lt;li&gt;&lt;code&gt;WeatherData&lt;/code&gt; 객체로부터 변경 사항을 받기 위해 &lt;code&gt;Observer&lt;/code&gt; 인터페이스를 구현합니다. 같은 &lt;code&gt;Subject&lt;/code&gt;를 쓰기위해 생성자를 통해 weatherData를 전달받고, 필드의 객체에 참조시킵니다. 그리고 &lt;code&gt;registerObserver(Observer)&lt;/code&gt; 메소드를 호출해 해당 클래스를 List에 등록시킵니다. 이 부분은 필요에 따라 메소드로 분리하셔도 됩니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;update()&lt;/code&gt; 메소드를 재정의합니다. 그리고 &lt;code&gt;display()&lt;/code&gt;메소드를 호출시켜 줍니다. 마찬가지로 재정의해줍니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h5&gt;3-5 Main 클래스&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {
        WeatherDataSubject weatherData = new WeatherDataSubject();

        CurrentWeatherDisplay cwd = new CurrentWeatherDisplay(weatherData);
        ForecastDisplay fd = new ForecastDisplay(weatherData);
        //StatisticsDisplay sd = new StatisticsDisplay(weatherData);

        weatherData.setMeasurments(28, 30);
        weatherData.setMeasurments(34, 89);

    }
}&lt;/code&gt;&lt;/pre&gt;&lt;h5&gt;실행 결과&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;최근 기온은 : 28.0 / 습도는 : 30.0% 입니다.
내일의 예상 기온은 : 30.0 / 에상 습도는 : 35% 입니다.
최근 기온은 : 34.0 / 습도는 : 89.0% 입니다.
내일의 예상 기온은 : 37.0 / 에상 습도는 : 88% 입니다.&lt;/code&gt;&lt;/pre&gt;&lt;h5&gt;람다로 리팩토링&lt;/h5&gt;
&lt;p&gt;위 예제에서 사용된 &lt;code&gt;Observer&lt;/code&gt; 인터페이스는 함수형 인터페이스라고 볼 수 있다. 그렇기에 아래 처럼 사용이 가능&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;weatherData.registerObserver((temperature, humidity) 
                -&amp;gt; System.out.println(&amp;quot;최근 기온은 : &amp;quot; + temperature + &amp;quot; / 습도는 : &amp;quot; + humidity +&amp;quot;% 입니다.&amp;quot;));

        weatherData.registerObserver((temperature, humidity) 
                -&amp;gt; System.out.println(&amp;quot;내일의 예상 기온은 : &amp;quot; + (temperature + (new Random().nextInt(6))) +&amp;quot; / 에상 습도는 : &amp;quot; + (new Random().nextInt(100)) + &amp;quot;% 입니다.&amp;quot; ));&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;예제에서는 &lt;code&gt;Display&lt;/code&gt;라는 행동을 분리해서 인터페이스화 했었지만, 람다에서는 필요한 구현을 넘기기 때문에 해당 &lt;code&gt;Display&lt;/code&gt; 인터페이스와 옵저버 구현 클래스 2개가 불필요해진다. &lt;/p&gt;
&lt;p&gt;다만 람다가 만능은 아닙니다. 현재는 구현 자체가 간단하지만, 구현의 로직이 복잡하고 어려운 경우는 기존의 방식처럼 클래스와 인터페이스를 통한 구현을 고려해봐야합니다. 상황에 맞게 사용하시면 되겠습니다.&lt;/p&gt;
&lt;h5&gt;사용 이유&lt;/h5&gt;
&lt;p&gt;실행결과와 같이 &lt;strong&gt;Clilet&lt;/strong&gt;는 이제 옵저버를 등록만하고, 변경만 해주면 알아서 변화된 상태를 감지하고 동작을 합니다. ( 예제에서는 &lt;code&gt;display()&lt;/code&gt;와 같이 )&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;문제점이였던 직접적인 참조가 해결되어서 언제든 Obverser을 추가하고 삭제가 가능하다. ( 느슨한 결합 )&lt;/li&gt;
&lt;li&gt;전혀 새로운 클래스 예를들어 &lt;code&gt;StatisticsDisplay&lt;/code&gt; 클래스가 추가 되어도 Observer 인터페이스를 구현하고, 필요한 로직을 작성해두면, 기존의 코드에는 수정이 없이 옵저버로 사용이 가능하게 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;4. 관련 패턴&lt;/h1&gt;
&lt;hr&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Mediator&lt;/code&gt; 패턴 : 패턴의 역할간의 통신에 Observer 패턴을 사용하는 경우가 있습니다. 두 패턴 모두 &amp;#39;상태 변화를 알린다&amp;#39;는 점에서 비슷하지만, 목적이나 시점이 다릅니다. 해당 패턴은 상태변화의 알림 목적이 다른 역할의 조정이라는 목적으로 동작하고, Observer은 상태변화를 알려서 동기화를 이루는 일에 주안점을 두고 있습니다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>PROGRAMMING/디자인패턴</category>
      <category>Design Pattern</category>
      <category>Observer</category>
      <category>관찰자패턴</category>
      <category>디자인패턴</category>
      <category>옵저버</category>
      <category>자바</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/94</guid>
      <comments>https://lee1535.tistory.com/94#entry94comment</comments>
      <pubDate>Wed, 11 Dec 2019 16:39:16 +0900</pubDate>
    </item>
    <item>
      <title>[디자인패턴/Design Pattern] Strategy 패턴 / 전략 패턴</title>
      <link>https://lee1535.tistory.com/93</link>
      <description>&lt;p&gt;관련 내용은&lt;code&gt;[자바 언어로 배우는 디자인 패턴 입문]&lt;/code&gt;, &lt;code&gt;[Head First Design Pattern]&lt;/code&gt; 의 내용을 참고해서 정리한 내용입니다. 잘못된 부분은 댓글로 지적해주시면 감사하겠습니다.&lt;/p&gt;
&lt;h1&gt;1. Strategy 패턴이란?&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;알고리즘군을 정의하고 각각을 &lt;b&gt;켑슐화&lt;/b&gt;하여 교환해서 사용할 수 있도록 만드는 방식, Strategy 패턴을 활용하면 알고리즘을 사용하는 클라이언트와는 독립적으로 알고리즘을 변경할 수 있다.&lt;br /&gt;즉 알고리즘의 인터페이스(API) 부분만 규정해서 변경해서 사용할 수 있도록 하는 것&lt;/p&gt;
&lt;h1&gt;2. Strategy 패턴의 등장 인물&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;Strategy(전략)
&lt;ol&gt;
&lt;li&gt;전략을 이용하기 위한 인터페이스(API)를 결정합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;ConcreteStrategy(구체적인 전략)
&lt;ol&gt;
&lt;li&gt;Strategy를 실제로 구현하는 역할&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Context(문맥)
&lt;ol&gt;
&lt;li&gt;Strategy의 인터페이스(API)를 호출해서 이용하는 역할&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;2-1. Strategy 패턴의 클래스 다이어그램&lt;/h5&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mpSQ3/btqAnoFF0DV/aobcZVSLzIkmCpKJvXitXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mpSQ3/btqAnoFF0DV/aobcZVSLzIkmCpKJvXitXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mpSQ3/btqAnoFF0DV/aobcZVSLzIkmCpKJvXitXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmpSQ3%2FbtqAnoFF0DV%2FaobcZVSLzIkmCpKJvXitXk%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;3. 예제&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;예제를 통해서 내용을 구체화해보겠습니다.&lt;br /&gt;우선 &lt;code&gt;Duck&lt;/code&gt;라는 부모 클래스와 하위 클래스로 &lt;code&gt;MallardDuck&lt;/code&gt;, &lt;code&gt;RedheadDuck&lt;/code&gt;가 존재한다고 가정합니다.&lt;br /&gt;이때 우리는 객체지향적인 특성을 사용하기 위해 상속과, 추상화를 통해 공통된 부분을 부모 클래스에 정의하고 공통되지 않는 부분을 자식 클래스에서 정의하려고 할 것입니다.&lt;/p&gt;
&lt;h5&gt;3-1. 예제에 사용될 클래스 다이어그램&lt;/h5&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-filename=&quot;이미지 14.png&quot; data-origin-width=&quot;373&quot; data-origin-height=&quot;288&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XdDBy/btqAo7pQz5S/V4lFbOhTTN4X6zEOUwslo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XdDBy/btqAo7pQz5S/V4lFbOhTTN4X6zEOUwslo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XdDBy/btqAo7pQz5S/V4lFbOhTTN4X6zEOUwslo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXdDBy%2FbtqAo7pQz5S%2FV4lFbOhTTN4X6zEOUwslo0%2Fimg.png&quot; data-filename=&quot;이미지 14.png&quot; data-origin-width=&quot;373&quot; data-origin-height=&quot;288&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h5&gt;3-2. Duck 클래스 ( 부모 클래스 )&lt;/h5&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public abstract class Duck {

    public void swim() {
        System.out.println(&quot;오리가 수영을 합니다.&quot;);
    }

    public void quack() {
        System.out.println(&quot;꽥꽥 웁니다.&quot;);
    }

    public abstract void display();
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;3-3. 자식클래스 ( MallardDuck, RedheadDuck, DecoyDuck )&lt;/h5&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;public class MallardDuck extends Duck  {

    @Override
    public void display() {
        // TODO Auto-generated method stub
        System.out.println(&quot;청둥오리입니다.&quot;);
    }

}

public class RedheadDuck extends Duck{

    @Override
    public void display() {
        System.out.println(&quot;붉은 머리 오리입니다.&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이런 식으로 우리는 객체지향적으로 객체를 설계할 것입니다. 그런데 추가로 짖지도 않고, 날지도 못하는 가짜 오리인 &lt;code&gt;DecoyDuck&lt;/code&gt;가 추가가 된다고 하면? 아래와 같이 정의해야 할 것입니다.&lt;/p&gt;
&lt;h5&gt;3-4. DecoyDuck&lt;/h5&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;public class DecoyDuck extends Duck{

    @Override
    public void display() {
        System.out.println(&quot;장난감 오리입니다.&quot;);
    }

    @Override
    public void quack() {
        System.out.println(&quot;장난감이 삐용삐용 하고 소리를 냅니다.&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;나아가 갑자기 오리가 날아가는 기능을 추가해달라고 했습니다. 그렇다면 여러분은 공통기능이라고 생각해 &lt;code&gt;Duck&lt;/code&gt; 클래스에&lt;br /&gt;&lt;code&gt;public void fly() { System.out.println(&quot;오리가 날아갑니다&quot;); }&lt;/code&gt; 라는 메소드를 추가했다고 하면 우리는 가짜 오리인 &lt;code&gt;DecoyDuck&lt;/code&gt;에도 추가로 오버라이딩을 해줘야 하는 일이 발생합니다. &lt;b&gt;이와 같이 코드의 한 부분이 바뀜으로써 전체 프로그램에 수정, 부작용이 발생하게 됩니다.&lt;/b&gt;&lt;/p&gt;
&lt;h1&gt;4. 해결&lt;/h1&gt;
&lt;hr /&gt;
&lt;h5&gt;4-1. 예제에 사용될 클래스 다이어그램&lt;/h5&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-filename=&quot;이미지 15.png&quot; data-origin-width=&quot;569&quot; data-origin-height=&quot;283&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTNS2Q/btqAm4Bf614/FtmrkjrysiS3WaFpIlFA4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTNS2Q/btqAm4Bf614/FtmrkjrysiS3WaFpIlFA4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTNS2Q/btqAm4Bf614/FtmrkjrysiS3WaFpIlFA4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTNS2Q%2FbtqAm4Bf614%2FFtmrkjrysiS3WaFpIlFA4K%2Fimg.png&quot; data-filename=&quot;이미지 15.png&quot; data-origin-width=&quot;569&quot; data-origin-height=&quot;283&quot; data-ke-mobilestyle=&quot;widthContent&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;위와 같은 문제로 인해 날기와, 짖기의 행동 자체를 구현이 아닌 &lt;code&gt;inteface(API)&lt;/code&gt;로 정의해 사용하는 방식을 사용합니다.&lt;/p&gt;
&lt;h5&gt;4-2. fly() 관련 전략 생성&lt;/h5&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;public interface FlyStrategy {
    public void fly();
}

public class FlyWithWingStrategy implements FlyStrategy {
    @Override
    public void fly() {
        System.out.println(&quot;오리가 날아가고 있습니다.&quot;);
    }
}

public class FlyNoWayStategy implements FlyStrategy {
    @Override
    public void fly() {
        System.out.println(&quot;이 오리는 날 수 없습니다.&quot;);

    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이렇게 행동 자체를 캡슐화해버리는 방식입니다. 마찬가지로 분리시킨 행동인 짖기에 관해서도 추가해주면 됩니다.&lt;br /&gt;그리고 &lt;code&gt;Duck&lt;/code&gt;에서 직접적으로 구현했던 &lt;code&gt;fly()&lt;/code&gt;부분을 아래와 같이 인터페이스를 comsition (구성)해주고, 해당 인터페이스의 메소드를 사용하는 방식으로 변경합니다.&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public abstract class Duck {

    private FlyStrategy flyStrategy;

    public void fly() { flyStrategy.fly();}

    public void swim() { System.out.println(&quot;오리가 수영을 합니다.&quot;) ; }

    public abstract void display();

    public void setFlyStrategy(FlyStrategy flyStrategy) {
        this.flyStrategy = flyStrategy;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;여기서 Strategy를 초기화하는 방식으로는 하위 클래스에서 생성자로 컨트롤할 수도 있고 그건 상황에 따라서 사용하시면 될 것 같습니다. 이렇게 사용하면 아래와 같이 사용이 가능하며, 행동을 원할 때 변경할 수 있습니다.&lt;/p&gt;
&lt;h5&gt;4-3. Main 클래스&lt;/h5&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {
        MallardDuck mallarDuck = new MallardDuck();

        mallarDuck.setFlyStrategy(new FlyWithWingStrategy());
        mallarDuck.fly();

        mallarDuck.setFlyStrategy(new FlyNoWayStategy());
        mallarDuck.fly();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;4-4. 실행 결과&lt;/h5&gt;
&lt;pre class=&quot;erlang&quot;&gt;&lt;code&gt;오리가 날아가고 있습니다.
이 오리는 날 수 없습니다.&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;4-5. 람다 표현식으로 리팩토링&lt;/h5&gt;
&lt;p&gt;위 예제에서 전략에 해당하는 &lt;code&gt;FlyStrategy&lt;/code&gt; 인터페이스는 선언된 메서드가 1개뿐이기 때문에, 함수형 인터페이스라는 조건에 해당한다. 그래서 람다 표현식으로 &lt;code&gt;4-3&lt;/code&gt;의 코드를 아래처럼 변화 가능&lt;/p&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;    mallarDuck.setFlyStrategy(() -&amp;gt; System.out.println(&quot;오리가 날아가고 있습니다.&quot;));
    mallarDuck.fly();

    mallarDuck.setFlyStrategy(() -&amp;gt; System.out.println(&quot;오리가 날아가고 있습니다.&quot;));
    mallarDuck.fly();&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;다만, 구현해야하는 내용이 지역변수를 참조한다거나, 복잡한 과정, 재사용이 많을 경우는 기존의 방식처럼 클래스를 이용한 방법이 조금 더 나을 수 있다. 전략 패턴의 경우 람다로도 사용이 가능하다고 인지하고, 상황에 맞는 방식을 사용하는 것을 권장합니다. &lt;a href=&quot;https://lee1535.tistory.com/137?category=816289&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;람다란&lt;/a&gt;&lt;/p&gt;
&lt;h5&gt;왜 사용하는 것일까?&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;위임이라는 느슨한 연결을 사용하고 있으므로 알고리즘을 용이하게 교환할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;5. 관련 패턴&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Flyweight&lt;/code&gt;패턴 : ConcreteStrategy 역할은 해당 패턴을 사용해서 복수의 장소에서 공유 가능&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Abstract Factory&lt;/code&gt; 패턴 : 알고리즘뿐만 아니라 공장, 부품, 제품을 모두 교체 가능&lt;/li&gt;
&lt;li&gt;&lt;code&gt;State&lt;/code&gt; 패턴 : 비슷한 방식이지만, 알고리즘이 아닌 '상태' 를 변화하는 방식을 위임&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;6. 비교하기&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;디자인 패턴을 배우다 보니까 Strategy , Template Method 가 얼핏 보면 비슷하다고 느낌이 들어서 차이점을 정리합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Strategy : 알고리즘을 구성으로 사용.&lt;b&gt;유연성&lt;/b&gt;&lt;a href=&quot;https://lee1535.tistory.com/93?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Template Method : 알고리즘을 서브클래스에서 일부 지정할 수 있으면서 재사용이 가능, 하지만 의존성이 크다는 문제가 발생. &lt;b&gt;재사용&lt;/b&gt;&lt;a href=&quot;https://lee1535.tistory.com/73?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>PROGRAMMING/디자인패턴</category>
      <category>Head First Design Pattern</category>
      <category>Strategy Pattern</category>
      <category>디자인패턴</category>
      <category>알고리즘 분리</category>
      <category>자바</category>
      <category>자바로 배우는 design pettern 입문</category>
      <category>전략패턴</category>
      <category>행동분리</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/93</guid>
      <comments>https://lee1535.tistory.com/93#entry93comment</comments>
      <pubDate>Wed, 11 Dec 2019 13:21:47 +0900</pubDate>
    </item>
    <item>
      <title>[자바/알고리즘] 프로그래머스 문자열 내 p와 y의 개수</title>
      <link>https://lee1535.tistory.com/91</link>
      <description>&lt;h1&gt;문제 설명&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;대문자와 소문자가 섞여있는 문자열 &lt;code&gt;s&lt;/code&gt;가 주어집니다. &lt;code&gt;s&lt;/code&gt;에 문자 'p'와 'y'의 개수를 비교해 같으면 True, 다르면 False를 return 하는 solution를 완성하세요, 'p', 'y' 모두 하나도 없는 경우는 항상 True를 리턴합니다. 단, 개수를 비교할 때 대문자와 소문자는 구별하지 않습니다.&lt;/p&gt;
&lt;p&gt;예를 들어 &lt;code&gt;s&lt;/code&gt;가 &quot;pPoooyY&quot;면 true를 return하고 &quot;Pyy&quot;라면 false를 return합니다.&lt;/p&gt;
&lt;h1&gt;제한사항&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;문자열 s의 길이 : 50 이하의 자연수&lt;/li&gt;
&lt;li&gt;문자열 s는 알파벳으로만 이루어져 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;입출력 예&lt;/h1&gt;
&lt;hr /&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 57px;&quot; border=&quot;1&quot; data-ke-style=&quot;style8&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 19px;&quot;&gt;&lt;b&gt;S&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 19px;&quot;&gt;&lt;b&gt;answer&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 19px;&quot;&gt;&quot;pPoooyY&quot;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 19px;&quot;&gt;true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 19px;&quot;&gt;&quot;Pyy&quot;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 19px;&quot;&gt;false&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;입출력 예 설명&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;입출력 예 #1
&lt;ul&gt;
&lt;li&gt;'p'의 개수 2개, 'y'의 개수 2개로 같으므로 true를 return 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;입출력 예 #2
&lt;ul&gt;
&lt;li&gt;'p'의 개수 1개, 'y'의 개수 2개로 다르므로 false를 return 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;나의 풀이&lt;/h1&gt;
&lt;hr /&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;class Solution {
    boolean solution(String s) {

        boolean answer = true;

        int cnt1 = 0;
        int cnt2 = 0;

        for(int i = 0; i &amp;lt; s.length(); i++){
            if(Character.toUpperCase(s.charAt(i)) == 'P'){
                cnt1++;
            } else if(Character.toUpperCase(s.charAt(i)) =='Y'){
                cnt2++;
            }
        }

        if(cnt1 != cnt2) {
            answer = false;
        }

        return answer;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;풀이 설명&lt;/h5&gt;
&lt;p&gt;아무 값도 없을경우 true를 반환한다는 조건 때문에 answoer을 true로 초기화 해줍니다. 그 후 대소문자 구분을 안하고 값을 비교 하기 위해 &lt;code&gt;Character&lt;/code&gt; 래퍼 클래스의 &lt;code&gt;toUpperCase(char)&lt;/code&gt; 메소드를 통해 값을 비교 후 카운터 변수를 증가시켜줍니다.&lt;br /&gt;마지막으로 값이 같은지 다른지를 비교해 리턴해줍니다.&lt;/p&gt;</description>
      <category>알고리즘/프로그래머스</category>
      <category>level1</category>
      <category>p와y의 개수</category>
      <category>레벨1</category>
      <category>문자열 비교</category>
      <category>알고리즘</category>
      <category>자바</category>
      <category>프로그래머스</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/91</guid>
      <comments>https://lee1535.tistory.com/91#entry91comment</comments>
      <pubDate>Tue, 10 Dec 2019 17:20:25 +0900</pubDate>
    </item>
    <item>
      <title>[자바/알고리즘] 프로그래머스 두 정수 사이의 합</title>
      <link>https://lee1535.tistory.com/90</link>
      <description>&lt;h1&gt;문제 설명&lt;/h1&gt;
&lt;hr&gt;
&lt;p&gt;두 정수 &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt; 가 주어졌을 때 &lt;code&gt;a&lt;/code&gt;와 &lt;code&gt;b&lt;/code&gt; 사이에 속한 모든 정수의 합을 리턴하는 함수, solution을 완성하세요.&lt;br&gt;예를 들어 &lt;code&gt;a = 3&lt;/code&gt;, &lt;code&gt;b = 5&lt;/code&gt; 인 경우, 3 + 4 + 5 = 12 이므로 12를 리턴합니다.&lt;/p&gt;
&lt;h1&gt;제한 조건&lt;/h1&gt;
&lt;hr&gt;
&lt;ul&gt;
&lt;li&gt;a와 b가 같은 경우는 둘 중 아무 수나 리턴하세요.&lt;/li&gt;
&lt;li&gt;a와 b는 -10,000,000 이상 10,000,000 이하인 정수입니다.&lt;/li&gt;
&lt;li&gt;a와 b의 대소관계는 정해져있지 않습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;입출력 예&lt;/h1&gt;
&lt;hr&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-style=&quot;style8&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;b&gt;a&lt;/b&gt;&lt;/td&gt;&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;b&gt;b&lt;/b&gt;&lt;/td&gt;&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;b&gt;return&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width: 33.3333%;&quot;&gt;3&lt;/td&gt;&lt;td style=&quot;width: 33.3333%;&quot;&gt;5&lt;/td&gt;&lt;td style=&quot;width: 33.3333%;&quot;&gt;12&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width: 33.3333%;&quot;&gt;3&lt;/td&gt;&lt;td style=&quot;width: 33.3333%;&quot;&gt;3&lt;/td&gt;&lt;td style=&quot;width: 33.3333%;&quot;&gt;3&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width: 33.3333%;&quot;&gt;5&lt;/td&gt;&lt;td style=&quot;width: 33.3333%;&quot;&gt;3&lt;/td&gt;&lt;td style=&quot;width: 33.3333%;&quot;&gt;12&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;

&lt;h1&gt;나의 풀이&lt;/h1&gt;
&lt;hr&gt;
&lt;pre&gt;&lt;code&gt;class Solution {
  public long solution(int a, int b) {
      long answer = 0;
      int maxNum = (a &amp;gt;= b ? a : b);
      int minNum = (a &amp;lt;=b ? a : b);

      for(int i = minNum ; i &amp;lt;= maxNum; i++){
          answer+= i;
      }
      return answer;
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;h5&gt;풀이 설명&lt;/h5&gt;
&lt;p&gt;대학교 시절 한참 삼항 연산자를 배울때 풀었던 문제인지라, 삼항 연산자를 통해 최대 값과 최소값을 구해 누계를 하는 방식으로 풀었던거 같다.&lt;br&gt;다른 사람들은 &lt;code&gt;Math.min()&lt;/code&gt;, 함수와 &lt;code&gt;Math.max()&lt;/code&gt;함수를 통해 최대값, 최소값을 구하고, 값 누계 부분은 등차수열의 합 공식을 사용해 `(b - a + 1 ) * ( a - b ) / 2; 값을 리턴한 사람들도 많았다.&lt;br&gt;역시 프로그래밍의 연산 최적화랑 수학은 밀접한 관계가 있는거 같다.&lt;/p&gt;</description>
      <category>알고리즘/프로그래머스</category>
      <category>math</category>
      <category>max()</category>
      <category>min()</category>
      <category>두 정수 사이의 합</category>
      <category>등차수열의 합</category>
      <category>삼항연산자</category>
      <category>알고리즘</category>
      <category>자바</category>
      <category>프로그래머스</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/90</guid>
      <comments>https://lee1535.tistory.com/90#entry90comment</comments>
      <pubDate>Tue, 10 Dec 2019 17:11:32 +0900</pubDate>
    </item>
    <item>
      <title>[JAVA/JPA] 연관관계 매핑</title>
      <link>https://lee1535.tistory.com/89</link>
      <description>&lt;p&gt;해당 내용은 인프런의 &lt;code&gt;자바 ORM 표준 JPA 프로그래밍 - 기본편, 김영한&lt;/code&gt; 의 내용을 기반으로 정리해서 작성한 글입니다.&lt;br /&gt;자세한 내용은 해당 강의 또는 책을 구매하시는걸 추천합니다.&lt;/p&gt;
&lt;h2&gt;테이블과 객체 사이의 간격&lt;/h2&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;code&gt;TEAM&lt;/code&gt;테이블과 &lt;code&gt;MEMBER&lt;/code&gt;테이블이 있다고 가정하고, &lt;code&gt;MEMBER&lt;/code&gt;테이블은 &lt;code&gt;TEAM&lt;/code&gt;을 기본키를 외래키로 가지고 있는 N:1의 관계일 때 기존의 방식으로 객체를 테이블의 데이터 기준으로 작성하면 아래와 같이 사용함 ( Mybaits 등)&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;public class Member{

    private Long memberId;
    private Long teamId;
    private String memberName;
}

public class Team{ 

    private Long teamId;
    private String teamName;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같은 경우 객체끼리의 참조가 끊김, 예를들어 &lt;code&gt;Member&lt;/code&gt;에서 &lt;code&gt;member.getTeam()&lt;/code&gt;등과 같이 연관 관계가 있는 객체끼리 참조가 불가능함. 이는 객체적인 모델링이 아니다. 이와 같은 이격이 존재하는 이유는 테이블과 객체의 아래와 같은 차이점 때문&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;테이블은 외래키로 조인( 키값의 데이터 )을 사용해서 연관된 테이블을 찾는다.&lt;/li&gt;
&lt;li&gt;객체는 참조를 사용해서 연관된 객체를 찾는다&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;위와 같은 차이점말고, 테이블은 사실상 기본키 값이든 외래키 값이든 키값을 통해 방향에 상관없이 테이블에서 식별이 가능하다.&lt;br /&gt;그러나 객체의 경우 참조는 단방향일 수 밖에 없다. 예를들어 아래와 같이 객체가 존재할 경우&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class Member{

    private Long memberId;
    private Team team;
    private String memberName;

    public Team getTeam(){ this.team }
}

public class Team{ 

    private Long teamId;
    private String teamName;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이제는&lt;code&gt;Member&lt;/code&gt;에 단순 키값 &lt;code&gt;Long teamId&lt;/code&gt;가 아닌 &lt;code&gt;Team&lt;/code&gt; 객체 자체를 넣었기 때문에 &lt;code&gt;Member.getTeam()&lt;/code&gt;을 통해서 객체의 참조가 가능하다. 그러나 &lt;code&gt;Team&lt;/code&gt;의 경우 &lt;code&gt;Member&lt;/code&gt;을 참조할 수 없다. 이것이 일반적인 객체의 참조이고, 객체의 참조는 테이블과 다르게 단방향으로만 가능&lt;/p&gt;
&lt;p&gt;그렇다면 객체는 양쪽으로는 참조가 불가능할까? 아니다 각 테이블의 관계를 고려해서 아래와 같이 수정하면 양방향으로도 객체의 참조가 가능해진다. 예제는 &lt;code&gt;Member&lt;/code&gt;와 &lt;code&gt;Team&lt;/code&gt;이 N:1의 관계라고 가정해본다.&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;public class Member{

    private Long memberId;
    private Team team;
    private String memberName;

    public Team getTeam(){ return this.team }
}

public class Team{ 

    private Long teamId;
    private String teamName;
    private List&amp;lt;Member&amp;gt; members = ArrayList&amp;lt;&amp;gt;();

    public List&amp;lt;Member&amp;gt; getMembers() { return this.members; } 
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같이 객체를 설계할 경우, 단방향이 서로 설정이 되며, 이를 양방향이라고 표현한다. 이제 기존의 데이터 지향에서 객체지향으로 설계를 바꿨고, 이제 JPA의 입장에서 생각을 해보자. 만일 &lt;code&gt;Member&lt;/code&gt;의 &lt;code&gt;team&lt;/code&gt;과 &lt;code&gt;Team&lt;/code&gt;의 &lt;code&gt;members&lt;/code&gt; 중 어느 값이 변경 되었을 경우 테이블에 영향을 주어야 할까? 이를 설정해주는 것이 이번장의 핵심 &lt;code&gt;연관관계 주인&lt;/code&gt;을 지정해주는 것이다.&lt;/p&gt;
&lt;h2&gt;연관관계 주인&lt;/h2&gt;
&lt;p&gt;기존의 &lt;code&gt;Member&lt;/code&gt;와 &lt;code&gt;Team&lt;/code&gt;을 엔티티로 변경하면 아래와 같이 변경할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;@Enity
public class Member{

    @Id @GeneratedValue
    @Column( name = &quot;member_id&quot;)
    private Long id;

    @ManyToOne
    @JoinColumn( name = &quot;team_id&quot;)
    private Team team;
    private String memberName;

    // 기타 필요 메소드 getter(), setter() 등
}

@Enity
public class Team{ 

    @Id @GeneratedValue
    @Column( name = &quot;team_id&quot;)
    private Long id;
    private String teamName;

    @OneToMany(mappedBy = &quot;team&quot;)
    private List&amp;lt;Member&amp;gt; members = ArrayList&amp;lt;&amp;gt;();

    // 기타 필요 메소드 getter(), setter() 등
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;주목해야 할 어노테이션은 &lt;code&gt;@ManyToOne&lt;/code&gt;, &lt;code&gt;@OneToMany&lt;/code&gt;, &lt;code&gt;@JoinColumn&lt;/code&gt; 이 3가지이다. &lt;code&gt;@ManyToOne&lt;/code&gt;, &lt;code&gt;@OneToMany&lt;/code&gt;의 경우 이름처럼 테이블의 관계가 1:N인지 N:1인지 N:M인지 등 관계를 표현하는 어노테이션이고, &lt;code&gt;@JoinColumn&lt;/code&gt; 어노테이션을 통해 해당 연관관계에서의 주인을 지정해주는 어노테이션이다.&lt;/p&gt;
&lt;p&gt;또한 현재 양방향 연관관계이기 때문에 &lt;code&gt;@OneToMany&lt;/code&gt;에 &lt;code&gt;mappedBy&lt;/code&gt; 속성을 통해서 연관관계의 주인이 아닌 반대 방향이라는 설정을 해줘야 한다.&lt;/p&gt;
&lt;p&gt;위와 같이 설정하게 되면 &lt;b&gt;연관관계의 주인을 설정할 경우에만 JPA가 테이블의 값을 변경하고, mappedBy로 설정된 값은 조회만 가능하게 된다.&lt;/b&gt;&lt;/p&gt;
&lt;h5&gt;누구를 연관관계 주인으로?&lt;/h5&gt;
&lt;p&gt;&lt;b&gt;외래키가 있는 곳을 연관관계 주인으로 지정해라.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;사실 객체의 입장에서 누구든 연관관계의 주인이 될 수 있지만, 테이블 기준 &lt;code&gt;외래키&lt;/code&gt;가 들어가는 엔티티를 연관관계의 주인으로 설정하기를 권장한다. 아닐 경우 아래와 같은 문제가 발생&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;team을 연관관계 주인으로 설정할 경우
&lt;ul&gt;
&lt;li&gt;성능상의 이슈, Team을 변경해도 Member의 update 쿼리가 발생한다.&lt;/li&gt;
&lt;li&gt;team을 변경해도 member 테이블을 조작하는 쿼리가 발생해 개발 시 헷갈리게 된다. 즉 직관적이지가 않다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;주의할 점&lt;/h5&gt;
&lt;p&gt;위와 같이 연관관계 주인을 설정하고, &lt;code&gt;mappedBy&lt;/code&gt; 속성을 통해 양방향 연관관계를 설정할 수 있게 되었다.&lt;br /&gt;그렇지만 양방향 연관관계의 경우 아래와 같은 주의점이 발생한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;toString(), lombok 사용시 무한 루프에 빠지게 된다. 재정의가 필요할 경우 양방향 연관관계를 고려해서 재정의 할 것&lt;/li&gt;
&lt;li&gt;JSON 라이브러리를 통해 생성시에도 무한루프에 빠진다. 그래서 컨트롤러에서 entity를 반환하지 말고 DTO를 사용해라&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;비지니스 로직상 add할때 내가 있는지 체크 후 빼고, 추가 이런 로직이 필요하면 추가로 changeTeam에 설정..&lt;/p&gt;
&lt;p&gt;실제는 단방향으로 모든 엔티티를 설계하고 필요에 의해서만 양방향을 고려해라.. 추가로 수정해도 기존 로직에 영향이 없음.. 그러나 JPQL에서 역방향으로 탐색할 일이 많기 때문에&lt;/p&gt;
&lt;h2&gt;가장 많이 하는 실수&lt;/h2&gt;
&lt;p&gt;연관관계 주인이 아닌곳은 조회만 가능한 점을 잘 생각하고 아래와 같은 로직이 있을 때 어떤 문제가 발생할까?&lt;/p&gt;
&lt;pre class=&quot;fsharp&quot;&gt;&lt;code&gt;Team team = new Team();
em.persist(team);

Member member = new Member();

// 주인이 아닌 역방향만 연관관계 설정
team.getMembers().add(member);

em.persist(member);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같이 작성시 &lt;code&gt;mappedBy&lt;/code&gt;로 설정된 읽기전용 필드에만 값을 설정 시 &lt;code&gt;MEMBER&lt;/code&gt; 테이블에 &lt;code&gt;TEAM&lt;/code&gt;의 키 값이 null로 등록되는 현상이 발생, 그렇기 때문에 아래와 같이 수정&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;Team team = new Team();
em.persist(team);

Member member = new Member();
member.setTeam(team); // !!! 중요 연관관계 주인에 값을 넣어야함 !!!

// team.getMembers().add(member); 없어도 되지만 둘다 설정하는게 좋다.

em.persist(member);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;team.getMember()&lt;/code&gt;의 경우 사실상 값을 설정해주지 않아도, JPA가 알아서 지연로딩 기법을 사용해 값을 참조하는 순간 알아서 값이 불러온다. 그치만 이와 같이 사용하면 JPA 메커니즘에 의해 오류가 발생 했을 때 값이 테이블과 동일하지 않는 문제가 발생할 수 있기 때문에 양쪽에 다 넣어주는게 유리하다. 또한 테스트 케이스 작성 시 한쪽으로만 데이터가 있는 경우가 발생하기 때문에 둘다 값을 넣어주는걸 추천&lt;/p&gt;
&lt;h5&gt;JPA 메커니즘에 의한 오류&lt;/h5&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;Team team = new Team();
em.persist(team);

Member member = new Member();
member.setTeam(team); 

em.persist(member);

Team findTeam = em.find(Team.class, team.getId()); // 1차 캐쉬
List&amp;lt;Member&amp;gt; member = findTeam.getMembers();&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같이 동작할때 JPA 메커니즘에 의해 &lt;code&gt;em.persist(team)&lt;/code&gt;로 등록된 엔티티는 DB에 저장되는게 아닌, 영속 컨텍스트에 저장되기 때문에 당연히 &lt;code&gt;em.find(Team.class, team.getId()&lt;/code&gt;를 통해 불러와도 당연히 DB가 아닌 영속 컨텍스트에서 값일 받아옴.&lt;br /&gt;그럼 해당 객체는 &lt;code&gt;team.getMembers().add(member)&lt;/code&gt;를 실행하지 않았기 때문에 당연히 null을 반환 em.find()도 같은 객체를 반환하기 때문에 null 문제가 발생 그렇기 때문에 양쪽에 넣어주는게 좋다.&lt;/p&gt;
&lt;p&gt;위와 같은 방법이 아니면 연관관계 편의 메소드를 만들것을 고려해라&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;// Member Entity
public void change(Team team) {
    this.team = team;
    team.getMembers().add(this);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;또는 &lt;code&gt;Team&lt;/code&gt; 엔티티에 설정해도 상관은 없다. 단 둘중 한곳에만 설정할 것!&lt;br /&gt;또한 &lt;code&gt;List&lt;/code&gt;를 사용하기 때문에 로직에 따라 기존의 &lt;code&gt;List&lt;/code&gt;에 값이 있으면 찾아서 제거하고, 추가하기 등 필요한 로직은 비니니스 로직에 따라 추가해줘야 하는 경우도 생긴다.&lt;/p&gt;
&lt;h2&gt;정리&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;객체와 테이블의 차이점 이해&lt;/li&gt;
&lt;li&gt;연관관계 설정 ( 연관관계 주인 파악하기 )
&lt;ul&gt;
&lt;li&gt;외래키를 가진 테이블의 엔티티를 연관관계 주인으로&lt;/li&gt;
&lt;li&gt;연관관계에서 데이터 조작시 JPA 메커니즘을 이해하고 조작하기 ( 주인만 테이블을 조작 )&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;toString, lombok, JSON 사용시 무한참조 주의&lt;/li&gt;
&lt;li&gt;엔티티는 단방향으로 전부 설계, 필요 시 양방향을 추가할 것 그래도 기존의 테이블에 수정이 없기 때문에 필요시에 추가해도 충분하다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>PROGRAMMING/JAVA</category>
      <category>JPA</category>
      <category>객체와테이블차이</category>
      <category>김영한</category>
      <category>매핑</category>
      <category>연관관계</category>
      <category>연관관계주인</category>
      <category>외래키</category>
      <category>인프런</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/89</guid>
      <comments>https://lee1535.tistory.com/89#entry89comment</comments>
      <pubDate>Mon, 9 Dec 2019 22:36:21 +0900</pubDate>
    </item>
    <item>
      <title>[JAVA/JPA] Entity Mapping  방법</title>
      <link>https://lee1535.tistory.com/88</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;해당 내용은 인프런의 &lt;code&gt;자바 ORM 표준 JPA 프로그래밍 - 기본편, 김영한&lt;/code&gt; 의 내용을 기반으로 정리해서 작성한 글입니다.&lt;br /&gt;자세한 내용은 해당 강의 또는 책을 구매하셔서 알아보시는걸 추천합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;사용 어노테이션&lt;/h1&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체와 테이블 매핑 : &lt;b&gt;@Entity&lt;/b&gt; , &lt;b&gt;@Table&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;필드와 컬럼 매핑 : &lt;b&gt;@Column, @Enumerated, @Temporal, @Lob, @Treansient&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;기본 키 패킹 : &lt;b&gt;@Id&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;연관관계 매핑 : &lt;b&gt;@ManyToOne&lt;/b&gt;, &lt;b&gt;@JoinColumn&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;객체와 테이블 매핑&lt;/h1&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;@Entity&lt;/h3&gt;
&lt;h5&gt;정의 : JPA가 관리하는 객체라고 선언하는 어노테이션&lt;/h5&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본 생성자 ( &lt;code&gt;public&lt;/code&gt;, &lt;code&gt;protected&lt;/code&gt; ) 가 필수로 있어야 ( 리플렉션이나 여러 기술을 사용할 때 필요 )&lt;/li&gt;
&lt;li&gt;final, enum, interface, inner 클래스는 사용 불가능&lt;/li&gt;
&lt;li&gt;필드에도 final 키워드 사용 불가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;속성&lt;/h5&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;name&lt;/code&gt;라는 속성이 사용가능하며. Default로 클래스 이름으로 지정, 다른 패키지내 같은 클래스이름이 있을 경우 둘을 구분하기 위해 사용한다.&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;import javax.persistence.Entity;
@Entity( name = &quot;Member&quot; )
public class Member {
    public Member() { }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;@Table&lt;/h3&gt;
&lt;h5&gt;정의 : &lt;code&gt;Entity&lt;/code&gt;와 매핑될 DB 테이블에 대한 설정&lt;/h5&gt;
&lt;h5&gt;속성&lt;/h5&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-style=&quot;style8&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;b&gt;속성&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;b&gt;기능&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;b&gt;기본값&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;name&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;매핑할 테이블 이름&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;Entity 의 name&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;catalog&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;데이터베이스 catalog 매핑&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;schema&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;데이터베이스 schema 매핑&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;uniqueConstraints(DDL)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;DDL 생성 시에 유니크 제약 조건 생성&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;필드와 컬럼 매핑&lt;/h1&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 120px;&quot; border=&quot;1&quot; data-ke-style=&quot;style8&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 32.907%; height: 20px;&quot;&gt;&lt;b&gt;어노테이션&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 67.093%; height: 20px;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 32.907%; height: 20px;&quot;&gt;@Column&lt;/td&gt;
&lt;td style=&quot;width: 67.093%; height: 20px;&quot;&gt;컬럼과 매핑&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 32.907%; height: 20px;&quot;&gt;@Temporal&lt;/td&gt;
&lt;td style=&quot;width: 67.093%; height: 20px;&quot;&gt;날짜 타입 컬럼과 매핑&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 32.907%; height: 20px;&quot;&gt;@Enumerated&lt;/td&gt;
&lt;td style=&quot;width: 67.093%; height: 20px;&quot;&gt;enum 타입과 컬럼 매핑&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 32.907%; height: 20px;&quot;&gt;@Lob&lt;/td&gt;
&lt;td style=&quot;width: 67.093%; height: 20px;&quot;&gt;BLOB, CLOB 매핑&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 32.907%; height: 20px;&quot;&gt;@Transient&lt;/td&gt;
&lt;td style=&quot;width: 67.093%; height: 20px;&quot;&gt;필드와 컬럼 매핑 제외&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;@Column&lt;/h3&gt;
&lt;h5&gt;속성&lt;/h5&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;name&lt;/code&gt; : 테이블에 매칭시킬 컬럼 이름 ( default : 필드명 )&lt;/li&gt;
&lt;li&gt;&lt;code&gt;insertable&lt;/code&gt;, &lt;code&gt;updateable&lt;/code&gt; : 등록, 변경 여부 ( default : true )&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nullable&lt;/code&gt; : null 값의 허용 여부, false로 설정시 DDL 생성 시에 not null 제약 조건이 자동 생성&lt;/li&gt;
&lt;li&gt;&lt;code&gt;unique&lt;/code&gt; : @Table의 unique 속성과 같지만 컬럼에도 선언 가능
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단 실무에서는 Unique 제약조건명이 자동으로 생성되기 때문에 사용을 안함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;columnDefinition&lt;/code&gt; : 데이터베이스에 컬럼 정보를 직접 생성&lt;/li&gt;
&lt;li&gt;&lt;code&gt;length&lt;/code&gt; : 문자 컬럼의 길이 제약조건, String 타입에서만 사용가능 (default : 255 )&lt;/li&gt;
&lt;li&gt;&lt;code&gt;precision&lt;/code&gt;,&lt;code&gt;scale&lt;/code&gt; : BigDecimal 타입이나 BigInteger에서 사용, double, float불가, 큰숫자나 정밀한 소수점 계산시 사용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;percision : 소수점을 포함한 전체 자릿수&lt;/li&gt;
&lt;li&gt;scale : 소수의 자릿수&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;public class Member {
    @Column( name =&quot;MEM_NAME&quot;, insertable = true, nullable = false
             ,columnDefinition = &quot;varchar2(200) default 'NONE'&quot;, length = 255)
    private String name;
    @Column(percision = 19 )
    private BigDecimal age;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;@Enumerated&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Enum 타입을 매핑할 때 사용 속성으로는 &lt;code&gt;ORDINAL&lt;/code&gt; 과 &lt;code&gt;STRING&lt;/code&gt;를 사용하지만, &lt;code&gt;STRING&lt;/code&gt;만 사용할 것 enum 순서에 변화가 생겼을 때, 순서로 저장할 경우 데이터 불일치 발생
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ORDINAL : enum 순서를 저장&lt;/li&gt;
&lt;li&gt;STRING : enum 이름을 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;@Temporal&lt;/h3&gt;
&lt;h5&gt;정의 : 날짜 타입 Date, Calendar 을 매핑, LocalDate, LocalDateTime을 사용할 경우 생략 가능&lt;/h5&gt;
&lt;h5&gt;속성&lt;/h5&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;TemporalType.DATE&lt;/code&gt; : 날짜, DB의 date 타입과 매핑&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TemporalType.TIME&lt;/code&gt; : 시간, DB의 time 타입과 매핑&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TemporalType.TIMESTAMP&lt;/code&gt; : 날짜와 시간, DB의 timestamp와 매핑&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;public class Member {
   @Temporal(TemporalType.TIMESTAMP)
   private Date;

   private LocalDate localDate;
   pirvate LocalDateTime localDateTime;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;@Lob&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DB의 BLOB, CLOB 와 매핑, 지정할 수 있는 속성이 없으며 문자타입이면 CLOB, 나머지는 BLOB로 자동 매핑&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;@Transient&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;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;기본키 매핑&lt;/h1&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;해당 필드를 DB에 사용할 기본키로 선언시 사용, 직접 할당시 &lt;code&gt;@Id&lt;/code&gt;만 선언해주면 되지만, 보통 sequence나 autoincrement 등으로 자동 관리하는 경우가 많은데 그럴 경우 &lt;code&gt;@GeneratedValue&lt;/code&gt;를 같이 사용해줘야 한다.&lt;/p&gt;
&lt;h5&gt;@GeneratedValue의 속성&lt;/h5&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IDENTITY : DB에 위임, autoincrement ( mySQL )&lt;/li&gt;
&lt;li&gt;SEQUECNE : 데이터베이스 시퀀스 sequence 사용 , ORACLE , 추가로 @SequenceGenerator 필요public class Member {}&lt;/li&gt;
&lt;li&gt;&lt;code&gt;  @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = &quot;MEMBER_SEQ_GENERATOR&quot;)
  private Long id; // 값을 주면 안된다.&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;  @Entity
  @SequenceGenerator(
      name = &quot;MEMBER_SEQ_GENERATOR&quot; // sequenceGenerator 이름 지정
      squenceName = &quot;MEMBER_SEQ&quot; // 매핑할 시퀀스 이름
      initialValue = 1, allocationSize = 1 ) // 시작하는 숫자, 증가값 기본으로 50&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;TABLE : 키 테이블 사용, 모든 DB에서 사용 가능하지만, 성능 이슈 발생&lt;/li&gt;
&lt;li&gt;AUTO : 방언에 따라 자동 지정, 기본 값&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;기본키 전략 strategy 의 특징&lt;/h5&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IDENTITY 전략의 특징
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;키값이 자동으로 생성되기 때문에 영속성 컨텍스트는 해당 Entity의 키값을 모른다. ( 영속컨테이너 메커니즘에 의해 ) 그렇기 때문에 &lt;code&gt;commit()&lt;/code&gt;나 &lt;code&gt;flush()&lt;/code&gt;시점이아닌, &lt;code&gt;persist()&lt;/code&gt; 시점에 insert가 발생하고 return 으로 키 값을 받아오기 때문에 별도의 select문은 없음, ( JDBC를 이용 )&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SEQUENCE 전략의 특징
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;IDENTITY&lt;/code&gt;전략과 마찬가지로 DB에 들어가야 키 값을 알 수 있음, 마찬가지로 &lt;code&gt;persist()&lt;/code&gt;시점에 동작하며. &lt;code&gt;SEQUENCE.nextVal()&lt;/code&gt; 호출로 키 값을 가져오며, insert는 기존의 메커니즘과 같이 &lt;code&gt;commit()&lt;/code&gt;, &lt;code&gt;flush()&lt;/code&gt;에 동작, 그래서 &lt;code&gt;allocationSize&lt;/code&gt;가 default로 50으로 잡혀 있는것!, 불필요하게 DB에 접근해서 sequence값을 가져오지 않고, 버퍼 기능도 사용가능하고, 동시성도 제어 가능&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;h1&gt;데이터베이스 스키마 자동 생성&lt;/h1&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;객체를 Entity로 매핑을 설정해놓으면 컴파일 단계에서 자동으로 DB에 테이블 생성 ( DDL ) 문을 동작, 개발 환경에서만 사용할 것을 권장&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-style=&quot;style8&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;b&gt;옵션&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;create&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;기존테이블 삭제 후 다시 생성&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;create-drop&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;create와 같고 종료 시점에 drop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;update&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;변경된 부분만 반영&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;validate&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;엔티티와 테이블 정상 매핑 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;none&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;사용 x&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</description>
      <category>PROGRAMMING/JAVA</category>
      <category>Entity</category>
      <category>Field</category>
      <category>id</category>
      <category>Java</category>
      <category>JPA</category>
      <category>mapping</category>
      <category>table</category>
      <category>매핑</category>
      <category>자바</category>
      <category>필드</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/88</guid>
      <comments>https://lee1535.tistory.com/88#entry88comment</comments>
      <pubDate>Mon, 9 Dec 2019 15:42:07 +0900</pubDate>
    </item>
    <item>
      <title>[JAVA/JPA] 영속성 컨텍스트 EntityManage JPA 동작 방식</title>
      <link>https://lee1535.tistory.com/87</link>
      <description>&lt;p&gt;해당 내용은 인프런의 &lt;code&gt;자바 ORM 표준 JPA 프로그래밍 - 기본편 , 김영한&lt;/code&gt; 의 내용을 기반으로 정리해서 작성한 글입니다.&lt;br /&gt;자세한 내용은 해당 강의 또는 책을 구매하셔서 알아보시는걸 추천합니다.&lt;/p&gt;
&lt;p&gt;해당 글을 읽기전 &lt;a href=&quot;https://lee1535.tistory.com/82&quot;&gt;JPA 기본편&lt;/a&gt; 을 먼저 보시는걸 추천합니다.&lt;/p&gt;
&lt;figure id=&quot;og_1575654617399&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[JAVA/JPA] JPA 와 ORM 기본 개념 Hibernate ORM&quot; data-og-description=&quot;해당 내용은 인프런의 자바 ORM 표준 JPA 프로그래밍-기본편 - 김영한 의 내용을 기반으로 정리해서 작성한 글입니다. 자세한 내용은 해당 강의 또는 책을 구매하셔서 자세히 알아보시는걸 추천합니다. ORM 이란?..&quot; data-og-host=&quot;lee1535.tistory.com&quot; data-og-source-url=&quot;https://lee1535.tistory.com/82&quot; data-og-url=&quot;https://lee1535.tistory.com/82&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/qY55H/hyDZooqvPV/sY4rrbkJyMrDrvhAtYrq61/img.png?width=800&amp;amp;height=215&amp;amp;face=0_0_800_215,https://scrap.kakaocdn.net/dn/cSrRVw/hyD042UFnE/QV9izKEOk2cGu9JqiWsqMK/img.png?width=800&amp;amp;height=215&amp;amp;face=0_0_800_215&quot;&gt;&lt;a href=&quot;https://lee1535.tistory.com/82&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://lee1535.tistory.com/82&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/qY55H/hyDZooqvPV/sY4rrbkJyMrDrvhAtYrq61/img.png?width=800&amp;amp;height=215&amp;amp;face=0_0_800_215,https://scrap.kakaocdn.net/dn/cSrRVw/hyD042UFnE/QV9izKEOk2cGu9JqiWsqMK/img.png?width=800&amp;amp;height=215&amp;amp;face=0_0_800_215');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;[JAVA/JPA] JPA 와 ORM 기본 개념 Hibernate ORM&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;해당 내용은 인프런의 자바 ORM 표준 JPA 프로그래밍-기본편 - 김영한 의 내용을 기반으로 정리해서 작성한 글입니다. 자세한 내용은 해당 강의 또는 책을 구매하셔서 자세히 알아보시는걸 추천합니다. ORM 이란?..&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;lee1535.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h1&gt;EntityManagerFactory와 EntityManager&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;어플리케이션은 단 하나의 &lt;code&gt;EntityManagerFactory&lt;/code&gt;를 가져야함. 즉 어플리케이션이 실행하면 생성하고 종료하면 소멸&lt;/li&gt;
&lt;li&gt;&lt;code&gt;EntityManager&lt;/code&gt;은 하나의 Thread(Transaction)가 생성될 때마다 &lt;code&gt;EntityManagerFactory&lt;/code&gt;가 생성해준다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;EntityManager&lt;/code&gt;은 실제 DB 사용을 담당&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;영속성 컨텍스트 ?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;논리적인 개념, 눈에 보이지 않음&lt;/li&gt;
&lt;li&gt;&lt;code&gt;EntityManager.persist(Entity)&lt;/code&gt;를 사용하면 DB에 저장하는게 아닌 영속성 컨텍스트에 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;엔티티의 생명주기&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;비영속 : 객체가 영속성 컨텍스트와 관련이 없는 상태&lt;br /&gt;아래와 같이 &lt;code&gt;EntityManger&lt;/code&gt;을 통해서 영속성 컨텍스트에 접근하지 않은 상태
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;public void process(){
  Member mbmer = new Member();
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;영속 : 객체에 영속성 컨텍스트에 관리되고 있는 상태&lt;br /&gt;아래와 같이 &lt;code&gt;EntityManger&lt;/code&gt;을 영속성 컨텍스트에 저장시킨 상태
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;public void process(){
  Member mbmer = new Member();
  entityManager.persist(member);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;준영속 : 영속 컨텍스트에 저장되어 있다가 분리된 상태&lt;br /&gt;아래와 같이 &lt;code&gt;EntityManger&lt;/code&gt;을 영속성 컨텍스트에서 객체를 분리시킨 상태
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public void process(){
  Member mbmer = new Member();
  entityManager.detach(member);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;삭제 : 삭제된 상태&lt;br /&gt;아래와 같이 &lt;code&gt;EntityManger&lt;/code&gt;을 영속성 컨텍스트에서 객체를 완전히 삭제시킨 상태
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public void process(){
  Member mbmer = new Member();
  entityManager.remove(member);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;영속성 컨텍스트 사용 이유&lt;/h2&gt;
&lt;p&gt;왜 DB에 바로 저장하지 않고 중간 단계인 영속성 컨텍스트라를 통해서 객체를 저장할까?&lt;br /&gt;아래와 같은 이점이 존재&lt;/p&gt;
&lt;h5&gt;이점&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;b&gt;1차 캐시&lt;/b&gt;&lt;br /&gt;실제 &lt;code&gt;EntityManager.persist(Entity)&lt;/code&gt;를 통해 객체를 저장하면 영속 컨텍스트에 저장만 시킨다&lt;br /&gt;그럼 언제 DB에 접근을 할까? 강조했던 &lt;code&gt;commit&lt;/code&gt;시점에 영속 컨텍스트가 1차 캐쉬에 있는 내용을 한번에 DB에 저장시킨다.&lt;br /&gt;아래와 같은 상황에서 DB 접근이 몇번 생기는지 확인해보자&lt;/p&gt;
&lt;pre class=&quot;fsharp&quot;&gt;&lt;code&gt;public void process(){
   Member member = new Member();
 member.setId(100L);
 entityManager.persist(member);

 Member selectMember = entityManager.find(Member.class, 100L );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;psersist()&lt;/code&gt;를 호출 했으니까 insert를 실행 할거 같고, 키 값이 100인 멤버를 &lt;code&gt;find()&lt;/code&gt;를 통해 select 해올 것 같다. 하지만 영속 컨텍스트 동작 메커니즘에 의해 &lt;code&gt;persist()&lt;/code&gt;시점에 객체는 &lt;b&gt;영속성 컨텍스트&lt;/b&gt;에 저장이 된다.&lt;br /&gt;그 후 &lt;code&gt;find()&lt;/code&gt;호출 시 DB에서 값을 가져오는게 아닌 &lt;b&gt;영속성 컨텍스트&lt;/b&gt;를 참조해서 값을 가져온다. 그리고 마지막 commit 시점에 INSERT 쿼리가 1번만 실행되는 방식으로 동작, 그러나 단위가 트랜잭션 단위이기 때문에 엄청나게 성능 향상은 아님&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ceAS2o/btqAgFoyMCP/hSIOV3MMdhnr0Bv4HbP1f1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ceAS2o/btqAgFoyMCP/hSIOV3MMdhnr0Bv4HbP1f1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ceAS2o/btqAgFoyMCP/hSIOV3MMdhnr0Bv4HbP1f1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FceAS2o%2FbtqAgFoyMCP%2FhSIOV3MMdhnr0Bv4HbP1f1%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;b&gt;객체의 동일성 보장&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public void process(){
   Member member = emtityManager.find(Member.class,100L);
 Member member = emtityManager.find(Member.class,100L);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;1차 캐쉬를 통해 SELECT문도 1번만 발생, 1차 캐쉬를 통해 &lt;code&gt;REPEATABLE READ&lt;/code&gt; 격리수준을 DB 차원이 아닌 어플리케이션 차원에서 제공해줌&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;b&gt;트랜잭션을 지원하는 쓰기 지연&lt;/b&gt;&lt;br /&gt;1번 1차캐시에서 설명한 내용처럼 &lt;code&gt;psersist()&lt;/code&gt;시점에 DB에 INSERT를 실행하는게 아닌 commit 시점에 추가/수정/삭제 쿼리를 발생 시킴, 이는 1차 캐쉬와 별도로 쓰기 지연 SQL 저장소라는 공간에서 SQL문을 관리하기 때문,&lt;br /&gt;이는 버퍼링의 기능을 사용함, DB에 여러번 접속이 아닌 &lt;code&gt;JDBC.batch()&lt;/code&gt; 를 통해 한번에 쿼리를 동작시킴&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/M4Xlp/btqAizm9lTI/ARlQvxUQWSlDtOn1KHvXT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/M4Xlp/btqAizm9lTI/ARlQvxUQWSlDtOn1KHvXT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/M4Xlp/btqAizm9lTI/ARlQvxUQWSlDtOn1KHvXT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FM4Xlp%2FbtqAizm9lTI%2FARlQvxUQWSlDtOn1KHvXT1%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;b&gt;변경 감지 ( Dirty Checking)&lt;/b&gt;&lt;br /&gt;아래와 같은 상황에서 언제 DB에 업데이트가 반영이 될까?&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public void process(){
 Member member = entityManager.find(Memeber.class,100L);
 member.setName(&quot;Lee's GrowUp&quot;);
 // entityManager.persist(member) ; 주석처리
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;사실 객체가 &lt;b&gt;영속&lt;/b&gt;상태인 경우 &lt;code&gt;entityManager.persist()&lt;/code&gt; 메소드 호출 없이 영속성 컨텍스트가 자동으로 UPDATE 쿼리를 발생 시킴, 이는 1차 캐쉬에 객체의&lt;b&gt;스냅샷&lt;/b&gt;을 저장하는 영역이 추가로 있는데, commit 시점 또는 &lt;code&gt;flush()&lt;/code&gt; 시점에 스냅샷과 현재 Entity를 비교해 다르면 UPDATE 쿼리를 발생시킴&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;b&gt;지연 로딩( Lazy Loading )&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public void process(){
   Member member = entityManager.find(Member.class,100L);
 member.getDepartment(); // 필드로 Department 클래스를 가짐
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같이 &lt;code&gt;Member&lt;/code&gt; 클래스가 필드로 &lt;code&gt;Department&lt;/code&gt;를 가지는 경우, &lt;code&gt;find(member)&lt;/code&gt; 시점에는 &lt;code&gt;MEMBER&lt;/code&gt; SELECT만 발생하고, &lt;code&gt;getDepartment()&lt;/code&gt;를 호출하는 순간 &lt;code&gt;DEPARTMENT&lt;/code&gt; 를 SELECT한다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;플러시&lt;/h2&gt;
&lt;p&gt;그렇다면 &lt;code&gt;EntityManager&lt;/code&gt;은 commit에서만 DB에 SQL을 동작시킬까? &lt;code&gt;flush()&lt;/code&gt;를 사용하면 강제로 쓰기지연 SQL 저장소에 있는 SQL 문을 동작시킴&lt;/p&gt;
&lt;h5&gt;동작시점&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;entityManager.flush() 호출&lt;/li&gt;
&lt;li&gt;트랜잭션 커밋 : 자동호출&lt;/li&gt;
&lt;li&gt;JPQL 쿼리 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;위와 같은 경우에 &lt;code&gt;flush()&lt;/code&gt;가 동작하며 영속성 컨텍스트에있는 값은 변경이 없고 쓰기지연 SQL 저장소의 값만 DB와 연동시키고 초기화 한다고 생각하면 됩니다.&lt;br /&gt;보시면 &lt;code&gt;JPQL&lt;/code&gt;이라고 JPA에서 지원하는 SQL 언어에서도 &lt;code&gt;flush()&lt;/code&gt;가 동작한다고 했는데 이유는 무엇일까?&lt;br /&gt;아래 코드를 보시면 문제점이 보일겁니다.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;  public void process(){
      entityManager.persist(member1);
    entityManager.persist(member2);

    query = entityManger.createQuery(&quot;select m from member m&quot;,Member.class);
    List&amp;lt;Member&amp;gt; members = query.getResultList();
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같은 코드에서 영속성 컨텍스트의 메커니즘을 이해하셨으면 문제가 보이실겁니다. 바로 해당 로직에서는 &lt;code&gt;flush()&lt;/code&gt;가 동작하지 않았습니다. 즉, &lt;code&gt;member1&lt;/code&gt;과&lt;code&gt;member2&lt;/code&gt;는 현재 DB에 저장되어 있지 않은 상태에서 쿼리를 실행해 DB에 값을 불러올 경우 데이터가 누락되는 현상이 발생하기 때문에 예외적으로 &lt;code&gt;JPQL&lt;/code&gt;에서도 &lt;code&gt;flush()&lt;/code&gt;가 동작합니다.&lt;/p&gt;
&lt;h5&gt;플러시 모드 설정&lt;/h5&gt;
&lt;p&gt;단 위와 같은 동작 방식이 불필요한경우, &lt;code&gt;JPQL&lt;/code&gt;에서 &lt;code&gt;flush()&lt;/code&gt;가 동작하지 않게 하는 방법도 존재합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;em.setFlushMode(FlushModeType.COMMIT)&lt;/code&gt; : 커밋시점에만 동작&lt;/li&gt;
&lt;li&gt;&lt;code&gt;em.setFlushMode(FlushModeType.AUTO)&lt;/code&gt; : 기본 동작&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;준영속 상태&lt;/h2&gt;
&lt;p&gt;영속성 컨텍스트에서 분리시킴으로써 필요한 로직에서 사용&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public void process(){
    Member member = entityManager.find(Member.class,100L);
    member.setName(&quot;changeName&quot;);

    entityManager.detach(member);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;원래라면 메커니즘에 의해 commit 시점에 UPDATE 쿼리가 발생해야 하지만, 해당 로직에서는 SELECT 문만 발생&lt;/p&gt;
&lt;h5&gt;비슷한 기능&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;entityManager.clear() : 영속성 컨텍스트를 전부 초기화&lt;/li&gt;
&lt;li&gt;entityManager.close() : 영속성 컨텍스트를 종료&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>PROGRAMMING/JAVA</category>
      <category>EntityManager</category>
      <category>JPA</category>
      <category>JPA메커니즘</category>
      <category>영속성컨텍스트</category>
      <category>자바</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/87</guid>
      <comments>https://lee1535.tistory.com/87#entry87comment</comments>
      <pubDate>Sat, 7 Dec 2019 02:48:46 +0900</pubDate>
    </item>
    <item>
      <title>[Gradle] Window에 설치 Gradle 설치하기</title>
      <link>https://lee1535.tistory.com/85</link>
      <description>&lt;h1&gt;Gradle&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;code&gt;Gradle&lt;/code&gt;는 &lt;b&gt;빌드 자동화&lt;/b&gt; 시스템으로, 빌드 툴인 &lt;code&gt;Ant Builder&lt;/code&gt;과 &lt;code&gt;Groovy&lt;/code&gt; 스크립트 기반으로 구축&lt;br /&gt;자세한 내용은 아래 위키를 참조하시길 바랍니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Gradle&quot;&gt;https://en.wikipedia.org/wiki/Gradle&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1575613175079&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Gradle - Wikipedia&quot; data-og-description=&quot;Gradle is an open-source build-automation system that builds upon the concepts of Apache Ant and Apache Maven and introduces a Groovy-based domain-specific language (DSL) instead of the XML form used by Apache Maven for declaring the project configuration.&quot; data-og-host=&quot;en.wikipedia.org&quot; data-og-source-url=&quot;https://en.wikipedia.org/wiki/Gradle&quot; data-og-url=&quot;https://en.wikipedia.org/wiki/Gradle&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Gradle&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://en.wikipedia.org/wiki/Gradle&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;&gt;Gradle - Wikipedia&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Gradle is an open-source build-automation system that builds upon the concepts of Apache Ant and Apache Maven and introduces a Groovy-based domain-specific language (DSL) instead of the XML form used by Apache Maven for declaring the project configuration.&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;en.wikipedia.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h1&gt;Gradle 설치하기&lt;/h1&gt;
&lt;hr /&gt;
&lt;h3&gt;1. 다운로드&lt;/h3&gt;
&lt;p&gt;아래 그래들 공식 홈페이지에서 원하는 Releases를 &lt;code&gt;complete&lt;/code&gt;버전으로 다운로드 해주고, 원하는 위치에 압축을 풀어줍니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gradle.org/releases/&quot;&gt;https://gradle.org/releases/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1575613186243&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Gradle | Releases&quot; data-og-description=&quot;Find binaries and reference documentation for current and past versions of Gradle.&quot; data-og-host=&quot;gradle.org&quot; data-og-source-url=&quot;https://gradle.org/releases/&quot; data-og-url=&quot;https://gradle.org/releases/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/7SSap/hyD1bU0mWq/GHwL3LAKXkYYHEcEIR5ZV0/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/bGQnEY/hyD02KwTdm/4ktt8gb6Ip4bALCJdUw6K0/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400&quot;&gt;&lt;a href=&quot;https://gradle.org/releases/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://gradle.org/releases/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/7SSap/hyD1bU0mWq/GHwL3LAKXkYYHEcEIR5ZV0/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/bGQnEY/hyD02KwTdm/4ktt8gb6Ip4bALCJdUw6K0/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Gradle | Releases&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Find binaries and reference documentation for current and past versions of Gradle.&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;gradle.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h3&gt;2. 환경설정&lt;/h3&gt;
&lt;p&gt;자바의 JDK처럼 윈도우에서 gradle를 호출하기 쉽게 PATH를 설정해줍니다.&lt;br /&gt;내PC -&amp;gt; 속성 -&amp;gt; 고급 시스템 설정 -&amp;gt; 고급 -&amp;gt; 환경변수 -&amp;gt; Path -&amp;gt; 편집 후 등록&lt;br /&gt;여기서 등록은 %Gradle 설치경로%\bin 으로 등록해줍니다. &lt;code&gt;( ex : C:\gradle-5.6.4\bin )&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;이미지 6.png&quot; data-origin-width=&quot;1272&quot; data-origin-height=&quot;737&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bj8jqk/btqAhq4FMFm/MwCJNAEKYKEziFJg13H0K1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bj8jqk/btqAhq4FMFm/MwCJNAEKYKEziFJg13H0K1/img.png&quot; data-alt=&quot;내PC 오른쪽 마우스 클릭 -&amp;amp;amp;gt; 속성 클릭&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bj8jqk/btqAhq4FMFm/MwCJNAEKYKEziFJg13H0K1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbj8jqk%2FbtqAhq4FMFm%2FMwCJNAEKYKEziFJg13H0K1%2Fimg.png&quot; data-filename=&quot;이미지 6.png&quot; data-origin-width=&quot;1272&quot; data-origin-height=&quot;737&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;내PC 오른쪽 마우스 클릭 -&amp;gt; 속성 클릭&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;이미지 10.png&quot; data-origin-width=&quot;1125&quot; data-origin-height=&quot;634&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPXA8s/btqAiWBMlJk/hK0OM1DGPGET7LgMuDn2PK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPXA8s/btqAiWBMlJk/hK0OM1DGPGET7LgMuDn2PK/img.png&quot; data-alt=&quot;고급 시스템 설정 클릭&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPXA8s/btqAiWBMlJk/hK0OM1DGPGET7LgMuDn2PK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPXA8s%2FbtqAiWBMlJk%2FhK0OM1DGPGET7LgMuDn2PK%2Fimg.png&quot; data-filename=&quot;이미지 10.png&quot; data-origin-width=&quot;1125&quot; data-origin-height=&quot;634&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;고급 시스템 설정 클릭&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;이미지 8.png&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;533&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZrWRa/btqAgUE80CS/kCkpybkjy5td5XIQynDi6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZrWRa/btqAgUE80CS/kCkpybkjy5td5XIQynDi6k/img.png&quot; data-alt=&quot;고급 탭 -&amp;amp;amp;gt; 환경변수 -&amp;amp;amp;gt; 시스템 또는 사용자의 Path 설정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZrWRa/btqAgUE80CS/kCkpybkjy5td5XIQynDi6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZrWRa%2FbtqAgUE80CS%2FkCkpybkjy5td5XIQynDi6k%2Fimg.png&quot; data-filename=&quot;이미지 8.png&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;533&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;고급 탭 -&amp;gt; 환경변수 -&amp;gt; 시스템 또는 사용자의 Path 설정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;위 과정까지 완료 되었다면 이제 &lt;code&gt;cmd&lt;/code&gt; (커맨드창) 을 열어주고 &lt;code&gt;gradle -v&lt;/code&gt; 를 입력해줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;이미지 11.png&quot; data-origin-width=&quot;979&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZ8v9Q/btqAiV3Wh96/IkJMyFUCYp9CFQNMyxACU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZ8v9Q/btqAiV3Wh96/IkJMyFUCYp9CFQNMyxACU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZ8v9Q/btqAiV3Wh96/IkJMyFUCYp9CFQNMyxACU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZ8v9Q%2FbtqAiV3Wh96%2FIkJMyFUCYp9CFQNMyxACU1%2Fimg.png&quot; data-filename=&quot;이미지 11.png&quot; data-origin-width=&quot;979&quot; data-origin-height=&quot;512&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;위 사진과 같이 버전 정보가 표시되면 설치 및 환경변수 설정이 끝납니다.&lt;/p&gt;</description>
      <category>Build</category>
      <category>build</category>
      <category>gradle</category>
      <category>window</category>
      <category>설치</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/85</guid>
      <comments>https://lee1535.tistory.com/85#entry85comment</comments>
      <pubDate>Fri, 6 Dec 2019 15:19:47 +0900</pubDate>
    </item>
    <item>
      <title>[Spring/Tiles-framework] page 전환 없이 body만 변경 / content만 새로고침 load</title>
      <link>https://lee1535.tistory.com/84</link>
      <description>&lt;p&gt;이번 포스팅에서는 Tiles에 대한 설명은 생략하겠습니다. 사실상 키워드를 저렇게 검색하고 오셨다는거는 이미 Tiles Framework를 사용한다는 가정하에 있으시니까.바로 특정 타일만 페이지 로드 없이 ajax콜을 통해 동적으로 변경하는 방법을 소개하겠습니다.&lt;/p&gt;
&lt;h1&gt;구조 이미지&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;948&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lYhzc/btqAgUYqjWu/tHctdPLAqFNdAJMgxSanb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lYhzc/btqAgUYqjWu/tHctdPLAqFNdAJMgxSanb0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lYhzc/btqAgUYqjWu/tHctdPLAqFNdAJMgxSanb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlYhzc%2FbtqAgUYqjWu%2FtHctdPLAqFNdAJMgxSanb0%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;1360&quot; data-origin-height=&quot;948&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;기존 구조&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;대충 위와 같은 구조의 홈페이지라고 가정했을 때 BODY || CONTENT 영역 부분만 바꾸고 싶을때입니다.&lt;br /&gt;우선 기존의 tiles.xml 파일은 아래와 같았습니다.&lt;/p&gt;
&lt;h5&gt;tiles.xml&lt;/h5&gt;
&lt;pre class=&quot;dust&quot;&gt;&lt;code&gt;&amp;lt;tiles-definitions&amp;gt;

    &amp;lt;definition name=&quot;layouts-tiles&quot; template=&quot;/WEB-INF/jsp/common/default-layouts.jsp&quot;&amp;gt;&amp;lt;/definition&amp;gt;

      &amp;lt;definition name=&quot;/*/*.do&quot; extends=&quot;layouts-tiles&quot;&amp;gt;
           &amp;lt;put-attribute name=&quot;content&quot; value=&quot;/WEB-INF/jsp/{1}/{2}.jsp&quot; /&amp;gt;
       &amp;lt;/definition&amp;gt;

       &amp;lt;definition name=&quot;/common/loginPage.jsp&quot; template=&quot;/WEB-INF/jsp/common/loginPage.jsp&quot;&amp;gt;
       &amp;lt;/definition&amp;gt;

&amp;lt;/tiles-definitions&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;다음으로 HTML 구조입니다.&lt;/p&gt;
&lt;h5&gt;default-layouts.jsp&lt;/h5&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;    ... 헤더, 메뉴 등등...공통으로 들어갈 화면 정의
    &amp;lt;div class=&quot;layout-body&quot;&amp;gt;
        &amp;lt;div class=&quot;layout-inner-body&quot;&amp;gt;        
            &amp;lt;tiles:insertAttribute name=&quot;content&quot;/&amp;gt;
         &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같은 방식으로 헤더나, 메뉴, 푸터는 간단하게 한 페이지로 구성하고, &lt;code&gt;content&lt;/code&gt;부분만 변경하는 구조입니다.&lt;br /&gt;이렇게 사용하면 해당 페이지를 새로 불러올때 불필요하게 공통부분을 &lt;code&gt;include&lt;/code&gt;할 필요 없이 &lt;code&gt;content&lt;/code&gt;부분만 바뀌어서 화면이 로드가 됩니다. 그치만 저같은 경우 헤더나, 메뉴에서 사용하는 외부 라이브러리가 많아 호출마다 0.5초씩 응답 시간이 필요해 화면이 깜빡이는 것 처럼 보이는게 싫었습니다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;그래서 공통 스크립트나, css 같은건 한번만 로드하고 가운데 &lt;code&gt;conetent&lt;/code&gt;영역만 바꾸고 싶었기 때문에 제가 선택한 방법은 우선은 빈 껍데기인 html을 하나 만들고 &lt;code&gt;&amp;lt;tiles:insertAttribute name=&quot;content&quot;/&amp;gt;&lt;/code&gt; 만 선언해줍니다.&lt;/p&gt;
&lt;h1&gt;변경 구조&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;위에 언급처럼 빈 껍데기인 하나의 html 파일을 생성해줍니다.&lt;/p&gt;
&lt;h5&gt;empty.html&lt;/h5&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;!-- empty.jsp --&amp;gt;
&amp;lt;tiles:insertAttribute name=&quot;content&quot;/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그리고 기존의 &lt;code&gt;tiles.xml&lt;/code&gt;을 수정해줍니다.&lt;/p&gt;
&lt;h5&gt;tiles.xml&lt;/h5&gt;
&lt;pre class=&quot;dust&quot;&gt;&lt;code&gt;&amp;lt;tiles-definitions&amp;gt;

    &amp;lt;definition name=&quot;layouts-tiles&quot; template=&quot;/WEB-INF/jsp/common/default-layouts.jsp&quot;&amp;gt;&amp;lt;/definition&amp;gt;

      &amp;lt;definition name=&quot;/*/*.do&quot; extends=&quot;layouts-tiles&quot;&amp;gt;
           &amp;lt;put-attribute name=&quot;content&quot; value=&quot;/WEB-INF/jsp/{1}/{2}.jsp&quot; /&amp;gt;
       &amp;lt;/definition&amp;gt;

       &amp;lt;definition name=&quot;/common/loginPage.jsp&quot; template=&quot;/WEB-INF/jsp/common/loginPage.jsp&quot;&amp;gt;
       &amp;lt;/definition&amp;gt;

    &amp;lt;definition name=&quot;empty&quot; template=&quot;/WEB-INF/jsp/common/empty.jsp&quot;&amp;gt;
         &amp;lt;put-attribute name=&quot;content&quot; value=&quot;&quot;/&amp;gt;
    &amp;lt;/definition&amp;gt;

    &amp;lt;definition name=&quot;*/empty/*.do&quot; extends=&quot;empty&quot;&amp;gt;
        &amp;lt;put-attribute name=&quot;content&quot; value=&quot;/WEB-INF/jsp/{1}/{2}.jsp&quot; /&amp;gt;
    &amp;lt;/definition&amp;gt;
&amp;lt;/tiles-definitions&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이렇게 빈 &lt;code&gt;empty.jsp&lt;/code&gt; 과 &lt;code&gt;default-layouts.jsp&lt;/code&gt; 의 &lt;code&gt;&amp;lt;tiles:insertAttribute name=&quot;content&quot;/&amp;gt;&lt;/code&gt; 을 연결해줍니다. 그리고 처음 언급처럼 ajax 호출을 통해 넘겨 받은 값으로 대체해줍니다. 아래는 예제 함수입니다.&lt;/p&gt;
&lt;h5&gt;예제 페이지 변경 함수&lt;/h5&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function changeContents(url){
        $.ajax({
            type        :    &quot;get&quot;,
            url : &quot;&amp;lt;c:url value='url'/&amp;gt;&quot;,
            dataType    :    'html',
            success        :    function(data){
                $(&quot;.layout-inner-body&quot;).children().remove();
                $(&quot;.layout-inner-body&quot;).html(data);

                // 접속 URL만 페이지 변환없이 변경
                // IE 10 이상이서만 지원...
                history.pushState({&quot;html&quot;:data},'',currentMenuUrl) 
            }
            , beforeSend: function() {

            },
            complete:function(){
            }
           });

    }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;간단하게 구현한 방식이며, 위와 같이 사용합니다.&lt;/p&gt;</description>
      <category>Spring/Spring</category>
      <category>body</category>
      <category>contents</category>
      <category>reload</category>
      <category>spring</category>
      <category>Tiles</category>
      <category>동적변경</category>
      <category>새로고침</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/84</guid>
      <comments>https://lee1535.tistory.com/84#entry84comment</comments>
      <pubDate>Thu, 5 Dec 2019 15:57:15 +0900</pubDate>
    </item>
    <item>
      <title>[인강리뷰] 자바 ORM 표준 JPA 프로그래밍 - 기본편</title>
      <link>https://lee1535.tistory.com/83</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;552&quot; data-origin-height=&quot;734&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ci3gL0/btqAeieMtyj/wwdJWM9JLcbKoDAK8KBgu1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ci3gL0/btqAeieMtyj/wwdJWM9JLcbKoDAK8KBgu1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ci3gL0/btqAeieMtyj/wwdJWM9JLcbKoDAK8KBgu1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fci3gL0%2FbtqAeieMtyj%2FwwdJWM9JLcbKoDAK8KBgu1%2Fimg.jpg&quot; width=&quot;100%&quot; data-origin-width=&quot;552&quot; data-origin-height=&quot;734&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;개인적으로 공부하다가 JPA, ORM, Hibernate 등등.. 단어들을 인터넷을 통해 자주 접하게 되어서 블로그나 참고자료를 찾아보는데 내용이 복잡해서 관련 책을 알아보다가 찾아냈다. 저자는 현재 우아한형제들 개발 팀장으로 계시는 김영한님이다.&lt;br /&gt;해당 책은 Inflearn을 통해 인강으로도 제공해주고 있기 때문에 독학에는 인강이 조금 더 이해하기 쉬울 거 같아서 인강을 선택하였다.&lt;/p&gt;
&lt;h2&gt;이런 걸 배울 수 있어요&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;JAP의 기본기를 탄탄하게 다질 수 있습니다.&lt;/li&gt;
&lt;li&gt;JAP의 내부 동작 방식을 이해할 수 있습니다.&lt;/li&gt;
&lt;li&gt;객체와 DB 테이블을 올바르게 설계하고 매핑할 수 있습니다.&lt;/li&gt;
&lt;li&gt;실무에서 자신있게 JPA를 사용할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;자바 ORM 표준 JPA 프로그래밍 - 기본편&lt;/h2&gt;
&lt;p&gt;객체를 관계형 데이터베이스에 저장하려면 개발자는 많은 코드와 SQL을 작성해야 합니다. 예를 들어 객체를 SQL로 변환하는 단순한 일부터, 객체의 상속 구조를 테이블에 저장하는 복잡한 일까지, 개발자는 객체와 데이터베이스 사이에서 무수한 매핑 코드와 SQL을 직접 작성해야 합니다. 자바 ORM 표준인 JPA는 SQL 작성 없이 객체를 데이터베이스에 직접 저장할 수 있게 도와주고, 객체와 관계형 데이터베이스의 차이도 중간에서 해결합니다.&lt;/p&gt;
&lt;h2&gt;강의 목표&lt;/h2&gt;
&lt;p&gt;앞으로 진행할 JPA 강의는 크게 기본편과 활용편으로 나뉘어져 있습니다. 이 강의는 기본편입니다.&lt;/p&gt;
&lt;h2&gt;마치며&lt;/h2&gt;
&lt;p&gt;뭐 대충 강의 내용은 이러하고 자세한 내용은 인프런을 통해서 확인하시길 바라겠습니다.&lt;/p&gt;
&lt;p&gt;사실상 가격이 부담되다 보니 구매를 망설이던 강의였는데, JPA나 Hibernate가 왜 등장했고 어떤 방식으로 동작하는지 핵심 기술부터 차근차근 설명해주기 때문에 만약 JPA를 쓰시는 분이라던가 책으로 공부중인데 이해가 어려우신 분들은 인강과 책을 같이 공부하면 더욱 도움이 될 것 같다고 생각이 들었습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;이상으로 강의를 보고 내용을 블로그에 조금씩 정리할 계획입니다.&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;color: #0593d3;&quot;&gt;&lt;a style=&quot;color: #0593d3;&quot; href=&quot;https://lee1535.tistory.com/82&quot;&gt;JPA와 ORM의 기본 개념&amp;nbsp;&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1575654648565&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[JAVA/JPA] JPA 와 ORM 기본 개념 Hibernate ORM&quot; data-og-description=&quot;해당 내용은 인프런의 자바 ORM 표준 JPA 프로그래밍-기본편 - 김영한 의 내용을 기반으로 정리해서 작성한 글입니다. 자세한 내용은 해당 강의 또는 책을 구매하셔서 자세히 알아보시는걸 추천합니다. ORM 이란?..&quot; data-og-host=&quot;lee1535.tistory.com&quot; data-og-source-url=&quot;https://lee1535.tistory.com/82&quot; data-og-url=&quot;https://lee1535.tistory.com/82&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/qY55H/hyDZooqvPV/sY4rrbkJyMrDrvhAtYrq61/img.png?width=800&amp;amp;height=215&amp;amp;face=0_0_800_215,https://scrap.kakaocdn.net/dn/cSrRVw/hyD042UFnE/QV9izKEOk2cGu9JqiWsqMK/img.png?width=800&amp;amp;height=215&amp;amp;face=0_0_800_215&quot;&gt;&lt;a href=&quot;https://lee1535.tistory.com/82&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://lee1535.tistory.com/82&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/qY55H/hyDZooqvPV/sY4rrbkJyMrDrvhAtYrq61/img.png?width=800&amp;amp;height=215&amp;amp;face=0_0_800_215,https://scrap.kakaocdn.net/dn/cSrRVw/hyD042UFnE/QV9izKEOk2cGu9JqiWsqMK/img.png?width=800&amp;amp;height=215&amp;amp;face=0_0_800_215');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;[JAVA/JPA] JPA 와 ORM 기본 개념 Hibernate ORM&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;해당 내용은 인프런의 자바 ORM 표준 JPA 프로그래밍-기본편 - 김영한 의 내용을 기반으로 정리해서 작성한 글입니다. 자세한 내용은 해당 강의 또는 책을 구매하셔서 자세히 알아보시는걸 추천합니다. ORM 이란?..&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;lee1535.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;a style=&quot;color: #0593d3;&quot; href=&quot;https://lee1535.tistory.com/87&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JAP의 영속성 컨텍스트&amp;nbsp;&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1575654672076&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[JAVA/JPA] 영속성 컨텍스트 EntityManage JPA 동작 방식&quot; data-og-description=&quot;해당 내용은 인프런의 자바 ORM 표준 JPA 프로그래밍 - 기본편 , 김영한 의 내요을 기반으로 정리해서 작성한 글입니다. 자세한 내용은 해당 강의 또는 책을 구매하셔서 알아보시는걸 추천합니다. 해당 글을 읽기..&quot; data-og-host=&quot;lee1535.tistory.com&quot; data-og-source-url=&quot;https://lee1535.tistory.com/87&quot; data-og-url=&quot;https://lee1535.tistory.com/87&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/mG4y0/hyD1bHJsTc/ttTVjihGzov27aJ2vhL901/img.png?width=800&amp;amp;height=456&amp;amp;face=0_0_800_456,https://scrap.kakaocdn.net/dn/bMTfXJ/hyD03wa5id/Kf5ykXp2txEBBxa1sgiMkk/img.png?width=800&amp;amp;height=456&amp;amp;face=0_0_800_456&quot;&gt;&lt;a href=&quot;https://lee1535.tistory.com/87&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://lee1535.tistory.com/87&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/mG4y0/hyD1bHJsTc/ttTVjihGzov27aJ2vhL901/img.png?width=800&amp;amp;height=456&amp;amp;face=0_0_800_456,https://scrap.kakaocdn.net/dn/bMTfXJ/hyD03wa5id/Kf5ykXp2txEBBxa1sgiMkk/img.png?width=800&amp;amp;height=456&amp;amp;face=0_0_800_456');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;[JAVA/JPA] 영속성 컨텍스트 EntityManage JPA 동작 방식&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;해당 내용은 인프런의 자바 ORM 표준 JPA 프로그래밍 - 기본편 , 김영한 의 내요을 기반으로 정리해서 작성한 글입니다. 자세한 내용은 해당 강의 또는 책을 구매하셔서 알아보시는걸 추천합니다. 해당 글을 읽기..&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;lee1535.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>일상/독서</category>
      <category>study</category>
      <category>공부</category>
      <category>독서</category>
      <category>독서리뷰</category>
      <category>우아한형제들</category>
      <category>인강</category>
      <category>인강리뷰</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/83</guid>
      <comments>https://lee1535.tistory.com/83#entry83comment</comments>
      <pubDate>Thu, 5 Dec 2019 13:01:21 +0900</pubDate>
    </item>
    <item>
      <title>[JAVA/JPA] JPA 와 ORM 기본 개념 Hibernate ORM</title>
      <link>https://lee1535.tistory.com/82</link>
      <description>&lt;p&gt;해당 내용은 인프런의 &lt;code&gt;자바 ORM 표준 JPA 프로그래밍-기본편 - 김영한&lt;/code&gt; 의 내용을 기반으로 정리해서 작성한 글입니다.&lt;br /&gt;자세한 내용은 해당 강의 또는 책을 구매하셔서 자세히 알아보시는걸 추천합니다.&lt;/p&gt;
&lt;h1&gt;ORM 이란?&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ORM(Object-relational mapping)&lt;/code&gt;의 약자로써, 객체와 관계의 연결을 시켜주는 것을 말한다. 즉 Java와 같은 객체 지향 언어에서의 객체와 Oracle와 같은 RDB를 연결 시켜주는 방식을 말하며, &lt;code&gt;Hibernate&lt;/code&gt;는 Java에서 사용하는 ORM의 &lt;b&gt;open source Framework&lt;/b&gt;의 한 종류이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;JPA 란?&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;code&gt;JPA(Java Persistent API)&lt;/code&gt;의 약자로 말 그대로 자바에서 사용하는 ORM 기술에 대한 API 표준 명세를 뜻합니다.&lt;br /&gt;JPA는 ORM을 사용하기 위한 인터페이스를 모아둔 것입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRDh0i/btqAcrQWvLk/UqvRyOMRpFjdMMcmWQL3jK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRDh0i/btqAcrQWvLk/UqvRyOMRpFjdMMcmWQL3jK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRDh0i/btqAcrQWvLk/UqvRyOMRpFjdMMcmWQL3jK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRDh0i%2FbtqAcrQWvLk%2FUqvRyOMRpFjdMMcmWQL3jK%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;등장 배경&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;위에서 ORM과 JPA에 대해서 간략하게 어떤 내용인지 설명을 했고, 그렇다면 왜 등장했을까?&lt;br /&gt;ORM의 정의처럼 현재 프로그래밍 방식인 &lt;b&gt;객체지향적&lt;/b&gt; 방식과 DB의 &lt;b&gt;관계지향적&lt;/b&gt; 방식의 불일치&lt;br /&gt;즉 &lt;b&gt;페러다임의 불일치&lt;/b&gt;로 인해 문제가 발생하며, 프로그래밍을 객체보다 테이블을 우선시 작성하며, 객체를 단순히 데이터 전달의 목적으로( DTO, VO 등 ) 사용&lt;/p&gt;
&lt;h3&gt;페러다임의 불일치로 발생하는 문제&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;b&gt;객체다운 모델링 문제&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;간단하게 객체지향 적으로 모델링을했다고 가정하고, 객체의 필드로 객체를 가지는 경우&lt;/p&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;public class Member {
  private String name;
  private Department dept;

  getter()/setter()
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같이 객체지향적으로 사용을 할경우 &lt;code&gt;Member&lt;/code&gt;클래스와 &lt;code&gt;Department&lt;/code&gt; 클래스를 모두 사용할 때, DB에서 MEMBER 테이블과 DEPT 테이블을 조인해 결과를 가지고 왔다고 가정했을 경우 로직에서 &lt;code&gt;new Member()&lt;/code&gt;로 인스턴스하고 값 매핑시켜주고, 추가로 &lt;code&gt;new Departemt()&lt;/code&gt; 를 통해서 또 매핑시켜주고..이런 동작이 필요하게 됨&lt;br /&gt;그래서 &lt;code&gt;MemberDepartemtDTO&lt;/code&gt; 대충 이런식으로 큰 클래스를 넣고 거기서 &lt;code&gt;Member&lt;/code&gt;클래스의 필드와 &lt;code&gt;Departemt&lt;/code&gt; 필드를 다 넣어서 사용 이는 &lt;i&gt;객체지향적이지 못한 방식의 프로그래밍&lt;/i&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;b&gt;객체의 탐색 범위 문제&lt;/b&gt;&lt;br /&gt;SQL은 데이터가 쿼리문에서 조회해온 데이터로 한정적이기 때문에 엔티티 신뢰에 문제가 발생&lt;br /&gt;간단하게 설명해 SQL 쿼리를 통해 &lt;code&gt;MEMBER&lt;/code&gt; 테이블에서 &lt;b&gt;name&lt;/b&gt;을 가져오는 쿼리를 실행했다고 가정하고, 매핑되는 &lt;code&gt;Member&lt;/code&gt; 객체는 field로 &lt;b&gt;String name, int age&lt;/b&gt;를 가지고 있다고 가정해봅니다.&lt;/p&gt;
&lt;pre class=&quot;fsharp&quot;&gt;&lt;code&gt;  public void process() {
    Member member = memberDAO.getMember(memberId);
    member.getName() // 가능
    member.getAge() // 값이 없음
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위 예제를 보면 우리는 &lt;code&gt;member&lt;/code&gt;객체를 통해서 &lt;code&gt;getName()&lt;/code&gt;는 가능하고 &lt;code&gt;getAge()&lt;/code&gt;는 값이 없다는걸 당연하다고 생각할 것입니다.&lt;br /&gt;왜?? 우리는 현재 쿼리가 어떻게 동작하고 어떤 값을 가져오는지 알고 있다는 가정하에 있으니까 가능합니다. 그러나 다른 사람이 작성한 코드의 경우, 예전에 만들어두고 까먹은 경우&lt;br /&gt;해당 값이 어떤 값을 매핑하는지는 보통 해당 Service -&amp;gt; DAO -&amp;gt; SQL 을 탐색해서 해당 쿼리문을 보고 받아오는 값을 확인합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;b&gt;객체의 동일성 보장이 안된다&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public void process() {
  Member member1 = memberDAO.getMember(100);
  Member member2 = memberDAO.getMember(100);
  System.out.println(member1 == member2 ) // false
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같이 실행했을 경우 member1과 member2는 동일한 객체일까요? 아쉽게도 JDBC API 메커니즘에 의해 전혀 새로운 객체로 취급받습니다. 그렇다면 우리가 흔히 생각하는 객체지향적으로 봤을때 두 객체는 같아합니다. 예제는 컬렉션을 기준으로 하겠습니다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public void process() {
  Member member1 = memberList.get(100);
  Member member2 = memberList.get(100);
  System.out.println(member1 == member2 ) // true
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위 둘 예제에서 객체의 동일성이 보장이 안되는 문제가 발생합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;b&gt;객체지향의 장점인 ( 추상화, 캡슐화, 상속, 다형성 ) 을 활용하지 못함&lt;/b&gt;&lt;br /&gt;예를들어 상속관계인 객체의 경우 자바 컬렉션에서는&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;public void process() {
  Book book = list.get(bookId);
  Item item = list.get(bookId);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같이 다형성등을 사용해 간단하게 사용 가능하지만, DB에 저장하기 위해서는&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;객체를 분해&lt;/li&gt;
&lt;li&gt;INSERT INTO ITEM...&lt;/li&gt;
&lt;li&gt;INSERT INTO BOOK...&lt;br /&gt;위와 같은 방식으로 동작하며 조회시에도 복잡한 작업이 많이 요구됩니다. 그래서 DB에 저장할 객체에는 상속 관게를 사용하지 않는 문제점 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;JPA를 통한 문제 해결&lt;/h3&gt;
&lt;p&gt;JPA를 사용하면 패러다임의 불일치에 대한 불필요한 처리를 해결해준다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;b&gt;객체답게 사용 가능&lt;/b&gt;&lt;br /&gt;아래의 방식처럼 객체간 연관관계가 끊기는 방식으로 동작하는 기존의 테이블의 &lt;b&gt;데이터&lt;/b&gt; 중심의 설계에서&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class Member {
     String name;
    String deptId;
}
public void process(){  
    Member member = new member();  
    Department dept = memberDAO.getDepartment(member.getDeptId());  
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;아래와 같이 객체의 연관관계를 사용할 수 있게 해줍니다. &lt;b&gt;단,&lt;/b&gt; JPA의 핵심이기한 객체지향적 모델링이 요구됩니다.&lt;br /&gt;그만큼 모델링 자체를 객체지향적인 관점에서 해야 하기 때문에 제일 어려운 부분입니다. 또한 객체관의 관계가 단방향인지, 양방향인지, 관계의 주인은 누구인지를 잘 파악하고 사용하셔야 합니다.&lt;/p&gt;
&lt;pre class=&quot;fsharp&quot;&gt;&lt;code&gt;public void process(){  
  Member member = new member();  
  Department dept = member.getDept();  
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;b&gt;객체의 탐색 범위 문제 해결&lt;/b&gt;&lt;br /&gt;위 예제처럼 동일한 상황에 SQL에 의존적이지 않고 객체의 필드를 필요하면 사용이 가능&lt;/p&gt;
&lt;pre class=&quot;fsharp&quot;&gt;&lt;code&gt;public void process() {
  Member member = memberDAO.find(memberId);  
  member.getDepartemt();  
  member.getAge(); //가능
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;또한 객체 그래프 탐색가능&lt;/p&gt;
&lt;pre class=&quot;fsharp&quot;&gt;&lt;code&gt;public void process() {
  Member.setTema(new Team());  
  jpa.persist(member); // 객체를 DB 지향적으로 teamId값이 아닌 객체 자체를 넣음

  // 조회도 가능  
  Member member = jpa.find(member.class, memberid)  
  Team tem = member.getTeam()
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;여기서 &lt;code&gt;persist()&lt;/code&gt;,&lt;code&gt;find()&lt;/code&gt;는 JPA에서 제공하는 메소드이고, 위와 같이 동작이 가능한 이유는 지연 로딩을 제공하기 때문입니다. 자세한 내용은 아래에 추가로 설명하겠습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;b&gt;객체의 동일성 보장 ( 단 같은 트랜잭션의 단위 -&amp;gt; jpa에서는 트랜잭션 단위가 중요함 )&lt;/b&gt;&lt;br /&gt;JPA에서 중요한 &lt;b&gt;EntityManager&lt;/b&gt;(영속성 컨텍스트)가 트랜잭션 단위로 생성과 소멸이 되기 때문&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;JPA의 장점&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;위 객체지향과 관계모델의 페러다임 불일치 해결과 함께 제공해주는 JPA의 장점입니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;SQL 중심적 개발에서 객체 중심 개발 -&amp;gt; SQL에 의존적이지 않음 -&amp;gt; 생산성 증가&lt;br /&gt;따로 SQL문 작성이 필요없이 몇개의 메소드로 동작함. 나머진 자동으로 SQL문 생성해줌&lt;/li&gt;
&lt;li&gt;페러다임 불일치 해결&lt;/li&gt;
&lt;li&gt;성능 향상
&lt;ul&gt;
&lt;li&gt;1차 캐시를 사용&lt;br /&gt;단 트랜잭션 단위에서만 지원함&lt;br /&gt;어플리케이션 자체에서 &lt;code&gt;DB Isolation Level&lt;/code&gt;을 &lt;b&gt;Read Commit&lt;/b&gt; 이여도 &lt;b&gt;Repeatable Read&lt;/b&gt;을 보장&lt;/li&gt;
&lt;li&gt;트랜잭션을 지원하는 쓰기 지연&lt;br /&gt;&lt;code&gt;JDBC batch()&lt;/code&gt; 기능, 여러개의 비슷한 쿼리를 한번에 묶어서 보냄 (버퍼처럼 )&lt;br /&gt;&lt;code&gt;update&lt;/code&gt;, &lt;code&gt;delete&lt;/code&gt;시 DB Lock를 최소화 하기 위해 커밋 직전에 실행 위 &lt;code&gt;insert&lt;/code&gt;도 동일&lt;/li&gt;
&lt;li&gt;지연 로딩&lt;br /&gt;&lt;code&gt;Member&lt;/code&gt; 객체만 사용할 경우 SQL이 &lt;code&gt;MEMBER&lt;/code&gt; 테이블에서만 조회 하다가 &lt;code&gt;getDepartemt()&lt;/code&gt; 시점에 &lt;code&gt;DEPARTMENT&lt;/code&gt; 테이블을 참조해 값을 가져옴&lt;br /&gt;그러나 매번 두 테이블을 같이 쓰는 경우 불필요하게 &lt;code&gt;select&lt;/code&gt;문이 많아질 수 있기 때문에, 즉시로딩 즉 member/team을 한번에 가져오는 방식도 지원해준다. 필요한 방식으로 사용하면 됩니다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;데이터 접근 추상화와 벤더 독립성&lt;br /&gt;데이터 접근에 대한 SQL문을 몰라도 되고, &lt;b&gt;Oracle&lt;/b&gt;,&lt;b&gt;MySQL&lt;/b&gt; 등 특정 DB에 종속적이지 않게 사용이 가능, 이는 &lt;code&gt;persistence.xml&lt;/code&gt;에 옵션으로 &lt;b&gt;dialect&lt;/b&gt; 설정을 통해 자동으로 쿼리를 완성해줌, 이는 장점이자 단점이 될 수도 있을거 같다는 생각이 듭니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;JPA의 단점&lt;/h1&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;b&gt;성능&lt;/b&gt;이 떨어진다. 자동으로 쿼리를 완성해준다는 부분이 원하는 쿼리를 수행하지 않을 경우도 존재한다는 말이고, 성능도 좋지 못했다고 합니다. 그러나 지금은 여러가지 보안을 하여서 잘만 이해하고 사용하면 &lt;b&gt;1차 캐쉬&lt;/b&gt;등을 통해서 더 좋은 성능을 낼 수 있다고 생각합니다. 또한 전세계적으로 사용중이기 때문에 꾸준한 발전이 되고 있습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;b&gt;세밀함&lt;/b&gt;이 떨어진다. 자동 SQL 완성으로인헤 통계를 구하는등의 세밀한 작업이 떨어집니다. 그래서 &lt;code&gt;JPQL&lt;/code&gt;이라는 별도의 언어를 제공해주고 또한 SQL 자체도 수행 가능하도록 지원하고 있습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;b&gt;러닝커브&lt;/b&gt; 사용하기 위해 비용이 많이 들어갑니다.. 제대로 사용하기 위해 시간을 투자해야한다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>PROGRAMMING/JAVA</category>
      <category>hibernate</category>
      <category>Java</category>
      <category>JPA</category>
      <category>ORM</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/82</guid>
      <comments>https://lee1535.tistory.com/82#entry82comment</comments>
      <pubDate>Thu, 5 Dec 2019 09:34:49 +0900</pubDate>
    </item>
    <item>
      <title>[Web] WAS 와 웹서버란? ( WAS, Web Server ) 아파치 (apache)  톰캣  (tomcat )</title>
      <link>https://lee1535.tistory.com/80</link>
      <description>&lt;p&gt;올해 초 웹 개발자 면접을 진행하면서&lt;br /&gt;&lt;b&gt;WAS와 Web Server의 차이는 무엇인가요?&lt;/b&gt; 라는 질문을 많이 들었던것 같다.&lt;br /&gt;답변으로 정적인 페이지 처리와, 동적인 페이지처리의 차이가 있다. 라고 기본적인 답변을 했었습니다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;그리고 &lt;b&gt;어떻게 동작하는지 아시나요?&lt;/b&gt; 라고 질문을 하신 분들도 계셨는데&lt;br /&gt;답변으로 &lt;code&gt;html&lt;/code&gt;과 &lt;code&gt;css&lt;/code&gt;같은 정적문서 요청인 경우 &lt;b&gt;Web Server&lt;/b&gt; 가 처리하고 &lt;code&gt;JSP&lt;/code&gt;,&lt;code&gt;Script&lt;/code&gt; 같이 동적문서 요청인 경우 &lt;b&gt;WAS&lt;/b&gt;가 처리한다고 답변을 했었습니다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;위에 말이 틀린말은 아니지만, 이번 포스팅에서는 좀 더 &lt;b&gt;어떤 방식으로 동작하는지&lt;/b&gt;에 대해서 구체적으로 공부를 하기 위한 포스팅이 목적입니다.&lt;/p&gt;
&lt;h1&gt;1. 전체 구조&lt;/h1&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;270&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOU0HO/btqz73DdjD4/GvCI2Tbn6wdBa3SvsaAkM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOU0HO/btqz73DdjD4/GvCI2Tbn6wdBa3SvsaAkM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOU0HO/btqz73DdjD4/GvCI2Tbn6wdBa3SvsaAkM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOU0HO%2Fbtqz73DdjD4%2FGvCI2Tbn6wdBa3SvsaAkM1%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;270&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;Web Server 란 ?&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;클라이언트의 &lt;code&gt;request&lt;/code&gt;가 오면 요청에 대한 처리를 담당하며&lt;br /&gt;정적문서( html, css ) 등일 경우 요청에 응답을 해줍니다. 대표적으로 &lt;b&gt;Apache&lt;/b&gt; 에 해당합니다.&lt;/p&gt;
&lt;h5&gt;동작&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;요청이 정적 컨텐츠일 경우 제공&lt;/li&gt;
&lt;li&gt;요청이 정적 컨텐츠가 아닐 경우 WAS로 처리를 위임 후, 넘어온 값을 응답&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;WAS ( Web Application Server ) 란 ?&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;b&gt;동적&lt;/b&gt; 컨텐츠를 제공하기 위해 만들어진 미들웨어로써, DB조회가 필요하거나 처리가 필요한 &lt;code&gt;JSP/Servlet&lt;/code&gt; 구동 환경을 제공합니다.&lt;br /&gt;대표적으로 &lt;b&gt;Tomcat&lt;/b&gt;가 있습니다.&lt;/p&gt;
&lt;h5&gt;동작&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;Web Server로 부터 요청이 오면 컨테이너가 응답&lt;/li&gt;
&lt;li&gt;컨테이너는 &lt;code&gt;JSP/Servlet&lt;/code&gt;을 실행&lt;/li&gt;
&lt;li&gt;컨테이너는 요청 결과를 &lt;code&gt;HTML&lt;/code&gt; 문서로 만들어 Web Server로 전달&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Web Server 과 WAS의 차이&lt;/h1&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ol&gt;
&lt;li&gt;&lt;b&gt;동적 컨텐츠처리와 정적 컨텐츠 처리의 역할을 분리해서 WAS 서버의 부하 방지&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;WAS가 불필요한 경우 Web Server이 처리를 함으로써 성능 향상 ?&lt;/b&gt;&lt;br /&gt;일부는 맞고 일부는 틀린말이라고 생각합니다. 과거에는 WAS에서 정적 컨텐츠 처리 기능을 제공하지 않았지만, 요즘 WAS는 내부에 HTTPD의 일부 기능을 제공하기 때문에 속도의 차이는 없다고 합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h5&gt;그렇다면 왜 사용하는 것일까?&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;1번에서 말한거 처럼 WAS 서버의 부하를 방지&lt;/li&gt;
&lt;li&gt;물리적으로 분리하여 ( Web Server과 WAS 서버의 포트가 다름 ) 보안강화&lt;/li&gt;
&lt;li&gt;위 구조 그림처럼 여러대의 WAS를 연결하여 사용 가능, 로드밸런싱의 역할
&lt;ul&gt;
&lt;li&gt;이는 java서버, php서버 등 하나의 웹서버를 통해 서비스가 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Web/web</category>
      <category>html</category>
      <category>Was</category>
      <category>web server</category>
      <category>동적 문서</category>
      <category>동적처리</category>
      <category>웹 컨테이너</category>
      <category>웹서버</category>
      <category>자바</category>
      <category>정적 문서</category>
      <category>정적처리</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/80</guid>
      <comments>https://lee1535.tistory.com/80#entry80comment</comments>
      <pubDate>Fri, 29 Nov 2019 11:05:18 +0900</pubDate>
    </item>
    <item>
      <title>[자바/알고리즘] 프로그래머스 자릿수 더하기</title>
      <link>https://lee1535.tistory.com/79</link>
      <description>&lt;h1&gt;문제 설명&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;자연수 &lt;code&gt;N&lt;/code&gt;이 주어지면, &lt;code&gt;N&lt;/code&gt;의 각 자릿수의 합을 구해서 &lt;code&gt;return&lt;/code&gt;하는 &lt;code&gt;solution&lt;/code&gt;함수를 만들어 주세요.&lt;br /&gt;예를들어 &lt;code&gt;N = 123&lt;/code&gt; 이면 1 + 2 + 3 = 6 을 &lt;code&gt;return&lt;/code&gt; 하면 됩니다.&lt;/p&gt;
&lt;h1&gt;제한 사항&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;N의 범위 : 100,000,000 이하의 자연수&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;입출력 예&lt;/h1&gt;
&lt;hr /&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-style=&quot;style8&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;b&gt;N&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;b&gt;answer&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;123&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;987&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;24&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;입출력 예 설명&lt;/h1&gt;
&lt;hr /&gt;
&lt;h4&gt;입출력 예 #1&lt;/h4&gt;
&lt;p&gt;문제의 예시와 같습니다.&lt;/p&gt;
&lt;h4&gt;입출력 예 #2&lt;/h4&gt;
&lt;p&gt;9 + 8 + 7 = 24이므로 24를 return 하면 됩니다.&lt;/p&gt;
&lt;h1&gt;나의 풀이&lt;/h1&gt;
&lt;hr /&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public class Solution {
    public int solution(int n) {
        int answer = 0;
        while(true){
            answer += n%10;
            if(n&amp;lt;10) break;
            n = n/10;
        }
        return answer;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;풀이 설명&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;code&gt;%&lt;/code&gt;연산자를 통해서 해당 자리의 자릿수를 &lt;code&gt;answer&lt;/code&gt;에 더해줍니다.&lt;br /&gt;그 후, 다른 자릿수를 구하기 위해 전체 값에 &lt;code&gt;/10&lt;/code&gt;을 통해 자릿수를 이동해줍니다.&lt;br /&gt;마지막까지 탐색 후 더한값 즉 &lt;code&gt;answer&lt;/code&gt;을 리턴해줍니다.&lt;/p&gt;</description>
      <category>알고리즘/프로그래머스</category>
      <category>Java</category>
      <category>더하기</category>
      <category>알고리즘</category>
      <category>자릿수</category>
      <category>자릿수 더하기</category>
      <category>자바</category>
      <category>프로그래머스</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/79</guid>
      <comments>https://lee1535.tistory.com/79#entry79comment</comments>
      <pubDate>Thu, 28 Nov 2019 16:51:06 +0900</pubDate>
    </item>
    <item>
      <title>[자바/알고리즘] 프로그래머스 자연수 뒤집어 배열로 만들기</title>
      <link>https://lee1535.tistory.com/78</link>
      <description>&lt;h1&gt;문제 설명&lt;/h1&gt;
&lt;hr&gt;
&lt;p&gt;자연수 &lt;code&gt;n&lt;/code&gt;을 뒤집어 각 자리 숫자를 원소로 가지는 배열 형태로 리턴해주세요. 예를들어 &lt;code&gt;n&lt;/code&gt;이 12345이면 &lt;code&gt;[5, 4, 3, 2, 1]&lt;/code&gt;을 리턴합니다.&lt;/p&gt;
&lt;h1&gt;제한 조건&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;n 은 10,000,000,000 이하인 자연수입니다,&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;입출력 예&lt;/h1&gt;
&lt;hr&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-style=&quot;style8&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;width: 50%;&quot;&gt;&lt;b&gt;n&lt;/b&gt;&lt;/td&gt;&lt;td style=&quot;width: 50%;&quot;&gt;&lt;b&gt;return&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span&gt;12345&lt;/span&gt;&lt;/td&gt;&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span&gt;[5,4,3,2,1]&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;

&lt;h1&gt;나의 풀이&lt;/h1&gt;
&lt;hr&gt;
&lt;pre&gt;&lt;code&gt;class Solution {
  public int[] solution(long n) {
      int[] answer = new int[String.valueOf(n).length()];
      for (int i = 0; i &amp;lt; answer.length; i++) {
            answer[i] = (int) (n%10);
            n /= 10;
        }
      return answer;
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;h1&gt;풀이 설명&lt;/h1&gt;
&lt;hr&gt;
&lt;p&gt;우선 자연수를 뒤집어 저장한다 -&amp;gt; 즉 1의자리부터 10의자리 100의자리...의 값으로 저장하면 된다. 라고 접근을했습니다.&lt;br&gt;그래서 넘어온 매개변수 &lt;code&gt;n&lt;/code&gt;의 길이만큼 &lt;code&gt;int[]&lt;/code&gt;배열의 크기를 초기화 해주고,&lt;/p&gt;
&lt;p&gt;  &lt;code&gt;%&lt;/code&gt;연산을 통해 해당 자리의 값을 추출&lt;br&gt;  &lt;code&gt;/&lt;/code&gt;연산자를 통해 다음 자릿수로 이동&lt;/p&gt;
&lt;p&gt;  의 로직을 반복문을 통해 실행하고 리턴하였습니다.&lt;/p&gt;</description>
      <category>알고리즘/프로그래머스</category>
      <category>%</category>
      <category>/</category>
      <category>Java</category>
      <category>알고리즘</category>
      <category>자바</category>
      <category>자연수 뒤집어 배열로 만들기</category>
      <category>프로그래머스</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/78</guid>
      <comments>https://lee1535.tistory.com/78#entry78comment</comments>
      <pubDate>Thu, 28 Nov 2019 16:34:33 +0900</pubDate>
    </item>
    <item>
      <title>[자바/알고리즘] 프로그래머스 정수 내림차순으로 배치하기</title>
      <link>https://lee1535.tistory.com/77</link>
      <description>&lt;h1&gt;문제 설명&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;함수 solution은 정수 n을 매개변수로 입력받습니다. n의 각 자릿수를 큰것부터 작은 순으로 정렬한 새로운 정수를 리턴해주세요. 예를들어 n이 118372면 873211을 리턴하면 됩니다.&lt;/p&gt;
&lt;h1&gt;제한 조건&lt;/h1&gt;
&lt;hr /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;n&lt;/code&gt;은 1이상 8,000,000,000 이하인 자연수입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;입출력 예&lt;/h1&gt;
&lt;hr /&gt;
&lt;table style=&quot;letter-spacing: 0px; border-collapse: collapse; width: 100%; height: 38px;&quot; border=&quot;1&quot; data-ke-style=&quot;style8&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 19px;&quot;&gt;&lt;b&gt;n&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 19px;&quot;&gt;&lt;b&gt;return&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 19px;&quot;&gt;118372&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 19px;&quot;&gt;873211&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;나의 풀이&lt;/h1&gt;
&lt;hr /&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;import java.util.Arrays;
import java.util.Comparator;
class Solution {
  public long solution(long n) {

        String[] sarr = (String.valueOf(n)).split(&quot;&quot;);

        Arrays.sort(sarr,new Comparator&amp;lt;String&amp;gt;() {
            @Override
            public int compare(String str1, String str2) {
                // TODO Auto-generated method stub
                return(str2).compareTo(str1);
            }
        });
      return Long.parseLong(String.join(&quot;&quot;, sarr));
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;풀이 설명&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;넘어온 숫자를 자릿수로 정렬하기 위해 각 자릿수의 숫자를 각각 &lt;code&gt;String[]&lt;/code&gt;배열에 저장하고 싶었다.&lt;br /&gt;그래서 사용한 방법이 넘어온 매개변수 &lt;code&gt;n&lt;/code&gt;을 &lt;code&gt;String.valueOf(long)&lt;/code&gt; 메소드를 통해 타입을 &lt;code&gt;String&lt;/code&gt; 형으로 바꾸고,&lt;br /&gt;&lt;code&gt;String&lt;/code&gt;의 메소드 &lt;code&gt;split()&lt;/code&gt;를 이용해 한글자씩 추출했습니다.&lt;br /&gt;그 후, &lt;code&gt;Arrays.sort()&lt;/code&gt; 를 사용해 내림차순 정렬을 한 후, 값을 리턴해줍니다.&lt;/p&gt;</description>
      <category>알고리즘/프로그래머스</category>
      <category>Java</category>
      <category>내림차순정렬</category>
      <category>숫자를 문자로</category>
      <category>자바</category>
      <category>정수</category>
      <category>정수 내림차순으로 배치하기</category>
      <category>프로그래머스</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/77</guid>
      <comments>https://lee1535.tistory.com/77#entry77comment</comments>
      <pubDate>Thu, 28 Nov 2019 13:14:41 +0900</pubDate>
    </item>
    <item>
      <title>[디자인패턴/Design Patter] Prototype 패턴 프로토타입 패턴</title>
      <link>https://lee1535.tistory.com/76</link>
      <description>&lt;p&gt;관련 내용은 &lt;code&gt;[자바 언어로 배우는 디자인 패턴 입문]&lt;/code&gt; 이라는 책의 공부 내용을 개인적으로 정리한 내용입니다.&lt;br /&gt;처음 배우는 부분이기 때문에 틀린 부분이 있다면 지적해주시면 감사하겠습니다.&lt;/p&gt;
&lt;h1&gt;1. Prototype 패턴이란?&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;code&gt;Prototype&lt;/code&gt;는 '원형' 이라는 의미로, 원형이 되는 인스턴스로 새로운 인스턴스를 만드는 방식, 즉 객체에 의해 생성될 객체의 타입이 결정되는 생성 디자인 패턴입니다.&lt;/p&gt;
&lt;h1&gt;2. Prototype 패턴의 등장인물&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;이번 포스팅에서 사용될 요소들의 역할입니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prototype의 역할
&lt;ol&gt;
&lt;li&gt;인스턴스를 복사하여 새로운 인스턴스를 만들기 위한 메소드를 결정&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;ConcretePrototype
&lt;ol&gt;
&lt;li&gt;인스턴스를 복사해서 새로운 인스턴스를 만드는 메소드를 실제로 구현&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Client
&lt;ol&gt;
&lt;li&gt;인스턴스 복사 메소드를 사용해서 새로운 인스턴스를 만듭니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Prototype 패턴의 클래스 다이어그램&lt;/h5&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-filename=&quot;그림 5.gif&quot; data-origin-width=&quot;446&quot; data-origin-height=&quot;256&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgSUMa/btqz257xbWW/DCd1Y1FefPrD1QbqPAehk1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgSUMa/btqz257xbWW/DCd1Y1FefPrD1QbqPAehk1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgSUMa/btqz257xbWW/DCd1Y1FefPrD1QbqPAehk1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bgSUMa/btqz257xbWW/DCd1Y1FefPrD1QbqPAehk1/img.gif&quot; data-filename=&quot;그림 5.gif&quot; data-origin-width=&quot;446&quot; data-origin-height=&quot;256&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;3. 예제&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;이제 Prototype 패턴의 예제로 내용을 구체화 해보겠습니다.&lt;/p&gt;
&lt;h5&gt;예제에서 사용될 클래스 다이어그램&lt;/h5&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c5DNs1/btqAa8I5xyq/v3X3mTMoKLEZn254ZkR1ok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c5DNs1/btqAa8I5xyq/v3X3mTMoKLEZn254ZkR1ok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c5DNs1/btqAa8I5xyq/v3X3mTMoKLEZn254ZkR1ok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc5DNs1%2FbtqAa8I5xyq%2Fv3X3mTMoKLEZn254ZkR1ok%2Fimg.png&quot; width=&quot;100%&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2&gt;Shape 클래스&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;clone()&lt;/code&gt; 메소드를 사용하기 위해 &lt;code&gt;Cloneable&lt;/code&gt; 인터페이스를 구현하며, 공통 메소드인 &lt;code&gt;draw()&lt;/code&gt;는 추상 메소드로 정의하고,&lt;br /&gt;하위 클래스에서 사용할 &lt;code&gt;clone()&lt;/code&gt;는 공통으로 동작하는 메소드를 정의&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;public abstract class Shape implements Cloneable{
    protected Type type;

    abstract void draw();

    @Override
    public Object clone() throws CloneNotSupportedException {
        Object clone = null;

        try {
            clone = super.clone();
        } catch (RuntimeException e) {
            e.printStackTrace();
        } catch (CloneNotSupportedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return clone;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;상황에 따라 &lt;code&gt;clone()&lt;/code&gt;메소드를 공통으로 동작하지 않게 할 경우, 해당 클래스 자체를 &lt;code&gt;interface&lt;/code&gt;로 선언 후,&lt;br /&gt;&lt;code&gt;clone()&lt;/code&gt;메소드 정의를 하위 클래스에 위임 하는 방식도 존재&lt;br /&gt;여담으로 &lt;code&gt;clone()&lt;/code&gt; 의 &lt;b&gt;try - catch&lt;/b&gt; 문에서는 어차피 &lt;code&gt;Clonable&lt;/code&gt; 인터페이스를 구현했기 때문에 &lt;code&gt;CloneNotSupportedException&lt;/code&gt; 이 발생하지 않는다. 그래서 추가로 &lt;code&gt;RuntimeException&lt;/code&gt; 을 &lt;b&gt;catch&lt;/b&gt;문에 추가 해주는 방식이 좋다.&lt;/p&gt;
&lt;h2&gt;Circle, Triangle, Rectangle 클래스&lt;/h2&gt;
&lt;p&gt;각각 Shape 클래스를 상속 받으며 &lt;code&gt;draw()&lt;/code&gt;메소드를 재정의한다. 해당 소스는 Circle 클래스 기준입니다.&lt;/p&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;public class Circle extends Shape {
    public Circle() {
        this.type = Type.CIRCLE;
    }

    @Override
    void draw() {
        System.out.println(&quot;[Circle]입니다.&quot;);    
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;ShapeStroe 클래스&lt;/h2&gt;
&lt;p&gt;저장소를 담당하며, 최초 &lt;code&gt;registerShap()&lt;/code&gt; 메소드 호출 시 복제에 사용할 객체를 인스턴스화 해서 &lt;code&gt;shapeMap&lt;/code&gt;에 저장하는 동적을 하며, &lt;code&gt;getShape()&lt;/code&gt;메소드를 통해 객체의 복사본을 반환해주는 역할을 합니다.&lt;/p&gt;
&lt;pre class=&quot;fsharp&quot;&gt;&lt;code&gt;public class ShapeStore {
    private static Map&amp;lt;Type, Shape&amp;gt; shapeMap = new HashMap&amp;lt;Type, Shape&amp;gt;();

    public void registerShape() {
        Rectangle rec = new Rectangle();
        Circle cir = new Circle();
        Triangle tri = new Triangle();

        shapeMap.put(rec.type, rec);
        shapeMap.put(cir.type, cir);
        shapeMap.put(tri.type, tri);
    }

    public Shape getShape(Type type)  {
        return (Shape) shapeMap.get(type).clone();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;사람에 따라 해당 로직을 &lt;code&gt;Client&lt;/code&gt; 해당 예제에서는 Main 클래스에서 정의하는 방식도 존재하지만,&lt;br /&gt;저의 경우 &lt;code&gt;Client&lt;/code&gt;와 역할을 분리해 해당 소스가 변경이 있어도 추가로 수정하는 부분이 없도록 역할을 분리해서 작성했습니다.&lt;/p&gt;
&lt;h2&gt;Main 클래스&lt;/h2&gt;
&lt;p&gt;마지막으로 &lt;code&gt;Client&lt;/code&gt;에 해당하는 부분입니다. 복제된 객체를 사용합니다.&lt;/p&gt;
&lt;pre class=&quot;pony&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {
        ShapeStore manager = new ShapeStore();
        manager.registerShape();

        Circle cir1 = (Circle)manager.getShape(Type.CIRCLE);
        cir1.draw();
        Circle cir2 = (Circle)manager.getShape(Type.CIRCLE);
        cir2.draw();

        Rectangle rec1 = (Rectangle)manager.getShape(Type.RECTANGLE);
        rec1.draw();

        Triangle tri1 = (Triangle)manager.getShape(Type.TRIANGLE);
        tri1.draw();

    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;실행 결과&lt;/h5&gt;
&lt;pre class=&quot;prolog&quot;&gt;&lt;code&gt;[Circle]입니다.
[Circle]입니다.
[Rectangle]입니다.
[Triangle]입니다&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;그렇다면 왜 사용하는 것일까?&lt;/h5&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;1. 객체의 생성이 값비싼 경우 ( DB를 참조하는 등 ) 객체 생성의 비용을 줄일 수 있습니다. &lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;고려할 사항&lt;/h5&gt;
&lt;p&gt;그러나, 예제에서 사용된 &lt;code&gt;clone()&lt;/code&gt;메소드는 &lt;b&gt;Object&lt;/b&gt; 클래스의 메소드로 써, 얕은 복사로 동작을 합니다.&lt;br /&gt;그렇기 때문에 깊은 복제를 사용해야 할 경우 &lt;code&gt;clone()&lt;/code&gt;메소드를 재정의 해야 합니다.&lt;br /&gt;위와 같은 문제로 복제된 객체의&lt;/p&gt;
&lt;p&gt;순환 참조나 깊은복사 얉은 복사에 대한 고민이 필요&lt;/p&gt;
&lt;h1&gt;4. 관련패턴&lt;/h1&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Flyweight&lt;/code&gt; 패턴 : 프로토타입과 다르게 하나의 인스턴스를 복수의 장소에서 공유해서 이용&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Memento&lt;/code&gt; 패턴 : 스냅샷과 undo를 실행하기 위해 인스턴스의 상태를 저장합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Composite&lt;/code&gt; 및 &lt;code&gt;Decorator&lt;/code&gt; 패턴 : 둘을 사용하면 복잡한 구조의 인스턴스가 동적으로 만들어지는 경우가 있는데, 이와 같은 경우 프로토 타입 패턴을 사용하면 편리합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Command&lt;/code&gt; 패턴 : 해당 패턴의 명령을 복제하고 싶은 경우 프로토타입 패턴을 사용&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>PROGRAMMING/디자인패턴</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/76</guid>
      <comments>https://lee1535.tistory.com/76#entry76comment</comments>
      <pubDate>Wed, 27 Nov 2019 13:01:59 +0900</pubDate>
    </item>
    <item>
      <title>[디자인패턴/Design Pattern] Singleton 패턴 / 싱글톤 패턴</title>
      <link>https://lee1535.tistory.com/75</link>
      <description>&lt;p&gt;관련 내용은 &lt;code&gt;[자바 언어로 배우는 디자인 패턴 입문]&lt;/code&gt; 이라는 책의 공부 내용을 개인적으로 정리한 내용입니다.&lt;br /&gt;처음 배우는 부분이기 때문에 틀린 부분이 있다면 지적해주시면 감사하겠습니다.&lt;br /&gt;또한 관련 내용은 Effective Java의 내용도 포함되어 있습니다.&lt;/p&gt;
&lt;h1&gt;1. Singleton 패턴이란?&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;생성자가 여러 차례 호출되어도 실제 생성되는 객체는 최초의 1개이고, 그 이후의 생성자는 최초 생성자를 통해 생성한 객체를 리턴하는 방식입니다. 즉, 인스턴스가 1개 밖에 존재하지 않는 것을 보증하는 패턴입니다.&lt;/p&gt;
&lt;h1&gt;2. Singleton 패턴의 등장 인물&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;이번 포스팅에서 사용될 요소들의 역할입니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Singleton의 역할
&lt;ol&gt;
&lt;li&gt;유일한 인스턴스를 얻기 위한 &lt;code&gt;static&lt;/code&gt;메소드를 가지며. 이 메소드는 언제나 동일한 인스턴스를 반환하는 역할&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Singleton 패턴의 클래스 다이어그램&lt;/h5&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-filename=&quot;1200px-Singleton_UML_class_diagram.svg.png&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dEdT1R/btqzVnIajtE/u8uCraDQyETDeoKjCYPkF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dEdT1R/btqzVnIajtE/u8uCraDQyETDeoKjCYPkF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dEdT1R/btqzVnIajtE/u8uCraDQyETDeoKjCYPkF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdEdT1R%2FbtqzVnIajtE%2Fu8uCraDQyETDeoKjCYPkF0%2Fimg.png&quot; data-filename=&quot;1200px-Singleton_UML_class_diagram.svg.png&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;720&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;3. 예제&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;이제 Singleton의 예제로 내용을 구체화 해보겠습니다. 다만 &lt;code&gt;Singleton&lt;/code&gt; 방식에 대해서 책의 내용은 입문 책이라 그런지 가장 고전적인 방법을 안내해주고 있어서 추가로 내용을 정리해서 올립니다.&lt;/p&gt;
&lt;h2&gt;3-1. 이 책에서 소개하는 Singleton 패턴&lt;/h2&gt;
&lt;p&gt;가장 기본적인 &lt;code&gt;singleton&lt;/code&gt; 패턴 방식이며, 아래 내용을 이해하기 위한 기본 구조입니다. 하지만 환경에 따라 여러 문제점이 발생하기 때문에 해결법은 아래에서 추가로 설명하겠습니다.&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public class Singleton {
    private static Singleton singleton = new Singleton();
    private Singleton() {
        System.out.println(&quot;인스턴스를 생성했습니다.&quot;);
    }
    public static Singleton getInstance() {
        return singleton;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;문제점&lt;/h5&gt;
&lt;p&gt;위와 같은 방식으로 &lt;code&gt;Singleton&lt;/code&gt; 을 &lt;b&gt;정적 팩토리 방식&lt;/b&gt;으로 생성하면, 간결하다는 장점이 존재한니다.&lt;br /&gt;하지만 &lt;code&gt;Reflection&lt;/code&gt;에 의해서 객체의 &lt;b&gt;인스턴스&lt;/b&gt;는 단 1개만 보장한다는 방식이 파괴되며, 직렬화 과정에서 같은 객체라는 보장이 되지 않습니다. 아래 예시에서 &lt;code&gt;Reflection&lt;/code&gt;에 대한 예시를 설명하겠습니다. 직렬화에 대한 테스트는 독자분들에게 맡기겠습니다.&lt;/p&gt;
&lt;h5&gt;싱글톤 파괴&lt;/h5&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) throws Exception {

        StaticFactorySingleton singleton1 = StaticFactorySingleton.getInstance();
        System.out.println(singleton1.hashCode());

        Constructor cs = StaticFactorySingleton.class.getDeclaredConstructor();
        cs.setAccessible(true);

        StaticFactorySingleton singleton2 = (StaticFactorySingleton)cs.newInstance();
        System.out.println(singleton3.hashCode());
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같이 실행을 하게 되면 일반적인 호출로는 같은 인스턴스를 반환해주지만, &lt;code&gt;reflection&lt;/code&gt;을 사용한 객체는 전혀 새로운 객체를 반환해줍니다.&amp;nbsp;&lt;/p&gt;
&lt;h5&gt;실행 결과&lt;/h5&gt;
&lt;pre class=&quot;dns&quot;&gt;&lt;code&gt;인스턴스를 생성했습니다.
5433634
인스턴스를 생성했습니다.
2430287&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3-2. EFFECTIVE Java에서 소개하는 방법&lt;/h2&gt;
&lt;p&gt;해당 방식전에 &lt;code&gt;Singleton&lt;/code&gt;을 보장( 멀티쓰레드, 직렬화 ) 하기 위한 방식으로 &lt;code&gt;Double Checked Locking&lt;/code&gt; 방식이 존재하지만, 현재 사용하지 않는다고 해서 설명은 생략하지만 관련 글을 읽어보면 좋을거 같아서 링크를 남깁니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://medium.com/@kevalpatel2106/how-to-make-the-perfect-singleton-de6b951dfdb0&quot;&gt;https://medium.com/@kevalpatel2106/how-to-make-the-perfect-singleton-de6b951dfdb0&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1576213860182&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;How to make the perfect Singleton?&quot; data-og-description=&quot;Design Patterns are popular among software developers. A design pattern is a well described solution to a common software problem. The&amp;hellip;&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/@kevalpatel2106/how-to-make-the-perfect-singleton-de6b951dfdb0&quot; data-og-url=&quot;https://medium.com/@kevalpatel2106/how-to-make-the-perfect-singleton-de6b951dfdb0&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b6dYVH/hyD6nVA3x9/gTvLj98QXmkchslD34QLJk/img.jpg?width=1200&amp;amp;height=800&amp;amp;face=0_0_1200_800,https://scrap.kakaocdn.net/dn/TgBTq/hyD6mh49Vs/HmWygb9zA2JJDNwwKtiWNk/img.jpg?width=60&amp;amp;height=40&amp;amp;face=0_0_60_40&quot;&gt;&lt;a href=&quot;https://medium.com/@kevalpatel2106/how-to-make-the-perfect-singleton-de6b951dfdb0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/@kevalpatel2106/how-to-make-the-perfect-singleton-de6b951dfdb0&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b6dYVH/hyD6nVA3x9/gTvLj98QXmkchslD34QLJk/img.jpg?width=1200&amp;amp;height=800&amp;amp;face=0_0_1200_800,https://scrap.kakaocdn.net/dn/TgBTq/hyD6mh49Vs/HmWygb9zA2JJDNwwKtiWNk/img.jpg?width=60&amp;amp;height=40&amp;amp;face=0_0_60_40');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;How to make the perfect Singleton?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Design Patterns are popular among software developers. A design pattern is a well described solution to a common software problem. The&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;medium.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;그러면, 본론으로 들어와서 &lt;code&gt;EFFECTIVE Java&lt;/code&gt;에서 소개하는 방식을 소개하겠습니다.&lt;br /&gt;내용은 간단합니다. &lt;code&gt;singleton&lt;/code&gt;을 사용할 객체를 &lt;code&gt;class&lt;/code&gt;가 아닌 &lt;code&gt;enum&lt;/code&gt;으로 정의하는 방식입니다. 코드는 아래와 같습니다.&lt;/p&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;public enum Singleton {
    INSTANCE;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같은 방식은 우선 &lt;b&gt;간결&lt;/b&gt;하고, 추가의 노력 없이 &lt;b&gt;직렬화&lt;/b&gt;가 가능하고, 심지어 &lt;b&gt;멀티쓰레드&lt;/b&gt;에서도 안정적입니다. 또한 리플렉션으로 생성자에 접근하지도 못합니다.&lt;br /&gt;하지만 만들려는 &lt;code&gt;Singleton&lt;/code&gt;이 &lt;code&gt;Enum&lt;/code&gt; 외의 클래스를 상속해야 하거나, &lt;code&gt;java 1.5&lt;/code&gt;이하 버전이라든지의 상황에서는 사용이 불가능합니다. 또한 메모리에 대한 성능 이슈도 존재합니다.&lt;/p&gt;
&lt;h2&gt;3-3. Initialization-on-demand holder idiom 방식&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;enum&lt;/code&gt; 방식은 안드로이드 개발시에 문제가 발생할 수 있어서 해당 방식이 제일 많이 사용하는 방식입니다. 이 방식을 사용하면, 위 본문에 소개에서 생략한 &lt;code&gt;Double Checked Locking&lt;/code&gt; 과 같은 방식에서 사용한 &lt;code&gt;synchronized&lt;/code&gt;도 필요없어서 성능이 뛰어나고, &lt;code&gt;enum&lt;/code&gt;방식처럼 Java 버전에 상관이 없습니다. 코드는 아래와 같습니다.&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;public class Singleton{
    private Singleton() { }
    public static Singleton getInstance() { 
        return LazyHolder.INSTANCE;
    }

    private static class LazyHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;해당 방식에 대한 설명은 간단히 하자면, 객체가 필요로 할때 초기화를 미뤄서, 불필요하게 메모리를 잡아먹지 않습니다.&lt;br /&gt;&lt;code&gt;Singleton&lt;/code&gt; 클래스를 로드를 해도 &lt;code&gt;LazyHolder&lt;/code&gt; 클래스의 변수가 없기 때문에 메모리에 할당받지 않습니다.&lt;br /&gt;이는 자바 클래스로더 매커니즘을 이용한 방식으로, &lt;code&gt;Singleton&lt;/code&gt;의 &lt;code&gt;getInstance()&lt;/code&gt; 메소드를 호출하는 순간 &lt;code&gt;LazyHolder Class&lt;/code&gt;가 로딩됩니다.&lt;br /&gt;이 때 Class를 로딩하고, 초기화하는 시점에 JVM에 의해서 &lt;code&gt;thread-safe&lt;/code&gt;를 보장하기 때문에, 불필요한 키워드로 인한 성능저하가 없기 때문에 실무에서 가장 많이 사용하는 방식이라고 합니다.&lt;br /&gt;그러나, 다른 방식과 마찬가지로 &lt;code&gt;Reflection&lt;/code&gt;을 통해 파괴가 가능합니다.&lt;/p&gt;
&lt;h1&gt;4.마치며&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;위와 같으 &lt;code&gt;Singleton&lt;/code&gt;을 만드는 방법은 다양하며, 각각 장단점이 존재하니 상황에 따라 필요한 방식으로 선택하면 될 것 같습니다.&lt;/p&gt;
&lt;h1&gt;5. 관련 패턴&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;아래 4개는 인스턴스가 1개인 경우가 많이 존재합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Abstract Factory&lt;/code&gt; 패턴&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Builder&lt;/code&gt; 패턴&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Facade&lt;/code&gt; 패턴&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Prototype&lt;/code&gt; 패턴 &lt;a href=&quot;https://lee1535.tistory.com/76?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>PROGRAMMING/디자인패턴</category>
      <category>Desing pattern</category>
      <category>Java</category>
      <category>Singleton</category>
      <category>디자인패턴</category>
      <category>싱글톤</category>
      <category>자바</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/75</guid>
      <comments>https://lee1535.tistory.com/75#entry75comment</comments>
      <pubDate>Tue, 26 Nov 2019 09:49:09 +0900</pubDate>
    </item>
    <item>
      <title>[디자인패턴/Design Pattern] Factory Method 패턴 / 팩토리 메소드 패턴</title>
      <link>https://lee1535.tistory.com/74</link>
      <description>&lt;p&gt;관련 내용은 &lt;code&gt;[자바 언어로 배우는 디자인 패턴 입문]&lt;/code&gt; 이라는 책의 공부 내용을 개인적으로 정리한 내용입니다.&lt;br /&gt;처음 배우는 부분이기 때문에 틀린 부분이 있다면 지적해주시면 감사하겠습니다.&lt;/p&gt;
&lt;h1&gt;1. Factory Method 패턴이란?&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;상위 클래스에 알려지지 않은 구체 클래스를 생성하는 패턴이며, 하위 클래스가 어떤 객체를 생성할지 결정하도록 하는 패턴입니다. 또한 부모 클래스 코드에 구체 클래스 이름을 감추기 위한 방법으로도 사용합니다.&lt;/p&gt;
&lt;p&gt;Factory Method라는 패턴 이름 때문에 객체를 생성하는 메소드라고 오해할 수 있지만, &lt;code&gt;Template Method&lt;/code&gt;의 생성 버전이라고 볼 수 있다.&lt;/p&gt;
&lt;p&gt;상속을 사용하지만 상위 클래스를 전혀 확장하지 않기 때문에 &lt;code&gt;extends&lt;/code&gt;의 관계를 잘못 이용한 것처럼 보여질 수 있다.&lt;/p&gt;
&lt;pre class=&quot;gcode&quot;&gt;&lt;code&gt;객체 생성에 대한 정의는 하지만, 객체의 생성을 자식클래스(서브클래스)에 위임하는 패턴&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;2. Factory Method 패턴의 등장인물&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;이번 포스팅에서 사용될 요소들의 역할입니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Product( 제품 ) 의 역할
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Factory Method&lt;/code&gt; 패턴에서 생성되는 인스턴스가 가져야 할 인터페이스를 결정하는 추상 클래스&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Creator ( 작성자 ) 의 역할
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Product&lt;/code&gt;의 역할과 인스턴스의 생성 메소드를 가집니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;new&lt;/code&gt; 연산자를 사용해 실제 인스턴스를 생성하는 대신에, 인스턴스 생성을 위한 메소드를 호출해서 구체적인 클래스 이름에 의한 속박에서 상위 클래스를 자유롭게 만듭니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;ConcreteProduct ( 구체적인 제품 ) 의 역할
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Product&lt;/code&gt;의 내용을 정의합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;ConcreteCreator ( 구체적인 작성자 ) 의 역할
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Creator&lt;/code&gt;의 내용을 정의합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Factory Method 패턴의 클래스 다이어그램&lt;/h5&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-filename=&quot;content05.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wBAdt/btqzVaaWSOa/XbwCXDIqk4EpYWe6TKCCL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wBAdt/btqzVaaWSOa/XbwCXDIqk4EpYWe6TKCCL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wBAdt/btqzVaaWSOa/XbwCXDIqk4EpYWe6TKCCL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwBAdt%2FbtqzVaaWSOa%2FXbwCXDIqk4EpYWe6TKCCL0%2Fimg.png&quot; data-filename=&quot;content05.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1&gt;3. 예제&lt;/h1&gt;
&lt;hr /&gt;
&lt;p&gt;이제 Factory Method의 예제로 내용을 구체화 해보겠습니다.&lt;/p&gt;
&lt;h5&gt;예제에서 사용될 클래스 다이어그램&lt;/h5&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-filename=&quot;이미지 16.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bj0YQf/btqzWsB1b4n/aaI9uIE947d6czKS9oAwJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bj0YQf/btqzWsB1b4n/aaI9uIE947d6czKS9oAwJK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bj0YQf/btqzWsB1b4n/aaI9uIE947d6czKS9oAwJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbj0YQf%2FbtqzWsB1b4n%2FaaI9uIE947d6czKS9oAwJK%2Fimg.png&quot; data-filename=&quot;이미지 16.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2&gt;Factory 클래스&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Template Method&lt;/code&gt;패턴을 사용하고 있습니다.&lt;code&gt;create()&lt;/code&gt;라는 메소드를 통해 '생성'한다라는 정의만 하고 자세한 구현은&lt;/p&gt;
&lt;p&gt;&lt;code&gt;protected abstract Calculator createCalculator(Calculator.TYPE type, int a, int b)&lt;/code&gt; 메소드에게 위임합니다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public abstract class Factory {
    public final Calculator create(Calculator.TYPE type,int a, int b ) {
        Calculator c = createCalculator(type, a, b);
        return c;
    }
    protected abstract Calculator createCalculator(Calculator.TYPE type, int a, int b);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;CalculatorFactory 클래스&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Factory&lt;/code&gt; 클래스를 상속 받으며 &lt;code&gt;createCalculator()&lt;/code&gt; 메소드를 재정의해 실제 인스턴스를 생성해서 '제품을 만드는 일'을 담당하고 있습니다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class CalulatorFactory extends Factory {
    @Override
    protected Calculator createCalculator(Calculator.TYPE type,int a, int b) {
        switch(type) {
        case SUM : 
            return new SumCalculator(a, b);
        case DIV : 
            return new DivCalculator(a, b);
        case MUL : 
            return new MulCalculator(a, b);
        }
        return null;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Calculator 클래스&lt;/h2&gt;
&lt;p&gt;제품에 대한 정의로 구현은 하위 클래스에게 위임합니다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public abstract class Calculator {
    public enum TYPE {
        DIV, SUM, MUL
    }
    public abstract void getValue();
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;SumCalculator 클래스&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;CalCulator&lt;/code&gt; 클래스를 상속받으며 &lt;code&gt;getValue()&lt;/code&gt;메소드를 재정의합니다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class SumCalculator extends Calculator{
    private int a;
    private int b;

    public SumCalculator(int a, int b) {
        System.out.println(&quot;덧셈 계산기의 입력 값은 : &quot; + a + &quot; / &quot; + b + &quot; 입니다&quot;);
        this.a = a;
        this.b = b;
    }
    @Override
    public void getValue() {
        System.out.println(&quot;연산 결과 : &quot; + ( a + b));
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;DivCalculator 클래스, MulCalculator 클래스&lt;/h2&gt;
&lt;p&gt;전체적인 로직은 &lt;code&gt;SumCalCulator&lt;/code&gt;클래스와 같으나 재정의 하는 &lt;code&gt;getValue()&lt;/code&gt;메소드 부분이 다르게 정의되어 있습니다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// DivCalculator 클래스
@Override
public void getValue() {
    System.out.println(&quot;연산 결과 : &quot; + ( a - b));
}

// MulCalculator 클래스
@Override
public void getValue() {
    System.out.println(&quot;연산 결과 : &quot; + ( a * b));
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Main 클래스&lt;/h2&gt;
&lt;p&gt;실행로직 클래스입니다. 계산기를 만들어서 사용해 보겠습니다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {

        Factory factory = new CalculatorFactory();

        Calculator sumCalculator = factory.create(Calculator.TYPE.SUM, 5, 3);
        sumCalculator.getValue();

        Calculator divCalculator = factory.create(Calculator.TYPE.DIV, 5, 3);
        divCalculator.getValue();

        Calculator mulCalculator = factory.create(Calculator.TYPE.MUL, 5, 3);
        mulCalculator.getValue();

    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;실행 결과&lt;/h5&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;덧셈 계산기의 입력 값은 : 5 / 3 입니다
연산 결과 : 8
뺄셈 계산기의 입력 값은 : 5 / 3 입니다
연산 결과 : 2
곱셈 계산기의 입력 값은 : 5 / 3 입니다
연산 결과 : 15&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;그렇다면 사용하는 이유는 무엇일까?&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;framework의 수정없이 새로운 '공장'과 '제품'추가가 가능합니다. ( 결합도가 낮다 )
&lt;ul&gt;
&lt;li&gt;전혀 다른 '공학용 계산기'의 제품과 '공학용 계산기 공장'을 해당 framework에 추가해도 해당 클래스들의 내용의 추가만 있을 뿐, 기존 코드에 수정이 필요가 없습니다. 즉 결합도를 낮춰 유지보수에 용이합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h5&gt;단점&lt;/h5&gt;
&lt;p&gt;패턴을 구현하기 위해 새로운 서브 클래스를 계속 생성하므로, 더 복잡해질 수 있다.&lt;/p&gt;
&lt;h5&gt;추가 내용&lt;/h5&gt;
&lt;p&gt;별도로 위 본문에서는 인스턴스 생성을 &lt;code&gt;abstract Method&lt;/code&gt; 즉 추상 메소드로 구현을 하위 클래스에게 강제화 시켰지만,&lt;br /&gt;디폴트로 구현을 하고, 재정의 하지 않을 경우 디폴트가 실행되게 하는방법과, 디폴트 시 에러를 발생 시키는 방법 등이 추가로 존재합니다.&lt;/p&gt;
&lt;h5&gt;default 구현 방식&lt;/h5&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;Class Factory {
    protected Calculator createCalculator(Calculator.TYPE type,int a, int b) {
        // 필요한 로직 작성 ex) return new SumCalculator();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;에러발생 구현 방식&lt;/h5&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;Class Factory {
    protected Calculator createCalculator(Calculator.TYPE type,int a, int b) {
        throw new FactoryMethodRuntimeException();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;4. 관련 패턴&lt;/h1&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Template Method&lt;/code&gt; 패턴 : 팩토리 메소드 패턴은 &lt;code&gt;Template Method&lt;/code&gt; 패턴의 응용 버전입니다. 본문 &lt;code&gt;create()&lt;/code&gt; 메소드 &lt;a href=&quot;https://lee1535.tistory.com/73?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Singleton&lt;/code&gt; 패턴 : 보통 &lt;code&gt;Creator&lt;/code&gt;역할 또는 &lt;code&gt;ConcreteCreator&lt;/code&gt;을 수행 하는 클래스는 대부분 복수로 존재할 필요가 없기 때문에 &lt;code&gt;Singleton&lt;/code&gt; 패턴으로 만들 수 있습니다. 단, 본문 예제에서는 사용하지 않았습니다. &lt;a href=&quot;https://lee1535.tistory.com/75?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Composite&lt;/code&gt; 패턴 : &lt;code&gt;Product&lt;/code&gt; 역할에 적용 가능합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Iterator&lt;/code&gt; 패턴 : 해당 패턴의 &lt;code&gt;iterator()&lt;/code&gt; 가 인스턴스를 작성할 때 &lt;code&gt;Factory Method&lt;/code&gt;패턴이 사용되는 경우가 존재합니다 &lt;a href=&quot;https://lee1535.tistory.com/71?category=819409&quot;&gt;link&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>PROGRAMMING/디자인패턴</category>
      <category>Design Pattern</category>
      <category>Factory Method</category>
      <category>Iterator</category>
      <category>Java</category>
      <category>Singleton</category>
      <category>Template Method</category>
      <category>디자인패턴</category>
      <category>자바</category>
      <author>효기로그</author>
      <guid isPermaLink="true">https://lee1535.tistory.com/74</guid>
      <comments>https://lee1535.tistory.com/74#entry74comment</comments>
      <pubDate>Fri, 22 Nov 2019 11:19:12 +0900</pubDate>
    </item>
  </channel>
</rss>