<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>ye-geeee.log</title>
        <link>https://velog.io/</link>
        <description>재밌는 것만 하고 싶어 ʕ•ﻌ•ʔ </description>
        <lastBuildDate>Fri, 17 Dec 2021 07:31:31 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>ye-geeee.log</title>
            <url>https://images.velog.io/images/ye-geeee/profile/589908c6-91a0-416a-817c-4337e1b4b209/KakaoTalk_Photo_2021-03-22-06-11-43.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. ye-geeee.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/ye-geeee" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[도커 이미지]]></title>
            <link>https://velog.io/@ye-geeee/%EB%8F%84%EC%BB%A4-%EC%9D%B4%EB%AF%B8%EC%A7%80</link>
            <guid>https://velog.io/@ye-geeee/%EB%8F%84%EC%BB%A4-%EC%9D%B4%EB%AF%B8%EC%A7%80</guid>
            <pubDate>Fri, 17 Dec 2021 07:31:31 GMT</pubDate>
            <description><![CDATA[<h1 id="21-도커-이미지와-컨테이너">2.1 도커 이미지와 컨테이너</h1>
<h2 id="211-도커-이미지">2.1.1 도커 이미지</h2>
<p>컨테이너를 생성할 때, 필요한 요소이며 iso파일과 비슷한 개념입니다. </p>
<p>컨테이너를 생성하고 실행할 때 읽기 전용으로 사용됩니다.
아래와 같이 이미지에는 <code>repository</code>, <code>image</code>, <code>tag</code> 가 있습니다. </p>
<p>[repository] / [image] : [tag]</p>
<ul>
<li><code>repository</code>는 저장소로 명시되지 않으면 도커 허브의 공식 이미지를 뜻합니다.</li>
<li><code>image</code>는 해당 이미지가 어떤 역할을 하는지 나타냅니다.</li>
<li><code>tag</code>는 버전관리 혹은 리비전 관리에 사용합니다. 생략할 경우 latest를 뜻합니다.</li>
</ul>
<p>ex. ubuntu:latest</p>
<h2 id="212-도커-컨테이너">2.1.2 도커 컨테이너</h2>
<p>이미지를 통해 도커 컨테이너를 생성하면 격리된 시스템 자원 및 네트워크를 사용할 수 있는 독립된 공간이 생성됩니다. </p>
<p>이 컨테이너는 이미지를 읽기 전용으로 사용하되 이미지에서 변경된 사항만 컨테이너 계층에 저장합니다. 따라서, 컨테이너에서 어떤 일을 하든 원래 이미지는 영향을 받지 않습니다. </p>
<h1 id="22-도커-컨테이너-다루기">2.2 도커 컨테이너 다루기</h1>
<h2 id="221-컨테이너-생성">2.2.1 컨테이너 생성</h2>
<h3 id="docker--v">docker -v</h3>
<p>도커 버전 확인을 위한 커맨드입니다.</p>
<h3 id="docker-run--i--t-imagetag">docker run -i -t [image]:[tag]</h3>
<p>ex. docker run -i -t ubuntu:14.04</p>
<p>도커 컨테이너를 생성하고 실행하는 커맨드입니다.</p>
<p>이미지가 로컬 엔진에 없을 경우, 도커 허브에서 자동으로 이미지를 내려받습니다. </p>
<ul>
<li>-i : 상호 입출력 활성화</li>
<li>-t : tty를 활성화</li>
</ul>
<pre><code class="language-bash">ye-geeee@192  ~  docker run -i -t ubuntu:14.04
root@91e008573de6:/#
root@91e008573de6:/# ls
bin   dev  home  media  opt   root  sbin  sys  usr
boot  etc  lib   mnt    proc  run   srv   tmp  var
root@91e008573de6:/#
ye-geeee@192  ~ </code></pre>
<p>run을 할 경우, 컨테이너를 생성, 실행 그리고 컨테이너 내부에 들어오는 것까지 동작을 수행합니다.</p>
<p>호스트 이름은 이때 무작위 16진수 해쉬값이고, 91e008573de6은 고유 ID의 앞부분입니다. </p>
<p>컨테이너를 빠져 나올 때는 두 가지 방법이 있습니다.</p>
<ul>
<li><code>exit</code> cmd 또는 Ctrl + D : 컨테이너 내부를 따져나오면서 동시에 컨테이너를 정지시킵니다.</li>
<li>Ctrl + P, Q : 단순히 컨테이너의 셸에서만 빠져나옵니다.</li>
</ul>
<h3 id="docker-pull-repositoryimagetag">docker pull [repository]/[image]:[tag]</h3>
<p>도커 이미지 다운 받을 때 사용하는 커맨드입니다.</p>
<pre><code class="language-bash">gang-yeji@192  ~  docker pull centos:7
7: Pulling from library/centos
6717b8ec66cd: Pull complete
Digest: sha256:0f4ec88e21daf75124b8a9e5ca03c37a5e937e0e108a255d890492430789b60e
Status: Downloaded newer image for centos:7
docker.io/library/centos:</code></pre>
<h3 id="docker-images">docker images</h3>
<p>도커 엔진에 존재하는 이미지의 목록을 출력합니다.</p>
<pre><code class="language-bash">ye-geeee@192  ~  docker images
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
mysql        latest    5a4e492065c7   3 weeks ago     514MB
ubuntu       14.04     423c4ed354ff   3 months ago    187MB
centos       7         e5df02c43685   10 months ago   301MB</code></pre>
<h3 id="docker-create--i--t-name-컨테이너명-imagetag">docker create -i -t —name [컨테이너명] [image]:[tag]</h3>
<p>도커 컨테이너를 생성하는 커맨드입니다.</p>
<p><code>—name</code> 옵션에 컨테이너 이름을 설정합니다. 아래 나오는 16진수 해시값이 컨테이너의 고유 ID입니다.</p>
<p><code>create</code> 커맨드로는 컨테이너 내부로 진입하지 않습니다. </p>
<pre><code class="language-bash">✘ ye-geeee@192  ~  docker create -i -t --name mycentos centos:7
2727851ed7ec07ff566f58ef2a3cf5d9b1b7508136e885b137d03edba8234d7a</code></pre>
<h3 id="docker-start-컨테이너명">docker start [컨테이너명]</h3>
<p>생성한 컨테이너를 실행시킬 때 사용하는 커맨드입니다. </p>
<p>컨테이너를 실행시킬 때에는 컨테이너명 대신 16진수 컨테이너 ID를 사용할 수도 있습니다. ID 전체를 넣을 필요 없이 식별되는 2~3자리만 기입을 하면 됩니다. </p>
<pre><code class="language-bash">✘ ye-geeee@192  ~  docker start mycentos
mycentos</code></pre>
<h3 id="docker-stop-컨테이너명">docker stop [컨테이너명]</h3>
<p>실행 중인 컨테이너를 중지시킬 때 사용하는 커맨드입니다. </p>
<h3 id="docker-attach-컨테이너명">docker attach [컨테이너명]</h3>
<p>도커 컨테이너 내부에 진입하기 위해 사용하는 커맨드입니다. </p>
<pre><code class="language-bash">✘ ye-geeee@192  ~  docker attach mycentos
[root@2727851ed7ec /]#</code></pre>
<h2 id="222-컨테이너-목록-확인">2.2.2 컨테이너 목록 확인</h2>
<h3 id="docker-ps">docker ps</h3>
<p>지금까지 생성한 도커 컨테이너 목록을 확인합니다. </p>
<pre><code class="language-bash">✘ ye-geeee@192  ~  docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                               NAMES
2727851ed7ec   centos:7       &quot;/bin/bash&quot;              7 minutes ago    Up 5 minutes                                        mycentos
91e008573de6   ubuntu:14.04   &quot;/bin/bash&quot;              22 minutes ago   Up 22 minutes                                       sad_yonath
cdd5df6f6e10   mysql:latest   &quot;docker-entrypoint.s…&quot;   2 weeks ago      Up 2 weeks      0.0.0.0:3306-&gt;3306/tcp, 33060/tcp   moniapp-db
✘ ye-geeee@192  ~  docker ps -a
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS                  PORTS                               NAMES
2727851ed7ec   centos:7       &quot;/bin/bash&quot;              9 minutes ago    Up 6 minutes                                                mycentos
91e008573de6   ubuntu:14.04   &quot;/bin/bash&quot;              23 minutes ago   Up 23 minutes                                               sad_yonath
78d292dfd430   ubuntu:14.04   &quot;/bin/bash&quot;              4 days ago       Exited (0) 4 days ago                                       agitated_kapitsa
cdd5df6f6e10   mysql:latest   &quot;docker-entrypoint.s…&quot;   2 weeks ago      Up 2 weeks              0.0.0.0:3306-&gt;3306/tcp, 33060/tcp   moniapp-db
✘ ye-geeee@192  ~  docker ps --format &quot;table {{.ID}}&quot;
CONTAINER ID
2727851ed7ec
91e008573de6
cdd5df6f6e10</code></pre>
<ul>
<li><code>-a</code> 옵션 : 옵션을 사용하지 않으면, 현재 정지 되지 않은 컨테이너만 출력합니다. 이 옵션을 사용하면 전체 컨테이너를 확인할 수 있습니다.</li>
<li><code>--format &quot;table {{.ID}}&quot;</code> 옵션: &quot;table {{.[Column명]}}\t{{.[Column명}}&quot; 에 보고 싶은 정보들만 넣어줍니다.</li>
</ul>
<h3 id="docker-rename-기존-컨테이너명-새로운-컨테이너명">docker rename [기존 컨테이너명] [새로운 컨테이너명]</h3>
<p>컨테이너명을 변경할 때 사용하는 커맨드입니다. </p>
<h2 id="223-컨테이너-삭제">2.2.3 컨테이너 삭제</h2>
<h3 id="docker-rm-컨테이너명">docker rm [컨테이너명]</h3>
<p>도커 컨테이너를 삭제할 때 사용하는 커맨드입니다.</p>
<pre><code class="language-bash">✘ ye-geeee@192@192  ~  docker rm agitated_kapitsa
agitated_kapitsa
✘ ye-geeee@192@192  ~  docker ps -a
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                               NAMES
2727851ed7ec   centos:7       &quot;/bin/bash&quot;              15 minutes ago   Up 13 minutes                                       centos
91e008573de6   ubuntu:14.04   &quot;/bin/bash&quot;              30 minutes ago   Up 30 minutes                                       sad_yonath
cdd5df6f6e10   mysql:latest   &quot;docker-entrypoint.s…&quot;   2 weeks ago      Up 2 weeks      0.0.0.0:3306-&gt;3306/tcp, 33060/tcp   moniapp-db
✘ ye-geeee@192  ~  docker rm centos
Error response from daemon: You cannot remove a running container 2727851ed7ec07ff566f58ef2a3cf5d9b1b7508136e885b137d03edba8234d7a. Stop the container before attempting removal or force remove
✘ ye-geeee@192@192  ~  docker stop centos
centos
 gang-yeji@192  ~  docker rm centos
centos</code></pre>
<p>실행중인 도커 컨테이너는 삭제할 수 없으므로 <code>docker stop [컨테이너명]</code> 을 통해 중지한 후에 컨테이너를 삭제합니다. </p>
<h3 id="docker-container-prune">docker container prune</h3>
<p>전체 컨테이너를 일괄로 모두 삭제할 때 사용하는 커맨드입니다. </p>
<h2 id="224-컨테이너를-외부에-노출">2.2.4 컨테이너를 외부에 노출</h2>
<p>외부에 컨테이너 애플리케이션을 노출하기 위해서는 eth0의 IP와 포트를 호스트의 IP와 포트에 바인딩해야 합니다.</p>
<p><code>run</code> 을 할 때에 <code>-p</code> 옵션을 통해 포트 바인딩을 합니다.</p>
<pre><code class="language-bash">✘ ye-geeee@192  ~  docker run -i -t -p 7000:80 ubuntu:14.04
root@909090adb7a2:/#</code></pre>
<h2 id="225-컨테이너-애플리케이션-구축">2.2.5 컨테이너 애플리케이션 구축</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[React Hooks]]></title>
            <link>https://velog.io/@ye-geeee/React-Hooks</link>
            <guid>https://velog.io/@ye-geeee/React-Hooks</guid>
            <pubDate>Thu, 09 Sep 2021 22:09:51 GMT</pubDate>
            <description><![CDATA[<p>본 포스팅은 &#39;실무에서 알아야할 기술은 따로 있다! 리액트를 다루는 기술&#39;을 보고 정리한 글입니다. </p>
<h1 id="hooks">Hooks?</h1>
<p>Hook는 리액트 v16.8부터 함수형 컴포넌트에서도 상태 관리를 할 수 있는 기능을 제공합니다. </p>
<h1 id="usestate">useState</h1>
<p><a href="https://github.com/ye-geeee/react-sample/commit/4fb06f21144a017e540bf873fa88c4e56762aa5b">reference code</a></p>
<p><code>useState</code>는 컴포넌트에서 상태를 관리할 때 기본적으로 사용하는 Hook입니다.</p>
<ol>
<li><code>react</code> 로부터 import 해줍니다.</li>
<li><code>useState(초기값)</code> 을 통해 초기값을 지정해줍니다.</li>
<li>상태를 변화시킬 때에는 <code>set변수명</code> 을 통해 변화시킵니다.</li>
</ol>
<pre><code class="language-jsx">import React, { useState } from &#39;react&#39;;

const Info = () =&gt; {
  const [name, setName] = useState(&#39;&#39;);
  const [nickName, setNickName] = useState(&#39;&#39;);

  const onChangeName = e =&gt; {
    setName(e.target.value);
  };

  const onChangeNickName = e =&gt; {
    setNickName(e.target.value);
  };
  ...
}</code></pre>
<h1 id="useeffect">useEffect</h1>
<p><code>useEffect</code>는 리액트 컴포넌트가 렌더링될 때마다 특정 작업을 수행하도록 설정할 수 있는 Hook입니다.</p>
<p><code>componentDidMount</code>와 <code>componentDidUpdate</code> 를 합친 형태라고 볼 수 있습니다. </p>
<h2 id="useeffect를-사용해보자">useEffect를 사용해보자!</h2>
<p><a href="https://www.notion.so/jsx-176796a4cdbb46b0b6555f14bba2a93e">reference code</a></p>
<pre><code class="language-jsx">import React, { useState, useEffect } from &#39;react&#39;;

const Info = () =&gt; {
  const [name, setName] = useState(&#39;&#39;);
  const [nickName, setNickName] = useState(&#39;&#39;);
  useEffect(() =&gt; {
    console.log(&#39;rendering ready&#39;);
    console.log({ name, nickName });
  });

  ...

};

export default Info;</code></pre>
<p>위 처럼 작성할 경우, 렌더링이 될 때마다 <code>useEffect</code>가 불리게 됩니다.</p>
<h2 id="마운트될-때만-useeffect를-사용해보자">마운트될 때만 useEffect를 사용해보자!</h2>
<p><a href="https://github.com/ye-geeee/react-sample/commit/615e475e27fca13f37db470d241559c8db10b1b4">reference code</a></p>
<p>업데이트를 제외하고 처음 렌더링 할 때만 <code>useEffect</code>를 사용하려면 아래와 같이 두 번째 파라미터에 빈 값을 넣어줍니다.</p>
<pre><code class="language-jsx">useEffect(() =&gt; {
    console.log(&#39;only when mounted&#39;);
  }, []);</code></pre>
<h2 id="특정값이-업데이트될-때만-useeffect를-사용해보자">특정값이 업데이트될 때만 useEffect를 사용해보자!</h2>
<p><a href="https://github.com/ye-geeee/react-sample/commit/827dfe035a0bb0758160ed54127390f906e9e222">reference code</a></p>
<p>특정값이 업데이트 될 때만 실행하고 싶다면 아래와 같이 모니터링하고 싶은 특정값을 두 번째 파라미터로 넣어줍니다.</p>
<pre><code class="language-jsx">useEffect(() =&gt; {
    console.log(name);
  }, [name]);</code></pre>
<h2 id="cleanup">Cleanup</h2>
<p><a href="https://github.com/ye-geeee/react-sample/commit/18567ede2acbb16c5d667c770e6095edbc0bfe26">code reference</a></p>
<p>컴포넌트가 언마운트되기 전이나 업데이트 되기 전에 어떠한 작업을 수행하고 싶다면 <code>useEffect</code> 에 return으로 수행하고 싶은 cleanup함수를 넘겨줍니다.</p>
<pre><code class="language-jsx">useEffect(() =&gt; {
    console.log(&#39;effect&#39;);
    console.log(name);
    return (() =&gt; {
      console.log(&#39;cleanup&#39;);
      console.log(name);
    });
  }, [name]);</code></pre>
<h1 id="usereducer">useReducer</h1>
<p><a href="https://github.com/ye-geeee/react-sample/blob/4ec100cc24d339f9b13c288c9bf35987b8a2b55d/basic/src/Info.js">reference code</a></p>
<p><code>useReducer</code> 함수는 더 다양한 상황에 따라 다양한 상태의 다른 값을 업데이트 해줄 때에 사용하는 Hook입니다. </p>
<p><code>action</code>을 통해 업데이트에 필요한 값을 전달 받아 새로운 상태를 반환합니다. </p>
<pre><code class="language-jsx">import React, { useState, useEffect, useReducer } from &#39;react&#39;;

function reducer(state, action) {
  return {
    ...state,
    [action.name]: action.value
  };
}

const Info = () =&gt; {
  const [state, dispatch] = useReducer(reducer, {
    name: &#39;&#39;,
    nickName: &#39;&#39;
  });
  const { name, nickName } = state;
  const onChange = e =&gt; {
    dispatch(e.target);
  }

  ...

}</code></pre>
<h1 id="usememo">useMemo</h1>
<p><a href="https://github.com/ye-geeee/react-sample/commit/5dc94f4154390b069cba919915358c1007a290fd">sample code to refactor</a></p>
<p>위의 코드는 값이 추가될 때마다 평균값을 연산하는 코드입니다.</p>
<p>하지만, 로그를 확인해보면 버튼을 눌렀을 때만 값을 출력하는 것이 아니라 숫자가 변경될 때마다 <code>getAverage</code> 함수가 호출되는 것을 확인할 수 있습니다.</p>
<p><img src="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/1d7169a8-b3ee-4a73-b26f-68cd3e94beff/Untitled.png" alt="Untitled"></p>
<p>이렇게 버튼이 눌렸을 때만 연산을 수행해도 되는데 숫자가 변경될 때마다 연산을 수행하는 것을 방지하기 위해 <code>useMemo</code>를 사용합니다. 즉, 렌더링 성능을 최적화 시키는 데에 사용한다고 할 수 있습니다. </p>
<p><a href="https://github.com/ye-geeee/react-sample/commit/b64150ce64edb26d9817603c25c69d24ecf8f347">reference code</a></p>
<pre><code class="language-jsx">import React, { useState, useMemo } from &#39;react&#39;;

...

const Average = () =&gt; {

  ...

    const avg = useMemo(() =&gt; getAverage(list), [list]);

    return (
        &lt;div&gt;
            &lt;input value={number} onChange={onChange} /&gt;
            &lt;button onClick={onInsert}&gt;Insert&lt;/button&gt;
            &lt;ul&gt;
                {list.map((value, index) =&gt; (
                    &lt;li key={index}&gt;{value}&lt;/li&gt;
                ))}
            &lt;/ul&gt;
            &lt;div&gt;
                &lt;b&gt;Average:&lt;/b&gt;{avg}
            &lt;/div&gt;
        &lt;/div&gt;
    );
}</code></pre>
<p>이제, 숫자가 변화하는 것이 아니라 list 배열의 내용이 바뀔 때만 <code>getAverage</code> 함수가 호출됩니다. </p>
<h1 id="usecallback">useCallback</h1>
<p><code>useCallback</code> 도 렌더링 성능을 최적화시키는 데에 사용하는 함수입니다. <code>useMemo</code>와 다르게 <code>useCallback</code> 은 함수 재사용을 가능하게 하여 성능을 향상시킵니다. </p>
<pre><code class="language-jsx">const Average = () =&gt; {
    const [list, setList] = useState([]);
    const [number, setNumber] = useState(&#39;&#39;);

    const onChange = e =&gt; {
        setNumber(e.target.value);
    };

    const onInsert = e =&gt; {
        const nextList = list.concat(parseInt(number));
        setList(nextList);
        setNumber(&#39;&#39;);
    };

        ...
}</code></pre>
<p>위의 코드는 컴포넌트가 리렌더링 될 때마다 <code>onChange</code> 함수와 <code>onInsert</code> 함수를 새로 생성합니다. 이러한 경우, 컴포넌트의 렌더링이 자주 발생하거나 컴포넌트의 개수가 많아질 때 최적화를 해주는 것이 좋습니다.</p>
<h2 id="usecallback으로-함수-재생성을-최적화한-코드">useCallback으로 함수 재생성을 최적화한 코드</h2>
<pre><code class="language-jsx">const Average = () =&gt; {
    const [list, setList] = useState([]);
    const [number, setNumber] = useState(&#39;&#39;);

    const onChange = useCallback(e =&gt; {
        setNumber(e.target.value);
    }, []);

    const onInsert = useCallback(e =&gt; {
        const nextList = list.concat(parseInt(number));
        setList(nextList);
        setNumber(&#39;&#39;);
    }, [number, list]);

    ...
}</code></pre>
<p>위의 코드에서는 <code>useCallback</code> 을 통해 함수 생성을 최적화하였습니다. 첫 번째 파라미터에는 생성하고 싶은 함수를 넣고, 두 번째 파라미터에는 어떤 값이 바뀌었을 때 함수를 새로 생성해야 하는지 명시합니다.</p>
<p>두 번째 파라미터에 빈 배열을 넣을 경우, 컴포넌트 렌더링 되었을 때 단 한 번만 함수가 생성되고, 값을 넣었을 경우, 해당 값에 변화가 있거나 새로운 항목이 추가될 경우 함수가 새로 생성됩니다. </p>
<h1 id="useref">useRef</h1>
<p><code>useRef</code> 는 함수형 컴포넌트에서 <code>ref</code> 를 쉽게 사용할 수 있도록 해줍니다. 아래는 버튼을 눌렀을 때, 포커스를 안쪽으로 넘어가도록 한 코드입니다.</p>
<p><a href="https://github.com/ye-geeee/react-sample/blob/04e2732bddee093bb5d720db15bfaad5ec02cbe6/basic/src/Average.js">reference code</a></p>
<pre><code class="language-jsx">import React, { useState, useMemo, useCallback, useRef } from &#39;react&#39;;

...

const Average = () =&gt; {
    const [list, setList] = useState([]);
    const [number, setNumber] = useState(&#39;&#39;);
    const inputE1 = useRef(null);

        ...

    const onInsert = useCallback(e =&gt; {
        ... 
        inputE1.current.focus();
    }, [number, list]);

    const avg = useMemo(() =&gt; getAverage(list), [list]);

    return (
        &lt;div&gt;
            &lt;input value={number} onChange={onChange} ref={inputE1} /&gt;
            ...
        &lt;/div&gt;
    );
};

export default Average;</code></pre>
<p>또한, <code>useRef</code> 는 렌더링과 관련되지 않은 값들을 관리할 때에 사용할 수 있습니다.</p>
<h1 id="hook-정리">Hook 정리</h1>
<ul>
<li><code>useState</code> : Component의 상태를 업데이트 할 때</li>
<li><code>useEffect</code> : 컴포넌트가 렌더링 될 때 동작을 수행하도록 할 때</li>
<li><code>useReducer</code> : 다양한 상태의 다양한 값을 업데이트 해줄 때</li>
<li><code>useMemo</code> : 숫자, 문자열, 객체처럼 일반 값을 재사용할 때</li>
<li><code>useCallback</code> : 함수를 재사용할 때</li>
<li><code>useRef</code> : <code>ref</code> 를 사용할 때</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[01 도커란?]]></title>
            <link>https://velog.io/@ye-geeee/01-%EB%8F%84%EC%BB%A4%EB%9E%80</link>
            <guid>https://velog.io/@ye-geeee/01-%EB%8F%84%EC%BB%A4%EB%9E%80</guid>
            <pubDate>Thu, 09 Sep 2021 09:59:35 GMT</pubDate>
            <description><![CDATA[<p>본 포스팅은 &quot;시작하세요! 도커/쿠버네티스&quot;를 읽고 정리한 글입니다.</p>
<blockquote>
<p><strong>도커는?</strong> 
리눅스 컨테이너에 여러 기능을 추가함으로써 애플리케이션을 컨테이너로서 좀 더 쉽게 사용할 수 있게 만들어진 오픈소스 프로젝트</p>
</blockquote>
<p>Go언어로 작성되었으며 성능에 손실이 거의 없다는 특징을 가지고 있습니다.</p>
<h1 id="11-가상-머신과-도커-컨테이너">1.1 가상 머신과 도커 컨테이너</h1>
<p>우선, 가상 머신과 도커 컨테이너를 비교해봅시다.</p>
<p><img src="https://gblobscdn.gitbook.com/assets%2F-M1TxO6lPQE2b5vWOIk9%2F-M1U9Pbm5zKP_maqE7_j%2F-M1UB2No2H2sWxm1YEXI%2Fimage.png?alt=media&token=a19d66a8-c0c2-46fb-a9ea-c51bfbe3e179" alt="https://gblobscdn.gitbook.com/assets%2F-M1TxO6lPQE2b5vWOIk9%2F-M1U9Pbm5zKP_maqE7_j%2F-M1UB2No2H2sWxm1YEXI%2Fimage.png?alt=media&amp;token=a19d66a8-c0c2-46fb-a9ea-c51bfbe3e179"></p>
<h2 id="가상-머신virtual-machines">가상 머신(Virtual Machines)</h2>
<p>하이퍼바이저에 의해 생성되고 관리되는 운영체제를 게스트 운영체제(Guest OS)라고 합니다. </p>
<p>각 게스트 운영체제는 완전히 독립된 공간과 시스템 자원을 할당받아 사용됩니다.</p>
<p>가상 머신의 단점은 아래와 같습니다.</p>
<ul>
<li>하이퍼바이저에 의해 독립된 공간을 생성하기 때문에 성능 손실이 있습니다.</li>
<li>게스트 운영체제에 라이브러리, 커널을 모두 포함하기 때문에 배포하기 위한 이미지의 크기가 커집니다.</li>
</ul>
<p>즉, 가상 머신은 완벽한 운영체제를 생성할 수 있지만, 일반 호스트에 비해 성능 손실이 있고, 배포하기에 부담스러울 수 있습니다.</p>
<h2 id="도커-컨테이너docker-containers">도커 컨테이너(Docker Containers)</h2>
<p>가상 머신에 대비한 도커 컨테이너의 장점은 아래와 같습니다. </p>
<ul>
<li>프로세스 단위로 격리 환경을 만들기 때문에 성능 손실이 거의 없습니다.</li>
<li>커널은 호스트의 커널을 공유해 사용하고, 컨테이너 안에는 애플리케이션 구동하는데 필요한 라이브러리와 실행 파일만 존재하여 이미지의 크기가 가상 머신에 비해 작습니다.</li>
</ul>
<p>즉, 배포 시간이 가상 머신에 비해 빠르고, 성능 손실이 거의 없다는 장점이 있습니다.</p>
<h1 id="12-도커를-시작해야-하는-이유">1.2 도커를 시작해야 하는 이유</h1>
<ol>
<li>애플리케이션의 개발과 배포가 편해집니다. <ul>
<li>독립된 개발 환경을 보장받을 수 있습니다.</li>
<li>&#39;도커 이미지&#39;를 만들어 운영 서버에 전달하기만 하면 됩니다.</li>
<li>애플리케이션의 배포 속도가 매우 빨라집니다.</li>
</ul>
</li>
<li>여러 애플리케이션의 독립성과 확장성이 높아집니다.<ul>
<li>여러 무돌에게 독립된 환경을 제공할 수 있기 때문에 마이크로서비스 구조에 적합합니다.</li>
</ul>
</li>
</ol>
<h1 id="13-도커-엔진-설치">1.3 도커 엔진 설치</h1>
<p>맥북을 사용하는 경우, 아래의 링크에서 도커를 다운받을 수 있습니다. </p>
<p><a href="https://hub.docker.com/editions/community/docker-ce-desktop-mac">https://hub.docker.com/editions/community/docker-ce-desktop-mac</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Springdoc]]></title>
            <link>https://velog.io/@ye-geeee/Springdoc-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@ye-geeee/Springdoc-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 05 Sep 2021 14:18:50 GMT</pubDate>
            <description><![CDATA[<h1 id="swagger-ui">Swagger UI</h1>
<p>API Document를 보여주기 위해 Swagger UI를 많이 사용합니다.</p>
<p>Spring 프로젝트에서 Swagger UI를 사용하려고 가장 많이 사용하는 두 라이브러리는 <code>spring-fox</code> 그리고 <code>springdoc-openapi-ui</code> 두 가지입니다.</p>
<p>원래 <code>spring-fox</code> 를 적용한 경험이 있는데, 현재 밀고 있는 것이 <code>springdoc</code> 이라길래 <code>springdoc</code> 을 한 번 적용해보려 합니다.</p>
<h1 id="환경-설정하기">환경 설정하기</h1>
<p>첫 번째로, <code>build.gradle</code> 을 수정해줘야 합니다. </p>
<pre><code class="language-bash">dependencies {
    ... 

    // Springdoc
    implementation &#39;org.springdoc:springdoc-openapi-ui:1.5.10&#39;</code></pre>
<p>설정한 다음 아래와 같은 경로로 진입할 경우, 사진처럼 Swagger UI 화면을 볼 수 있습니다.</p>
<p>[server address]/swagger-ui.html</p>
<p><img src="https://images.velog.io/images/ye-geeee/post/735b7f79-9062-4835-bfe4-8d36925f9c63/Screen%20Shot%202021-09-06%20at%207.16.36%20AM.png" alt=""></p>
<h3 id="reference">Reference</h3>
<p><a href="https://springdoc.org/#getting-started">https://springdoc.org/#getting-started</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[리액트 라이프사이클 (React LifeCycle)]]></title>
            <link>https://velog.io/@ye-geeee/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%9D%BC%EC%9D%B4%ED%94%84%EC%82%AC%EC%9D%B4%ED%81%B4-React-LifeCycle</link>
            <guid>https://velog.io/@ye-geeee/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%9D%BC%EC%9D%B4%ED%94%84%EC%82%AC%EC%9D%B4%ED%81%B4-React-LifeCycle</guid>
            <pubDate>Tue, 24 Aug 2021 21:33:34 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>본 포스팅은 &#39;실무에서 알아야 할 기술은 따로 있다! 리액트를 다루는 기술&#39; 을 보고 정리한 것입니다.</p>
</blockquote>
<h1 id="react-lifecycle">React LifeCycle</h1>
<p><code>React</code> 에서 라이프 사이클은 크게 &#39;마운트&#39;, &#39;업데이트&#39;, &#39;언마운트&#39;로 구분합니다. 세 카테고리의 순서는 아래와 같습니다. </p>
<p><img src="https://images.velog.io/images/ye-geeee/post/0d5cb2c4-ef01-4b82-8311-340780a1bff2/Screen%20Shot%202021-08-24%20at%2011.23.27%20PM.png" alt="">
라이프 사이클 함수들 중에 &#39;Will&#39; 접두사가 붙은 메소드는 어떤 작업을 작동하기 전에 실행되는 메소드이고, &#39;Did&#39; 접두사가 붙은 메서드는 어떤 작업이 작동한 후에 실행되는 메소드입니다. 자세한 것은 예제를 차차 알아가도록 하겠습니다!</p>
<h1 id="mount">Mount</h1>
<p>DOM이 생성되고 웹 브라우저 상에 나타나는 것을 마운트(Mount)라고 합니다. 자세한 순서는 아래와 같습니다.</p>
<p><img src="https://images.velog.io/images/ye-geeee/post/0ad30713-c42d-49ce-b661-d069a415035a/Screen%20Shot%202021-08-24%20at%2011.24.34%20PM.png" alt=""></p>
<h1 id="update">Update</h1>
<p>update가 되는 경우는 아래 네 가지 경우가 있습니다. </p>
<ol>
<li>props가 바뀔 때</li>
<li>state가 바뀔 때</li>
<li>부모 컴포넌트가 리렌더링될 때</li>
<li>this.forceUpdate로 강제로 렌더링을 트리거할 때</li>
</ol>
<p><img src="https://images.velog.io/images/ye-geeee/post/0f4d01e7-da54-4500-9f8b-d4ad4e787375/Screen%20Shot%202021-08-24%20at%2011.24.58%20PM.png" alt=""></p>
<p>1, 2, 3번의 경우 화면 갱신 단계의 첫 번째부터 이루어지지만, <code>forceUpdate</code> 함수를 강제로 트리거 하였을 경우에는 이전 단계 없이 바로 <code>render</code> 함수를 실행합니다. </p>
<p>여기서 <code>shouldComponentUpdate</code> 함수는  리렌더링을 할지 말지 결정하는 함수이고, 리턴값은 true 또는 false입니다. 리턴값이 true일 경우에만 <code>render</code> 함수를 수행하고, false의 경우에는 리렌더링을 종료합니다. </p>
<h1 id="unmount">Unmount</h1>
<p><img src="https://images.velog.io/images/ye-geeee/post/9a5bb113-17ca-4d08-b33d-3caed69e2f7c/Screen%20Shot%202021-08-24%20at%2011.24.45%20PM.png" alt=""></p>
<p>언마운트(Unmount)의 경우에는 컴포넌트가 웹 브라우저 상에서 사라지기 전에 호출하는 메소드인 <code>componentWillUnmount</code> 만 호출하고 종료됩니다. </p>
<h1 id="lifecycle-method">LifeCycle Method</h1>
<h2 id="render">render()</h2>
<p>컴포넌트의 모양새를 정의하며 라이프사이클 메소드 중에 유일하게 필수인 메소드입니다. </p>
<p>메소드 내에서 <code>this.props</code> 와 <code>this.state</code> 에 접근이 가능하고, 리액트 요소를 반환합니다. </p>
<p>아무것도 보여주지 않고 싶을 때는 <code>null</code> 또는 <code>false</code> 를 반환합니다.</p>
<p>메소드 내에서 이벤트 설정이 아닌 곳에서 <code>setState</code> 를 사용하면 안되며, 브라우저의 DOM에 접근해서도 안됩니다. (DOM 정보를 가져오거나 <code>state</code> 에 변화를 줄 때는 <code>componentDidMount</code> 에서 처리합니다.)</p>
<h2 id="constructor">constructor</h2>
<p>컴포넌트를 만들 때 처음으로 실행되고, 초기 <code>state</code> 를 정의할 수 있습니다. </p>
<h2 id="getderivedstatefromprops">getDerivedStateFromProps</h2>
<p>부모 Component로 부터 받은 <code>props</code> 를 <code>state</code> 에 동기화시키기 위해 사용합니다. </p>
<h2 id="componentdidmount">componentDidMount</h2>
<p>렌더링을 마친 후에 수행됩니다. </p>
<p>다른 자바스크립트 라이브러리 또는 프레임워크의 함수를 호출하거나 이벤트 등록, <code>setTimeout</code>, <code>setInterval</code>, 네트워크 요청 같은 비동기 작업을 처리합니다. </p>
<h2 id="shouldcomponentupdate">shouldComponentUpdate</h2>
<p>Update가 발생하였을 경우, 리렌더링을 시작할지 결정하는 메소드입니다. </p>
<p>이 메소드는 반드시 <code>true</code> 또는 <code>false</code> 를 반환해야 합니다. </p>
<h2 id="getsnapshotbeforeupdate">getSnapshotBeforeUpdate</h2>
<p><code>render</code> 에서 만들어진 결과물이 부라우저에서 실제로 반영되기 직전에 호출됩니다.</p>
<p><code>componentDidUpdate</code> 에서 세 번째 파라미터인 <code>snapshot</code> 값으로 전달받을 수 있습니다. </p>
<p>주로 스크롤바 위치 유지 등과 같이 업데이트하기 직전의 값을 참고할 일이 있을 때 활용됩니다. </p>
<h2 id="componentdidupdate">componentDidUpdate</h2>
<p>리렌더링이 완료된 후에 실행합니다. </p>
<p>Update가 끝난 직후이기 때문에, DOM 관련 처리를 해도 됩니다. </p>
<p><code>prevProps</code> 또는 <code>prevState</code> 를 사용하여 컴포넌트가 이전에 가졌던 데이터 접근이 가능합니다.</p>
<p>그리고 <code>getSnapshotBeforeUpdate</code> 에서 반환한 값을 <code>snapshot</code> 으로 전달받을 수 있습니다. </p>
<h2 id="componentwillunmount">componentWillUnmount</h2>
<p>컴포넌트를 DOM에서 제거할 때 실행되며, 등록한 이벤트, 타이머, 직접 생성한 DOM이 있다면 제거합니다.</p>
<h2 id="componentdidcatch">componentDidCatch</h2>
<p>컴포넌트 렌더링 도중에 에러가 발생했을 때 애플리케이션이 먹통이 되지 않고 오류 UI를 보여줄 수 있게 해 줍니다. </p>
<h1 id="reference-code">Reference Code</h1>
<p>위와 관련된 코드 예제는 아래 링크를 통해 확인할 수 있습니다. </p>
<p><a href="https://github.com/ye-geeee/react-sample/tree/7deb1162a139e0f19d047ca3d3060604c8584220">reference link</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[클래스 컴포넌트(Class Component) vs 함수형 컴포넌트(Function Component)]]></title>
            <link>https://velog.io/@ye-geeee/%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8Class-Component-vs-%ED%95%A8%EC%88%98%ED%98%95-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8Function-Component</link>
            <guid>https://velog.io/@ye-geeee/%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8Class-Component-vs-%ED%95%A8%EC%88%98%ED%98%95-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8Function-Component</guid>
            <pubDate>Tue, 03 Aug 2021 21:17:09 GMT</pubDate>
            <description><![CDATA[<p><code>React</code>를 사용하다 보면 어떨 땐, <code>Component</code>의 시작이 <code>function</code>으로 시작하고 어떨 땐 <code>class</code>로 시작한다. 이 두 형식이 어떻게 다른 것인지 <code>함수형 컴포넌트</code>와 <code>클래스 컴포넌트</code> 에 대해 알아보자!</p>
<h1 id="기본-형식-비교">기본 형식 비교</h1>
<p><em>함수형 컴포넌트</em> 예시</p>
<p>함수형 컴포넌트는 <code>function</code> 으로 시작한다. 그리고 <code>return</code> 내부에 적용하고 싶은 view를 넣어준다. </p>
<pre><code class="language-jsx">// 함수형 컴포넌트
function App() {
  const name = &#39;리액트&#39;;

  return (
    &lt;div&gt;{name}&lt;/div&gt;
  );
}</code></pre>
<p><em>클래스형 컴포넌트</em> 예시</p>
<p>클래스형 컴포넌트는 <code>class</code>로 시작한다. 그리고 넣고 <code>render</code> 함수에 적용하고 싶은 view를 넣어준다. </p>
<pre><code class="language-jsx">import &#39;./App.css&#39;;
import React, { Component } from &#39;react&#39;;

// 클래스형 컴포넌트
class App extends Component {
  render() {
    const name = &#39;리액트&#39;;

    return (
      &lt;div&gt;{name}&lt;/div&gt;
    );
  }
}

export default App;</code></pre>
<p>함수형 컴포넌트와 클래스형 컴포넌트는 문법과 지원할 수 있는 기능이 조금 다를 뿐이지 역할은 똑같다.</p>
<h1 id="각-컴포넌트의-장단점">각 컴포넌트의 장단점</h1>
<h2 id="클래스-컴포넌트의-이점">클래스 컴포넌트의 이점</h2>
<ol>
<li><code>state</code> 기능 및 라이프사이클 기능을 사용할 수 있다</li>
<li>임의 메서드를 정의할 수 있다.  </li>
</ol>
<p>단, 클래스 컴포넌트를 사용하려면 <code>render</code> 함수가 꼭 정의되어 있어야 한다.</p>
<h2 id="함수-컴포넌트의-이점">함수 컴포넌트의 이점</h2>
<ol>
<li>선언하기가 편하다.</li>
<li>메모리 자원도 덜 사용한다.</li>
<li>결과물의 크기가 작아 배포시에 유리할 수 있다.</li>
</ol>
<p>하지만, <code>state</code> 와 라이프사이클 API가 사용 불가하다. 이 점은 리액트 v16.8 업데이트 후 <code>Hooks</code> 라는 기능이 도입되면서 해결되었다.</p>
<h1 id="props-사용법">Props 사용법</h1>
<p><em>함수형 컴포넌트</em> 예시</p>
<pre><code class="language-jsx">const MyComponent = props =&gt; {
  return (
    &lt; div &gt;
      안녕하세요, 제 이름은 {props.name} 입니다. &lt;br /&gt;
      children 값은 {props.children} 입니다.
    &lt;/div &gt;
  );
};</code></pre>
<p><em>클래스형 컴포넌트</em> 예시</p>
<pre><code class="language-jsx">class MyComponent extends Component {
  static defaultProps = {
    name: &#39;기본 이름&#39;
  };

  static propTypes = {
    name: PropTypes.string,
    favoriteNumber: PropTypes.number.isRequired
  }

  render() {
    const { name, favoriteNumber, children } = this.props;

    return (
      &lt; div &gt;
        안녕하세요, 제 이름은 {name} 입니다. &lt;br /&gt;
        children 값은 {children} 입니다. &lt;br /&gt;
        제가 좋아하는 숫자는 {favoriteNumber} 입니다.
      &lt;/div &gt;
    );
  }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[@Controller와 @RestController]]></title>
            <link>https://velog.io/@ye-geeee/Controller%EC%99%80-RestController</link>
            <guid>https://velog.io/@ye-geeee/Controller%EC%99%80-RestController</guid>
            <pubDate>Fri, 02 Jul 2021 14:44:49 GMT</pubDate>
            <description><![CDATA[<p>Controller와 RestController의 차이점에 대해 한 번 알아보겠습니다.</p>
<p>우선 <code>@Controller</code> 의 애터테이션을 까보았습니다.</p>
<p><em>Controller.java</em></p>
<pre><code class="language-java">package org.springframework.stereotype;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.core.annotation.AliasFor;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {

    /**
     * The value may indicate a suggestion for a logical component name,
     * to be turned into a Spring bean in case of an autodetected component.
     * @return the suggested component name, if any (or empty String otherwise)
     */
    @AliasFor(annotation = Component.class)
    String value() default &quot;&quot;;

}</code></pre>
<p><em>RestController.java</em></p>
<pre><code class="language-java">package org.springframework.web.bind.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Controller;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {

    /**
     * The value may indicate a suggestion for a logical component name,
     * to be turned into a Spring bean in case of an autodetected component.
     * @return the suggested component name, if any (or empty String otherwise)
     * @since 4.0.1
     */
    @AliasFor(annotation = Controller.class)
    String value() default &quot;&quot;;

}</code></pre>
<p>첫 번째로,  <code>Controller</code> 애너테이션은 <code>Component</code> 애너테이션을 포함하고 있고, <code>RestController</code> 는 이 <code>Controller</code> 를 포함하고 있습니다. </p>
<p>두 번째로 <code>RestController</code> 는 <code>ResponseBody</code> 애너테이션을 포함하고 있고, <code>Controller</code> 는 포함하고 있지 않습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Compound Pattern]]></title>
            <link>https://velog.io/@ye-geeee/Compound-Pattern</link>
            <guid>https://velog.io/@ye-geeee/Compound-Pattern</guid>
            <pubDate>Fri, 25 Jun 2021 14:36:46 GMT</pubDate>
            <description><![CDATA[<h1 id="컴파운드-패턴compound-pattern의-정의">컴파운드 패턴(Compound Pattern)의 정의</h1>
<p>컴파운드 패턴(Compound Pattern)이란 하나의 디자인 문제를 해결하기 위해 여러 패턴을 함께 사용하는 것을 뜻합니다. MVC 패턴도 바로바로 컴파운드 패턴의 한 예시입니다.</p>
<h1 id="mvc-집중-탐구">MVC 집중 탐구</h1>
<h2 id="controller가-존재하는-이유">Controller가 존재하는 이유</h2>
<ol>
<li>모델(Model)을 조작하는 임무를 뷰(View)에서 수행한다면, 뷰에서 두 가지 역할을 하게 되면서 코드가 복잡해지는 문제가 있습니다.</li>
<li>뷰를 모델에 너무 밀접하게 연관시켜야 한다는 문제가 있습니다. 이러한 경우, 재사용하기가 아주 힘들어집니다.</li>
</ol>
<p>컨트롤러(Controller)를 사용하면 모델과 뷰의 결합을 끊어줄 수 있어서 나중에 확장하기가 용이합니다.</p>
<h2 id="mvc에-사용된-디자인-패턴">MVC에 사용된 디자인 패턴</h2>
<ul>
<li>모델(Model) : 옵저버 패턴(Observer Pattern)<ul>
<li>모델에서는 옵저버 패턴을 이용하여 상태가 변경되었을 때 연관된 객체들에게 연락을 합니다.</li>
</ul>
</li>
<li>컨트롤러(Controller) : 스트래티지 패턴(Strategy Pattern)<ul>
<li>뷰와 컨트롤러는 고전적인 스트래티지 패턴으로 구현되어 있습니다. 뷰에서는 애플리케이션의 겉모습에만 신경쓰고, 인터페이스의 행동에 대한 결정은 모두 컨트롤러에게 맡깁니다.</li>
</ul>
</li>
<li>뷰(View) : 컴포지트 패턴(Composite Pattern)<ul>
<li>컨트롤러는 최상단 뷰한테만 화면을 갱신해달라고 요청을 하고, 나머지 뷰들은 컴포지트 패턴에 의해 자동으로 처리됩니다.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Proxy Pattern]]></title>
            <link>https://velog.io/@ye-geeee/Proxy-Pattern</link>
            <guid>https://velog.io/@ye-geeee/Proxy-Pattern</guid>
            <pubDate>Sun, 20 Jun 2021 08:59:26 GMT</pubDate>
            <description><![CDATA[<h1 id="프록시-패턴proxy-pattern의-정의">프록시 패턴(Proxy Pattern)의 정의</h1>
<p><strong>프록시 패턴(Proxy Pattern)</strong> - 어떤 객체에 대한 접근을 제어하기 위한 용도로 대리인이나 대변인에 해당하는 객체를 제공하는 패턴</p>
<p><img src="https://images.velog.io/images/ye-geeee/post/033cbf55-49a4-461e-a0ef-d313e1004aba/ProxyPattern.png" alt=""></p>
<p>프록시 패턴에서 접근을 제어하는 활용은 아래와 같습니다.</p>
<ul>
<li>원격 프록시(remote proxy)<ul>
<li>프록시 패턴을 써서 원격 객체에 대한 접근을 제어할 수 있습니다. 다른 JVM에 들어있는 객체의 대변인에 해당하는 로컬 객체입니다.</li>
</ul>
</li>
<li>가상 프록시(virtual proxy)<ul>
<li>프록시 패턴을 써서 생성하기 힘든 자원에 대한 접근을 제어할 수 있습니다. 실제 객체 생성을 미루게 해 주는 기능을 제공하기도 합니다.</li>
</ul>
</li>
<li>보호 프록시(protection proxy)를 써서 접근 권한이 필요한 자원에 대한 접근을 제어할 수 있습니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[State Pattern]]></title>
            <link>https://velog.io/@ye-geeee/State-Pattern</link>
            <guid>https://velog.io/@ye-geeee/State-Pattern</guid>
            <pubDate>Sat, 19 Jun 2021 05:06:24 GMT</pubDate>
            <description><![CDATA[<h1 id="스테이트-패턴state-pattern-예제">스테이트 패턴(State Pattern) 예제</h1>
<h2 id="개선할-샘플-코드">개선할 샘플 코드</h2>
<p><a href="https://github.com/ye-geeee/headfirst-designpattern-practice/commit/9ce1ff19e768ac3e09ba9a0170af5dc4b5f4eaf2#diff-7da1eb697196c92b1ede93114e134b5df7c1bcac5bf44bb4cab7a396cfda2217">reference code to refactor</a></p>
<p>위의 예제는 현재 상태에 따라서 수행하는 동작이 달라지는 Gumball Machine을 구현한 것입니다. </p>
<p>각 메소드는 아래와 같이 현재 상태에 따라서 수행하는 동작이 달라지게 됩니다.</p>
<p><em>GumballMachine.java</em></p>
<pre><code class="language-java">    public void insertQuarter() {
          switch (state) {
              case SOLD_OUT:
                  System.out.println(&quot;SOLD OUT&quot;);
                  break;
              case NO_QUARTER:
                  state = HAS_QUARTER;
                  System.out.println(&quot;Inserted quarter&quot;);
                  break;
              case HAS_QUARTER:
                  System.out.println(&quot;Please insert only one quarter&quot;);
                  break;
              case SOLD:
                  System.out.println(&quot;Please wait for a second. The gumball is going out&quot;);
                  break;
          }
      }</code></pre>
<h2 id="샘플-코드의-문제점">샘플 코드의 문제점</h2>
<ul>
<li>OCP(Open Closed Principal)을 지키지 않고 있습니다.</li>
<li>객체 지향 디자인이라고 하기 힘듭니다.</li>
<li>상태 전환이 복잡한 조건문 속에 숨어 있기 때문에 분명하게 드러나지 않습니다.</li>
<li>바뀌는 부분을 전혀 캡슐화하지 않았습니다.</li>
<li>다른 기능을 더 추가하는 과정에서 기존 코드에 없던 새로운 버그가 생길 가능성이 높습니다.</li>
</ul>
<h2 id="스테이트-패턴state-pattern-적용">스테이트 패턴(State Pattern) 적용</h2>
<p><a href="https://github.com/ye-geeee/headfirst-designpattern-practice/tree/master/state-pattern/src">reference code</a></p>
<p>스테이트 패턴을 적용하면 아래와 같이 적용할 수 있습니다.</p>
<p><em>GumballMachine.java</em></p>
<pre><code class="language-java">public class GumballMachine {

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

        // 현재 state
    State state = soldOutState;
    int count;

        ...

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

        ...
}</code></pre>
<p><em>NoQuaterState.java</em></p>
<pre><code class="language-java">@Override
    public void insertQuarter() {
        System.out.println(&quot;Inserted quarter&quot;);
        machine.setState(machine.getHasQuarterState());
    }</code></pre>
<p>위의 코드처럼 기존에는 if 문으로 모든 상태에 대해 각 행동을 정해줘야했지만, 이제 <code>State</code> 클래스에서 각 상태에 맞게 동작을 수행하고 상태를 변경해줍니다.</p>
<p>구현을 구조적으로 바꾸면서 크게 아래 다섯 가지 이점을 얻을 수 있었습니다.</p>
<ul>
<li>각 상태의 행동을 별개의 클래스로 국지화시켰습니다.</li>
<li>관리하기 힘든 골칫덩어리 if 선언문들을 없앴습니다.</li>
<li>각 상태를 변경에 대해서는 닫혀 있도록 하면서도 <code>GumballMachine</code> 자체는 새로운 상태 클래스를 추가하는 확장에 대해서 열려있도록 고쳤습니다. (OCP)</li>
<li>더 이해하기 좋은 코드 베이스와 클래스 구조를 만들었습니다.</li>
</ul>
<p><img src="https://images.velog.io/images/ye-geeee/post/b555c608-e1d8-48d9-8b28-a3e034090577/StatePatternSample.png" alt=""></p>
<h1 id="스테이트-패턴state-pattern의-정의">스테이트 패턴(State Pattern)의 정의</h1>
<p><strong>스테이트 패턴(State Pattern)</strong>을 이용하면 객체의 내부 상태가 바뀜에 따라서 객체의 행동을 바꿀 수 있습니다. 마치 객체의 클래스가 바뀌는 것과 같은 결과를 얻을 수 있습니다. </p>
<p><img src="https://images.velog.io/images/ye-geeee/post/2bdaf3fd-6c9d-4995-9778-2d4faaa23924/StatePattern.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Composite Pattern]]></title>
            <link>https://velog.io/@ye-geeee/Composite-Pattern</link>
            <guid>https://velog.io/@ye-geeee/Composite-Pattern</guid>
            <pubDate>Sun, 13 Jun 2021 22:58:37 GMT</pubDate>
            <description><![CDATA[<h1 id="컴포지트-패턴composite-pattern-디자인">컴포지트 패턴(Composite Pattern) 디자인</h1>
<p>컴포지트 패턴(Composite Pattern)은 객체들을 트리 구조로 구성할 때 쓰는 디자인 패턴입니다.</p>
<p>우선, 객체는 트리 구조와 동일하게 1. <code>Leaf</code> 노드와 2. <code>Leaf</code> 노드가 아닌 <code>Composite</code> 노드가 있습니다. 이 두 객체는 상위 개념인 <code>Component</code> 클래스를 상속받고 재귀적인 구조를 구성합니다. 상위 클래스인 <code>Component</code> 클래스는 이 두 객체에서 구현해야하는 모든 함수를 포함하고 있습니다. </p>
<p><code>Composite</code> 클래스는 자식이 있는 구성요소의 행동을 정의하고 자식 구성요소를 저장하는 역할을 합니다. <code>Leaf</code> 클래스는 그 안에 들어있는 원소에 대한 행동을 정의합니다. </p>
<p><img src="https://images.velog.io/images/ye-geeee/post/c76f48cb-a2d6-4554-a6d7-66fe64035f43/CompositePattern.png" alt=""></p>
<h1 id="컴포지트-패턴composite-pattern-예제">컴포지트 패턴(Composite Pattern) 예제</h1>
<p>아래 다이어그램은 컴포지트 패턴의 예제입니다. </p>
<p><code>MenuItem</code> 은 <code>Leaf</code> 노드의 역할을 하고, <code>Menu</code> 는 <code>Composite</code> 역할을 수행합니다. 모든 구성요소는 <code>MenuComponent</code> 인터페이스를 구현해야만 합니다. 하지만 하위 두 클래스의 역할이 다르기 때문에 각 역할에 맞게 메소드는 구현하고 나머지 메소드는 상위 클래스의 기본 메소드를 사용합니다. </p>
<p><em><a href="https://github.com/ye-geeee/headfirst-designpattern-practice/commit/5be8e1ba0be06140988cfdb8f80008421c1be8f7">reference code</a></em></p>
<p><img src="https://images.velog.io/images/ye-geeee/post/7de1b0bb-f926-411a-8ddc-bfcb4976b749/CompositePatternSample.png" alt=""></p>
<h1 id="컴포지트-패턴composite-pattern-정의">컴포지트 패턴(Composite Pattern) 정의</h1>
<blockquote>
<p><strong>컴포지트 패턴(Composite Pattern)</strong>을 이용하면 객체들을 트리 구조로 구성하여 부분과 전체를 나타내는 계층구조로 만들 수 있습니다. 이 패턴을 이용하면 클라이언트에서 개별 객체와 다른 객체들로 구성된 복합 객체(composite)를 똑같은 방법으로 다룰 수 있습니다. </p>
</blockquote>
<p>컴포지트 패턴을 이용하면 객체의 구성과 개별 객체를 노드로 가지는 트리 형태로 객체를 구축할 수 있습니다. 이런 복합 구조(composite structure)를 사용하면 복합 객체와 개별 객체에 대해 똑같은 작업을 적용할 수 있습니다. </p>
<p>컴포지트 패턴에서는 <strong>단일 책임 원칙</strong>을 위반하면서 투명성을 확보하기 위한 패턴이라고 할 수 있습니다. 상위 클래스에 자식들을 관리하기 위한 모든 기능을 넣음으로써 <code>Composite</code> 객체와 <code>Node</code> 객체를 똑같은 방식으로 처리할 수 있도록 할 수 있습니다. </p>
<p><code>Component</code> 클래스에는 두 종류의 기능이 모두 있어 안정성은 조금 떨어지게 되지만, 컴포지트 패턴을 사용하지 않고 서로 다른 인터페이스로 분리를 할 경우, <code>instanceOf</code> 함수와 같이 투명성이 떨어지는 코드를 사용해야 합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Iterator Pattern]]></title>
            <link>https://velog.io/@ye-geeee/Iterator-Pattern</link>
            <guid>https://velog.io/@ye-geeee/Iterator-Pattern</guid>
            <pubDate>Sun, 13 Jun 2021 01:09:40 GMT</pubDate>
            <description><![CDATA[<h1 id="이터레이터-패턴iterator-pattern은-언제-필요할까">이터레이터 패턴(Iterator Pattern)은 언제 필요할까?</h1>
<p><em><a href="https://github.com/ye-geeee/headfirst-designpattern-practice/commit/0f7ec46cce5b609decb114dfd151b41f66c8bb37">code reference</a></em></p>
<p>두 개의 구성 객체에서 하나는 정보를 <code>ArrayList</code> 데이터 타입로 가지고 있고 하나는 정보를 <code>Array</code> 데이터 타입으로 가지고 있을 경우, 아래와 같이 각각 다른 <code>loop</code> 를 통해 탐색을 해야합니다.</p>
<ul>
<li><code>ArrayList</code> - <code>size()</code> 함수 이용</li>
<li><code>Array</code> - 배열에 들어있는 원소의 크기 변수 이용</li>
</ul>
<p><em>Waitress.java</em></p>
<pre><code class="language-java">public void printMenu() {
        ArrayList breakfastItems = pancakeHouseMenu.getMenuItems();
        for (int i = 0; i &lt; breakfastItems.size(); i++) {
            MenuItem menuItem = (MenuItem) breakfastItems.get(i);
            System.out.print(menuItem.getName() + &quot; &quot;);
            System.out.println(menuItem.getPrice() + &quot; &quot;);
            System.out.println(menuItem.getDescription());
        }

        MenuItem[] lunchItems = dinerMenu.getMenuItems();
        for (int i = 0; i &lt; dinerMenu.numberOfItems; i++) {
            MenuItem menuItem = lunchItems[i];
            System.out.print(menuItem.getName() + &quot; &quot;);
            System.out.println(menuItem.getPrice() + &quot; &quot;);
            System.out.println(menuItem.getDescription());
        }
    }</code></pre>
<p><code>HashMap</code> 형태의 다른 데이터 타입이 또 추가된다면 <code>loop</code> 를 돌기 위해 또다른 방식의 처리를 해줘야 합니다.</p>
<p>매번 다른 형태의 데이터타입을 가지고 있는 객체에 대해서 위처럼 처리를 해주는 것을 개선하기 위해 반복을 캡슐화한 이터레이터 패턴(Iterator Pattern)을 적용합니다.</p>
<h1 id="이터레이터-패턴iterator-pattern-예제">이터레이터 패턴(Iterator Pattern) 예제</h1>
<p><img src="https://images.velog.io/images/ye-geeee/post/35beff8b-10bd-4570-aeb0-73960eb294c8/IteratorPatternSample.png" alt=""></p>
<p><em><a href="https://github.com/ye-geeee/headfirst-designpattern-practice/commit/e51545d97b1c8ee0773ac4a7ed3babcd9f46698c">code reference</a></em></p>
<p>각각의 구성 객체(<code>PancakeHouseMenu</code>, <code>DinerMenu</code>)에 <code>Iterator</code> 를 구현한 객체를 하나씩 구성하도록 개선하였습니다. 그럼 아래와 같이 <code>loop</code> 를 도는 부분을 캡슐화하여 통일감 있게 코드를 작성할 수 있습니다. </p>
<p><em>Waitress.java</em></p>
<pre><code class="language-java">    public void printMenu() {
      Iterator pancakeIterator = pancakeHouseMenu.createItertor();
      Iterator dinerIterator = dinerMenu.createIterator();
      printMenu(pancakeIterator);
      printMenu(dinerIterator);
  }

  public void printMenu(Iterator iterator) {
      while(iterator.hasNext()) {
          MenuItem menuItem = (MenuItem) iterator.next();
          System.out.print(menuItem.getName() + &quot; &quot;);
          System.out.println(menuItem.getPrice() + &quot; &quot;);
          System.out.println(menuItem.getDescription());
    }</code></pre>
<p>이렇게 개선하면, 각 객체가 어떤 타입의 데이터(<code>ArrayList, Array, HashMap</code> 등)를 가지고 있는지 <code>Waitress</code> 에서 알 필요 없도록 캡슐화하고, <code>Waitress</code> 에서는  <code>Iterator</code> 객체만 알고 있으면 됩니다. </p>
<h1 id="javautiliterator-적용하기">java.util.Iterator 적용하기</h1>
<p><em><a href="https://github.com/ye-geeee/headfirst-designpattern-practice/commit/3970f8c38493623c6a35468813cdaa8eb1173fad">code reference</a></em></p>
<p><code>ArrayList</code> 와 <code>HashMap</code> 의 경우, Java의 <code>Iterator</code> 를 포함하고 있습니다. 따라서 이전의 <a href="https://github.com/ye-geeee/headfirst-designpattern-practice/commit/e51545d97b1c8ee0773ac4a7ed3babcd9f46698c">reference code</a> 에서 <code>PancakeIterator</code> 를 구현할 필요가 없이 아래와 같이 수정할 수 있습니다.</p>
<p><em>PancakeHouseMenu.java</em></p>
<pre><code class="language-java">// Java Iterator 적용 전
public Iterator createItertor() {
        return new PancakeIterator(menuItems);
    }

// Java Iterator 적용 후
public Iterator createItertor() {
        return menuItems.iterator();
    }
</code></pre>
<p><code>Array</code> 의 경우에는 포함하고 있지 않기 때문에 이를 구현해줘야 합니다. </p>
<h3 id="주의-사항">주의 사항</h3>
<p>다중 스레드를 사용하는 환경에서는 같은 객체 컬렉션(<code>Collection</code>)에 대해 여러 반복자가 있는 경우, <code>remove()</code> 함수에 대한 처리가 정의되어 있지 않습니다. 따라서 컬렉션에 동시에 접근하는 멀티스레드 코드를 디자인할 때는 매우 조심해야 합니다. </p>
<h1 id="이터레이터-패턴iterator-pattern의-정의">이터레이터 패턴(Iterator Pattern)의 정의</h1>
<p><img src="https://images.velog.io/images/ye-geeee/post/f135ffae-33e3-4396-9ad3-f57f4ad54dc6/IteratorPattern.png" alt=""></p>
<blockquote>
<p><strong>이터레이터 패턴(Iterator Pattern)</strong>은 컬렉션 구현 방법을 노출시키지 않으면서도 그 집합체 안에 들어있는 모든 항목에 접근할 수 있게 해주는 방법을 제공해줍니다. </p>
</blockquote>
<h3 id="이터레이터-패턴iterator-pattern을-사용하면-좋은-점">이터레이터 패턴(Iterator Pattern)을 사용하면 좋은 점</h3>
<ol>
<li>모든 항목에 접근하는 방식이 통일되어 있으면 어떤 종류의 집합체에 대해서도 사용할 수 있는 다형적인 코드를 만들 수 있습니다. </li>
<li>모든 항목에 일일이 접근하는 작업을 반복자 객체에서 맡게 되기 때문에 집합체의 인터페이스 및 구현이 간단해질 뿐 아니라, 집합체에서는 반복작업에서 손을 떼고 원래 자신이 할 일 (객체 컬렉션 관리)에만 전념할 수 있습니다. </li>
</ol>
<h1 id="단일-책임의-원칙">단일 책임의 원칙</h1>
<p>클래스에서 맡고 있는 역할들은 나중에 코드 변화를 불러올 수 있습니다. </p>
<blockquote>
<p>Design Principal 9.
클래스를 바꾸는 이유는 한 가지 뿐이어야 한다.</p>
</blockquote>
<p>클래스를 고치는 것은 최대한 피해야 합니다. 코드를 변경하다 보면 온갖 문제가 발생할 수 있기 대문입니다. 따라서 변화를 최소화하기 위해 한 클래스에서는 응집도 높은 메소드만 담당하고 있는 것이 좋습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Adapter Pattern]]></title>
            <link>https://velog.io/@ye-geeee/Adapter-Pattern</link>
            <guid>https://velog.io/@ye-geeee/Adapter-Pattern</guid>
            <pubDate>Sat, 12 Jun 2021 15:18:41 GMT</pubDate>
            <description><![CDATA[<h1 id="객체지향-어댑터adapter">객체지향 어댑터(Adapter)</h1>
<p>어댑터(Adapter)는 클라이언트로부터 요청을 받아서 업체에서 제공하는 클래스에서 받아들일 수 있는 형태의 요청으로 변환시켜주는 <strong>중개인 역할</strong>을 합니다.</p>
<p><img src="https://images.velog.io/images/ye-geeee/post/8c01f153-5ee7-4b0a-bbae-3b232c871a49/Adapter.png" alt=""></p>
<h1 id="어댑터-패턴adapter-pattern-예시">어댑터 패턴(Adapter Pattern) 예시</h1>
<p><a href="https://github.com/ye-geeee/headfirst-designpattern-practice/commit/ef8c5c74feaef6f1a5f2c774a3ef32e786273c3e">reference code</a></p>
<p>레퍼런스 코드를 확인해보면 클라이언트에서  <code>Turkey</code> 를 기존에 제공하는 클래스인 <code>Duck</code> 으로 변환시켜주기 위해 <code>TurkeyAdapter</code> 코드를 추가하였습니다. </p>
<p><em>TurkeyAdapter.java</em></p>
<pre><code class="language-java">public class TurkeyAdapter implements Duck {
    Turkey turkey;

    public TurkeyAdapter(Turkey turkey) {
        this.turkey = turkey;
    }

    @Override
    public void quack() {
        turkey.gobble();
    }

    @Override
    public void fly() {
        for(int i = 0; i &lt; 5; i++) {
            turkey.fly();
        }
    }
}</code></pre>
<p>다이어그램으로 살펴보면 아래와 같습니다.</p>
<p><img src="https://images.velog.io/images/ye-geeee/post/8925df24-91e1-4a7a-88c2-415adace1683/AdapterPatternSample.png" alt=""></p>
<ol>
<li>클라이언트(Client)에서는 <code>Duck</code> 인터페이스를 가지고 있습니다. 하지만 실제 구현된 구상 클래스는 <code>TurkeyAdapter</code> 입니다. </li>
<li><code>TurkeyAdapter</code> 에서는 <code>Turkey</code> 인터페이스를 가지고 있습니다. 클라이언트로부터 받은 요청을 <code>Turkey</code> 인터페이스에 대한 메소드로 변환합니다.</li>
<li>클라이언트에서는 <code>TurkeyAdapter</code> 에서 무엇을 하는지 모른 채로 호출 결과를 받습니다. </li>
</ol>
<h1 id="어댑터-패턴adapter-pattern-정의">어댑터 패턴(Adapter Pattern) 정의</h1>
<p>(<a href="https://images.velog.io/images/ye-geeee/post/d22c6f80-0836-43c2-9657-38c685d8d8b2/Adapter.png)!%5B%5D(https://images.velog.io/images/ye-geeee/post/a01fb8dd-629f-4bc4-90e3-f8dcc39d14d4/AdapterPattern.png)">https://images.velog.io/images/ye-geeee/post/d22c6f80-0836-43c2-9657-38c685d8d8b2/Adapter.png)![](https://images.velog.io/images/ye-geeee/post/a01fb8dd-629f-4bc4-90e3-f8dcc39d14d4/AdapterPattern.png)</a></p>
<ol>
<li>클라이언트(Client)에서 타겟(Target) 인터페이스 메소드를 호출함으로써 어댑터(Adapter)에 요청합니다.</li>
<li>어댑터에서는 어댑티(Adaptee) 인터페이스를 사용하여 그 요청을 어댑티에 대한 (하나 이상의) 메소드 호출로 변환합니다.</li>
<li>클라이언트에서는 호출 결과를 받긴 하지만 중간에 어댑터가 껴 있는지는 전혀 알지 못합니다. </li>
</ol>
<p><strong>어댑터 패턴(Adapter Pattern)</strong>
한 클래스의 인터페이스를 클라이언트에서 사용하고자 하는 다른 인터페이스로 변환합니다. 어댑터를 이용하면 인터페이스 호환성 문제 때문에 같이 쓸 수 없는 클래스들을 연결해서 쓸 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Template Method Pattern]]></title>
            <link>https://velog.io/@ye-geeee/Template-Method-Pattern</link>
            <guid>https://velog.io/@ye-geeee/Template-Method-Pattern</guid>
            <pubDate>Thu, 10 Jun 2021 21:15:54 GMT</pubDate>
            <description><![CDATA[<h1 id="템플릿-메소드-패턴template-method-pattern-예제">템플릿 메소드 패턴(Template Method Pattern) 예제</h1>
<p><a href="https://github.com/ye-geeee/headfirst-designpattern-practice/commit/f764292f0a0ede8febdb741a5112163e0c6001b8">code reference</a></p>
<p>템플릿 메소드(Template Method)에서는 알고리즘의 각 단계들을 정의하며, 그 중 한 개 이상의 단계가 서브클래스에 의해 제공될 수 있습니다. </p>
<p>아래 예시를 살펴보면 <code>CaffeineBeverage</code> 클래스에서 <strong>알고리즘을 독점</strong>하고 있는 것(<code>prepareRecipe</code>)을 볼 수 있습니다. 그리고 이 알고리즘의 일부 구현만 서브 클래스에 의존합니다. 그래서 알고리즘은 한 군데에 있기 때문에 그 부분만 고치면 됩니다. </p>
<p><em>CaffeineBeverage.java</em></p>
<pre><code class="language-java">public abstract class CaffeineBeverage {

    final void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }

    abstract void brew();

    abstract void addCondiments();

    void boilWater() {
        System.out.println(&quot;boiling water ...&quot;);
    }

    void pourInCup() {
        System.out.println(&quot;pouring in cup ...&quot;);
    }
}</code></pre>
<p><em>Coffee.java</em></p>
<pre><code class="language-java">public class Coffee extends CaffeineBeverage {

    @Override
    void brew() {
        System.out.println(&quot;brewing coffee ...&quot;);
    }

    @Override
    void addCondiments() {
        System.out.println(&quot;adding sugar and milk ...&quot;);
    }

}</code></pre>
<h1 id="템플릿-메소드-패턴template-method-pattern의-정의">템플릿 메소드 패턴(Template Method Pattern)의 정의</h1>
<p>Head First Design Patterns의 책에서는 템플릿 메소드 패턴을 아래와 같이 정의하고 있습니다.</p>
<p><strong>템플릿 메소드 패턴(Template Method Pattern)</strong>에서는 알고리즘의 골격을 정의합니다. 알고리즘의 여러 단계 중 일부는 서브클래스에서 구현할 수 있습니다. 템플릿 메소드를 이용하면 알고리즘의 구조는 그대로 유지하면서 서브클래스에서 특정 단계를 재정의할 수 있습니다. </p>
<p><img src="https://images.velog.io/images/ye-geeee/post/d3202ea7-01fb-4bec-b371-c49af40bffd7/TemplateMethodPattern.png" alt=""></p>
<h1 id="템플릿-메소드-패턴template-method-pattern의-양식">템플릿 메소드 패턴(Template Method Pattern)의 양식</h1>
<p>템플릿 메소드 패턴의 기본 구조는 아래와 같습니다.</p>
<ul>
<li>알고리즘은 <code>final</code>로 지정하여 서브클래스에서 수정할 수 없도록 하였습니다.</li>
<li>알고리즘의 일부 구현은 서브클래스에서 담당하도록 합니다.</li>
<li><code>hook()</code> 다양한 용도로 사용할 수 있습니다.<ul>
<li><code>hook()</code> <a href="https://github.com/ye-geeee/headfirst-designpattern-practice/commit/fb9374f8bdebab396377d0f7b22ef38d1dd28db7">reference code</a></li>
</ul>
</li>
</ul>
<pre><code class="language-java">public abstract class AbstractClass {

    final void templateMethod() {
        primitiveOperation1();
        primitiveOperation2();
        concreteOperation();
        hook();
    }

    abstract void primitiveOperation1();

    abstract void primitiveOperation2();

    final void concreteOperation() {}

    void hook() {}
}</code></pre>
<h1 id="헐리우드-원칙">헐리우드 원칙</h1>
<p><strong>헐리우드 원칙</strong>
먼저 연락하지 마세요. 저희가 연락 드리겠습니다 .</p>
<p>헐리우드 원칙을 활용하면 &quot;의존성 부패(dependency rot)&quot;를 방지할 수 있습니다. 의존성이 복잡하게 꼬여있는 것을 의존성 부패라고 부릅니다. 의존성이 부패되면 시스템이 어떤 식으로 디자인된 것인지 거의 아무도 알아볼 수 없게 됩니다. </p>
<p>템플릿 메소드 패턴은 헐리우드 원칙을 적용한 패턴이라고 할 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Facade Pattern]]></title>
            <link>https://velog.io/@ye-geeee/Facade-Pattern</link>
            <guid>https://velog.io/@ye-geeee/Facade-Pattern</guid>
            <pubDate>Thu, 10 Jun 2021 06:15:12 GMT</pubDate>
            <description><![CDATA[<h1 id="퍼사드-패턴facade-pattern의-정의">퍼사드 패턴(Facade Pattern)의 정의</h1>
<p>퍼사드 패턴(Facade Pattern)은 하나 이상의 복잡한 인터페이스를 깔끔하면서도 말쑥한 퍼사드(겉모양, 외관 등을 뜻함)으로 덮어주는 패턴입니다. 일련의 복잡한 클래스들을 단순화하고 통합된 클래스를 제공합니다.</p>
<p>Head First Design Patterns에서는 아래와 같이 퍼사드 패턴을 정의합니다. </p>
<p><strong>퍼사드 패턴(Facade Pattern)</strong>
어떤 서브시스템의 일련의 인터페이스에 대한 통합된 인터페이스를 제공합니다. 퍼사드에서 고수준 인터페이스를 정의하기 때문에 서브시스템을 더 쉽게 사용할 수 있습니다. </p>
<p><img src="https://images.velog.io/images/ye-geeee/post/1bf587b2-6f31-426d-a45d-fa600c0af7e0/FacadePatternSample.png" alt=""></p>
<h1 id="최소-지식-원칙">최소 지식 원칙</h1>
<p>Design Pattern 7.
최소 지식 원칙 - 정말 친한 친구하고만 얘기하라. </p>
<p>시스템을 디자인 할 때, 어떤 객체든 그 객체와 상호작용을 하는 클래스의 개수에 주의해야 하며, 그런 객체들과 어떤 식으로 상호작용을 하는지에도 주의를 기울여야 한다는 뜻입니다.</p>
<p>이 원칙을 따르면 복잡하게 얽혀서 있는 시스템의 한 부분을 변경했을 때 다른 부분까지 줄줄이 고쳐야 되는 상황을 미리 방지할 수 있습니다. </p>
<p><strong>최소 지식 원칙을 지키기 위해 아래와 같이 어떤 메소드에서든지 다음 네 종류 객체 내의 메소드만 호출할 수 있도록 가이드를 제시하고 있습니다.</strong> </p>
<ol>
<li>객체 자체</li>
<li>메소드에 매개변수로 전달된 객체</li>
<li>그 메소드에서 생성하거나 인스턴스를 만든 객체</li>
<li>그 객체에 속하는 구성요소</li>
</ol>
<p>네 개의 객체에 대한 예시는 아래를 확인하면 알 수 있습니다. </p>
<pre><code class="language-java">public class Car {
    Engine engine; // 4. 클래스의 구성 요소

    public Car() {}

    public void start(Key key) { // 2. 매개 변수로 전달된 객체
        Doors doors = new Doors(); // 3. 메소드에서 생성하거나 인스턴스를 만든 객체

        boolean authorized = key.turns(); // 2. 매개 변수로 전달된 객체의 메소드

        if (authorized) {
            engine.start(); // 4. 클래스의 구성 요소 객체의 메소드
            updateDashboardDisplay(); // 1. 객체 내에 있는 메소드
            doors.lock(); // 3. 메소드에서 생성하거나 인스턴스를 만든 객체의 메소드
        }
    }

    private void updateDashboardDisplay() {
        // update display
    }
}</code></pre>
<h1 id="추가-사항">추가 사항</h1>
<ul>
<li>데메테르의 법칙과 최소 지식 원칙은 동일한 말입니다.</li>
<li>최소 지식 원칙을 사용하면 객체들 사이의 의존성을 줄일 수 있고, 소프트웨어가 더 용이해질 수도 있습니다. 하지만 &quot;래퍼&quot; 클래스를 더 많이 만들면서 더 복잡해지고, 개발 시간도 늘어나고, 성능도 저하될 수 있습니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Command Pattern]]></title>
            <link>https://velog.io/@ye-geeee/Command-Pattern</link>
            <guid>https://velog.io/@ye-geeee/Command-Pattern</guid>
            <pubDate>Sun, 06 Jun 2021 12:56:11 GMT</pubDate>
            <description><![CDATA[<h1 id="커맨드-패턴command-pattern-예시">커맨드 패턴(Command Pattern) 예시</h1>
<p><img src="https://images.velog.io/images/ye-geeee/post/8e3b610f-3431-4be0-88f3-14f9af3336fc/CommandPattern.png" alt=""></p>
<p>커맨드 객체는 일련의 행동을 특정 리시버하고 연결시킴으로써 <strong>요구 사항을 캡슐화</strong>합니다. </p>
<p>아래 샘플 코드에서 <code>SimpleRemoteControl</code> 은 인보커(Invoker) 클래스,  <code>LightOnCommnad</code> 클래스는 커맨드(Command) 클래스, <code>Light</code> 는 리시버(Receiver) 클래스, <code>RemoteControlTest</code> 는 클라이언트(Client) 클래스의 예시입니다. </p>
<p><a href="https://github.com/ye-geeee/headfirst-designpattern-practice/commit/7a1ac92b07830a4a8b653b08fb3a6e25e86cd221">reference code</a></p>
<p><em>SimpleRemoteControl.java (Invoker)</em></p>
<p><code>SimpleRemoteControl</code> 은 <code>Command</code> 객체를 들고 있습니다. 그리고 실제 <code>Command</code> 객체가 어떤 객체인지, 어떤 일을 하는지 상관없이 버튼이 눌리면 <code>execute</code> 함수를 호출합니다.</p>
<pre><code class="language-java">public class SimpleRemoteControl {
    Command slot;

    public SimpleRemoteControl() { }

    public void setCommand(Command command) {
        this.slot = command;
    }

    public void buttonWasPressed() {
        slot.execute();
    }
}</code></pre>
<p><em>Command.java</em></p>
<pre><code class="language-java">public interface Command {
    void execute();
}</code></pre>
<p><em>LightOnCommand.java (Command)</em></p>
<p><code>LightOnCommand</code> 는 리시버(Receiver)객체를 참조하고 있습니다. 이 리시버는 Client로부터 주입받은 리시버입니다. </p>
<pre><code class="language-java">public class LightOnCommand implements Command {

    Light light;

    public LightOnCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.on();
    }
}</code></pre>
<p><em>RemoteControlTest.java (Client)</em></p>
<p>클라이언트(Client)는 커맨드 객체와 리시버 객체를 모두 들고 있고 커맨드 객체에 리시버 객체를 주입하여 줍니다. 그래서 커맨드 객체에서 <code>exexcute</code> 함수가 불리게 되면 주입된 리시버 객체에서 어떤 특정 일을 수행하게 됩니다. </p>
<pre><code class="language-java">public class RemoteControlTest {

    public static void main(String[] args) {
        SimpleRemoteControl remote = new SimpleRemoteControl();
        Light light = new Light();
        LightOnCommand lightOn = new LightOnCommand(light);

        remote.setCommand(lightOn);
        remote.buttonWasPressed();

        Garage garage = new Garage();
        GarageDoorOpenCommand garageDoorOpen = new GarageDoorOpenCommand(garage);

        remote.setCommand(garageDoorOpen);
        remote.buttonWasPressed();
    }
}</code></pre>
<h1 id="커맨드-패턴command-pattern의-정의">커맨드 패턴(Command Pattern)의 정의</h1>
<p>Head First Design Patterns에서 정의한 커맨드 패턴의 정의는 아래와 같습니다. </p>
<blockquote>
<p><strong>커맨드 패턴(Command Pattern)</strong>
커맨드 패턴을 이용하면서 요구 사항을 객체로 캡슐화할 수 있으며, 매개변수를 써서 여러 가지 다른 요구 사항을 집어넣을 수도 있습니다. 또한 요청 내역을 큐에 저장하거나 로그로 기록할 수도 있으며, 작업 취소 기능도 지원 가능합니다.</p>
</blockquote>
<h1 id="커맨드-패턴command-pattern의-활용">커맨드 패턴(Command Pattern)의 활용</h1>
<h2 id="요청을-큐에-저장하기">요청을 큐에 저장하기</h2>
<p>커맨드 객체를 사용하면 컴퓨테이션(computation)의 한 부분을 패키지(리시버와 일련의 행동)로 묶어서 객체 형태로 전달한느 것도 가능합니다. 이를 통해서 스케줄러, 스레드 풀, 작업 큐와 같은 곳에 활용될 수 있습니다.</p>
<p>작업 큐를 보면 어떤 업무를 수행하는지 모른채 큐에 커맨드 객체를 쌓습니다. 그리고 순차적으로 커맨드를 가져오고 커맨드가 어떤 업무를 수행하든지 상관없이 커맨드 객체의 <code>execute</code> 만 호출합니다. </p>
<h2 id="요청을-로그에-기록하기">요청을 로그에 기록하기</h2>
<p>애플리케이션이 다운되었을 때에 이전 기록을 복구하는 기능을 추가할 수 있습니다. <code>Command</code> 인터페이스에 <code>store()</code> 과 <code>load()</code> 를 추가하면 매번 <code>execute()</code> 가 불릴 때 <code>store()</code> 을 수행합니다. 그러면 애플리케이션이 다운되면 <code>load()</code> 를 통해 복구할 수 있습니다. </p>
<p>하지만, 방대한 자료구조인 애플리케이션의 경우, <code>store()</code> 라는 함수의 오버헤드가 커지게 됩니다. 이러한 경우에는 요청을 로그에 기록합니다. 그리고 애플리케이션이 다운되었을 경우, 로그를 통해 시스템을 복구시키는 데에 활용할 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Singleton Pattern]]></title>
            <link>https://velog.io/@ye-geeee/Singleton-Pattern</link>
            <guid>https://velog.io/@ye-geeee/Singleton-Pattern</guid>
            <pubDate>Thu, 03 Jun 2021 20:55:10 GMT</pubDate>
            <description><![CDATA[<h1 id="싱글톤-패턴singleton-pattern의-용도">싱글톤 패턴(Singleton Pattern)의 용도</h1>
<p>스레드 풀, 캐시, 대화상자, 사용자 설정 혹은 레지스트리를 처리하는 객체, 로그 기록용 객체, 디바이스 드라이버 등 객체 중에 하나만 있으면 되는 경우 사용합니다. </p>
<h1 id="고전적인-싱글톤-패턴singleton-pattern">고전적인 싱글톤 패턴(Singleton Pattern)</h1>
<p>고전적인 싱글톤 패턴 방식은 아래와 같습니다.</p>
<p>생성자는 <code>private</code> 으로 설정하고, 객체를 부를 때에는 따로 <code>static</code> 함수를 사용합니다. 인스턴스가 있을 경우에는 그대로 그 인스턴스를 반환하고, 인스턴스가 없을 경우에는 생성하여 인스턴스를 반환하변 됩니다. </p>
<pre><code class="language-java">public class Singleton {
    private static Singleton uniqueInstance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (uniqueInstance == null) {
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
}</code></pre>
<h1 id="싱글톤-패턴singleton-pattern의-정의">싱글톤 패턴(Singleton Pattern)의 정의</h1>
<blockquote>
<p><strong>싱글톤 패턴</strong> 
싱글톤 패턴은 해당 클래스의 인스턴스가 하나만 만들어지고, 어디서든지 그 인스턴스에 접근할 수 있도록 하기 위한 패턴입니다. </p>
</blockquote>
<ul>
<li>반드시 생성은 클래스 자신을 통해 하도록 하여, 다른 어떤 클래스에서도 자신의 인스턴스를 추가로 만들지 못하도록 합니다.</li>
<li>싱글톤은 &#39;게으르게&#39; 생성할 수 있습니다. 클래스의 객체가 자원을 많이 잡아먹는 경우에 유용합니다.</li>
</ul>
<h1 id="멀티스레딩-문제-해결-방법">멀티스레딩 문제 해결 방법</h1>
<h2 id="간단한-해결-방법">간단한 해결 방법</h2>
<p>객체를 부르는 <code>getInstance()</code> 함수를 동기화시키면 해결할 수 있습니다. </p>
<pre><code class="language-java">public class Singleton {
    private static Singleton uniqueInstance;

    private Singleton() {}

    public static synchronized Singleton getInstance() {
        if (uniqueInstance == null) {
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
}</code></pre>
<p>하지만, 위의 방법은 동기화가 좀 아깝게 느껴질 수 있습니다. 왜냐하면 꼭 필요한 시점이 메소드를 시작할 때 뿐이기 때문입니다. Head First Design Patterns에서는 아래와 같이 해결 방법을 제시합니다.</p>
<ol>
<li><p><code>getInstance()</code> 의 속도가 그리 중요하지 않다면 그냥 둡니다.</p>
</li>
<li><p>인스턴스를 필요할 때 생성하지 말고, 처음부터 만들어 버립니다. </p>
<pre><code class="language-java"> public class SingletonNoSynchronized {
     private static final SingletonNoSynchronized uniqueInstance = new SingletonNoSynchronized();

     private SingletonNoSynchronized() {
     }

     private static SingletonNoSynchronized getInstance() {
         return uniqueInstance;
     }
 }</code></pre>
</li>
<li><p>DCL(Double-checking Locking)을 써서 <code>getInstance()</code> 의 동기화 부분을 줄입니다. </p>
<p> <code>volatile</code> 을 사용하는 이유는 <a href="https://nesoy.github.io/articles/2018-06/Java-volatile">reference</a>를 읽어보는 것이 좋을 것 같습니다. </p>
<pre><code class="language-java"> public class DoubleCheckLock {
     private volatile static DoubleCheckLock uniqueInstance;

     private DoubleCheckLock() {}

     public static DoubleCheckLock getInstance() {
         if (uniqueInstance == null) {
             synchronized (DoubleCheckLock.class) {
                 if (uniqueInstance == null) {
                     return new DoubleCheckLock();
                 }
             }
         }

         return uniqueInstance;
     }
 }</code></pre>
</li>
</ol>
<h1 id="추가-정보">추가 정보</h1>
<ul>
<li>클래스 로더가 두 개 이상이라면 같은 클래스를 여러 번 로딩할 수도 있습니다. 클래스 로더를 여러 개 사용한다면 싱글턴 패턴 사용을 조심해야 합니다. 클래스 로더를 직접 지정해서 이 문제를 피할 수 있습니다.</li>
<li>책에서는 다루지 않고 있지만 싱글톤 패턴을 구현하기 위해 <code>Lazy Holder</code> 라는 방식이 있으니 참고하시면 좋습니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Factory Pattern]]></title>
            <link>https://velog.io/@ye-geeee/Factory-Pattern</link>
            <guid>https://velog.io/@ye-geeee/Factory-Pattern</guid>
            <pubDate>Mon, 31 May 2021 23:21:20 GMT</pubDate>
            <description><![CDATA[<p>흔히 말하는 팩토리 패턴(Factory Pattern)에는 팩토리 메소드 패턴(Factory Method Pattern)과 추상 팩토리 패턴(Abstract Factory Pattern) 두 가지 패턴이 있습니다. 이 패턴들에 대해 오늘 순서대로 알아보겠습니다.</p>
<h1 id="팩토리-패턴factory-pattern의-필요성">팩토리 패턴(Factory Pattern)의 필요성</h1>
<p>new를 사용하는 것은 구상 클래스의 인스턴스를 만드는 것입니다. 구상 클래스를 바탕으로 코딩을 하면 나중에 코드를 수정해야할 가능성이 높아지고, 유연성이 떨어지게 됩니다.</p>
<p>그 예가 아래와 같습니다. <a href="https://github.com/ye-geeee/headfirst-designpattern-practice/tree/fc40a14479769de7f183756cd9d76b2ebbbb8e61/factory-pattern/src">code reference</a></p>
<p>구상 클래스를 사용하면 아래처럼 조건에 따라 만들려고 하는 구상 클래스를 명시해줘야 합니다. 이는 뭔가 변경하거나 확장해야할 때 코드를 또 확인하고 추가해야한다는 뜻이죠. <strong>이걸 다른 메소드 또는 객체로 클래스 생성을 위임하여 역할을 분리하는 것이 바로 팩토리 패턴입니다.</strong>  </p>
<pre><code class="language-java">Pizza orderPizza(String type) {
      Pizza pizza;

      if (type.equals(&quot;cheese&quot;)) {
          pizza = new CheesePizza();
      } else if (type.equals(&quot;greek&quot;)) {
          pizza = new GreekPizza();
      } else if (type.equals(&quot;pepperoni&quot;)) {
          pizza = new PepperoniPizza();
      }

      pizza.prepare();
      pizza.bake();
      pizza.cut();
      pizza.box();
      return pizza;
}</code></pre>
<p>자, 이제 간단한 팩토리를 만들어 이를 클래스 생성을 위임해 봅시다. </p>
<p>이 작업 전에 바뀌는 부분과 안바뀌는 부분을 구분해야 합니다. 변하는 부분은 pizza 인스턴스를 생성하는 부분, 변하지 않는 부분은 나머지 작업이네요. 하나의 factory class를 생성하여 변하는 부분을 다른 클래스로 분리합니다.</p>
<p><a href="https://github.com/ye-geeee/headfirst-designpattern-practice/tree/cb732aa549d0857ec7e47454340b37e6f4b09cab">code reference link</a></p>
<pre><code class="language-java">public class SimplePizzaFactory {
    public Pizza createPizza(String type) {
        Pizza pizza = null;

        if (type.equals(&quot;cheese&quot;)) {
            pizza = new CheesePizza();
        } else if (type.equals(&quot;greek&quot;)) {
            pizza = new GreekPizza();
        } else if (type.equals(&quot;pepperoni&quot;)) {
            pizza = new PepperoniPizza();
        }

        return pizza;
    }
}</code></pre>
<p>위처럼하면 <code>SimplePizzaFactory</code>가 클라이언트가 많을 때에 빛을 발휘합니다. 만약 <code>SimplePizzaFactory</code>가 없었다면 모든 클라이언트에서 수정 작업을 해줘야 합니다. </p>
<h1 id="팩토리-메소드-패턴factory-method-pattern">팩토리 메소드 패턴(Factory Method Pattern)</h1>
<p><a href="https://github.com/ye-geeee/headfirst-designpattern-practice/tree/84961ba687aa4e54ed28c87fce4a3eb3a7ef20a2/factory-method-pattern/src">code reference</a></p>
<p>팩토리 메소드 패턴(Factory Method Pattern)은 추상 메소드를 이용하여 생성하는 객체를 <strong>서브 클래스에서 결정</strong>하게 구현하는 것입니다. </p>
<p><em>PizzaStore.java</em></p>
<pre><code class="language-java">public abstract class PizzaStore {

    Pizza orderPizza(String type) {
            Pizza pizza;
            pizza = createPizza(type);

                    /* 피자를 준비하고 굽고 커팅하는 과정 */
        }
            /* PizzaStore에서는 만들 피자를 결정하지 않고 서브 클래스에서 결정 */
        public abstract Pizza createPizza(String type);
    }
}</code></pre>
<p><em>ChicagoPizzaStore.java</em></p>
<pre><code class="language-java">public class ChicagoPizzaStore extends PizzaStore {

    @Override
    public Pizza createPizza(String type) {
        if (type.equals(&quot;cheese&quot;)) {
            return new ChicacoStyleCheesePizza();
        } else if (type.equals(&quot;greek&quot;)) {
            return new ChicagoStyleGreekPizza();
        } else if (type.equals(&quot;pepperoni&quot;)) {
            return new ChicagoStylePepperoniPizza();
        } else {
            return null;
        }
    }
}</code></pre>
<p>팩토리 메소드는 객체 생성을 처리하며, 팩토리 메소드를 이용하면 <strong>객체를 생성하는 작업을 서브클래스에 캡슐화시킬 수 있습니다.</strong> 이렇게 하면 수퍼클래스에 있는 클라이언트 코드와 서브클래스에 있는 객체 생성 코드를 분리시킬 수 있습니다. </p>
<p>팩토리 메소드 패턴의 정의는 아래와 같습니다. </p>
<p><strong>팩토리 메소드 패턴</strong> - 팩토리 메소드 패턴에서는 객체를 생성하기 위한 인터페이스를 정의하는데, 어떤 클래스의 인스턴스를 만들지는 서브클래스에서 결정하게 만듭니다. 팩토리 메소드 패턴을 이용하면 클래스의 인스턴스를 만드는 일을 서브클래스에게 맡기는 것이죠.</p>
<p><img src="https://images.velog.io/images/ye-geeee/post/803c4960-0b47-4857-84b9-b18cc0c59759/FactoryMethodPattern.png" alt=""></p>
<p>간단한 팩토리 패턴은 일회성으로 사용가능한 반면, 팩토리 메소드 패턴을 이용하면 어떤 구현을 사용할지를 서브 클래스에서 결정하는 프레임워크를 만들 수 있습니다. </p>
<h1 id="의존성-뒤집기-원칙dependency-inversion-principle">의존성 뒤집기 원칙(Dependency Inversion Principle)</h1>
<p>Design Principle 6.
추상화된 것에 의존하도록 만들어라. 구상 클래스에 의존하도록 만들지 않도록 한다.</p>
<p>고수준 구성요소가 저수준 구성요소에 의존하면 안됩니다. </p>
<p>예를 들어, 예시에서 <code>Pizza</code> 라는 상위 클래스가 없었다면 <code>PizzaStore</code> 클래스는 여러 피자 종류를 감당하고 여러 피자 종류의 클래스에 의존하고 있었을 것입니다. 하지만 <code>Pizza</code> 라는 상위 클래스를 생성함으로써 <code>PizzaStore</code> 는 <code>Pizza</code> 를 구성으로 가지고 있고 나머지 피자 종류 클래스는 <code>Pizza</code> 에 의존하게 됩니다. </p>
<h1 id="원칙을-지키는-데-도움이-될만한-가이드라인">원칙을 지키는 데 도움이 될만한 가이드라인</h1>
<ul>
<li><p>어떤 변수에도 구상 클래스에 대한 레퍼런스를 저장하지 맙시다.</p>
</li>
<li><p>구상 클래스에서 유도된 클래스를 만들지 맙시다.</p>
<p>  → 구상 클래스에서 유도된 클래스를 만들면 특정 구상 클래스에 의존하게 됩니다. </p>
</li>
<li><p>베이스 클래스에 이미 구현되어 있던 메소드를 오버라이드하지 맙시다.</p>
<p>  → 오버라이드가 필요한 경우는 추상화가 잘못된 경우라고 볼 수 있습니다. </p>
</li>
</ul>
<h1 id="추상-팩토리-패턴abstract-factory-pattern">추상 팩토리 패턴(Abstract Factory Pattern)</h1>
<p>추상 팩토리 패턴 - 추상 팩토리 패턴에서는 인터페이스를 이용하여 서로 연관된 , 또는 의존하는 객체를 구상 클래스를 지정하지 않고도 생성할 수 있습니다. </p>
<p><img src="https://images.velog.io/images/ye-geeee/post/98e39fac-4307-401e-b6ad-6bcbb7517855/AbstractFactoryPattern.png" alt=""></p>
<p>추상 팩토리 패턴을 사용하면 클라이언트에서 추상 인터페이스를 통해 제품을 공급받을 수 있습니다. 이를 통해 클라이언트에서는 구성 클래스에 대한 의존성을 분리할 수 있습니다. </p>
<p>다이어그램을 확인해보면 <code>Client</code>에서는<code>AbstractProductA</code>, <code>AbstractProductB</code> 를 구성하고 있습니다. <code>Client</code> 는 실제 어떤 구성 클래스를 포함하고 있는지 알지 못합니다. </p>
<p>이 구성 변수는 <code>Client</code> 코드 상에는 인터페이스를 통해 추상화시키고, 실제 객체 구상 클래스는 <code>AbstractFactory</code> 를 구현한 하위 클래스(<code>ConcreteFactor1</code> 인지 <code>ConcreteFactory2</code>)에서 지정합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Decorator Pattern]]></title>
            <link>https://velog.io/@ye-geeee/Decorator-Pattern</link>
            <guid>https://velog.io/@ye-geeee/Decorator-Pattern</guid>
            <pubDate>Sun, 30 May 2021 08:10:53 GMT</pubDate>
            <description><![CDATA[<h1 id="ocpopen-closed-principal">OCP(Open-Closed Principal)</h1>
<blockquote>
<p>Design Principal 5.
클래스는 확장에 대해서는 열려 있어야 하지만 코드 변경에 대해서는 닫혀 있어야 한다.</p>
</blockquote>
<p>기존 코드는 건드리지 않은 채로 확장을 통해서 새로운 행동을 간단하게 추가할 수 있게 구조를 잡으면 새로운 기능을 아주 유연하게 추가할 수 있으면서도 강하고 견고한 디자인을 만들 수 있습니다. 다만, 무조건 OCP를 적용하는 것은 시간 낭비가 될 수도 있고, 쓸 데 없는 일일 수 있으니 유의하여야 합니다.</p>
<h1 id="데코레이터-패턴decorator-pattern의-정의">데코레이터 패턴(Decorator Pattern)의 정의</h1>
<p>데코레이터 패턴은 객체를 다른 객체로 &quot;장식&quot;하는 것입니다. 데코레이터 패턴은 아래와 같이 정의됩니다.</p>
<blockquote>
<p>데코레이터 패턴에서는 객체에 추가적인 요건을 동적으로 첨가한다. 데코레이터는 서브클래스를 만드는 것을 통해서 기능을 유연하게 확장할 수 있는 방법을 제공한다.</p>
</blockquote>
<p><img src="https://images.velog.io/images/ye-geeee/post/199ad7c2-f7ce-4c38-ae96-147f7ded8b9a/DecoratorPatterns.png" alt=""></p>
<p>새로운 동작은 <code>ConcreteComponent</code> 에 동적으로 추가하게 됩니다. </p>
<p>각 <code>Decorator</code> 안에는 <code>Component</code> 객체가 들어있고, 자신이 장식할 구성요소와 같은 인터페이스 또는 추상 클래스를 구현합니다. </p>
<h1 id="데코레이터-패턴decorator-pattern-동작-방식">데코레이터 패턴(Decorator Pattern) 동작 방식</h1>
<p>Head First Java에서 예제로 사용하고 있는 코드는 아래와 같습니다. </p>
<p><a href="https://github.com/ye-geeee/headfirst-designpattern-practice/tree/master/decorator-pattern/src">code reference</a></p>
<p><img src="https://images.velog.io/images/ye-geeee/post/b309223c-f8ec-48a7-84e4-3791796f6f25/DecoratorPatterns-sample.png" alt=""></p>
<p>데코레이터의 특징은 아래와 같습니다. </p>
<ol>
<li>데코레이터의 수퍼클래스는 자신이 장식하고 있는 객체의 수퍼클래스와 같습니다.</li>
<li>한 객체를 여러 개의 데코레이터로 감쌀 수 있습니다.</li>
<li>데코레이터는 자신이 감싸고 있는 객체와 같은 수퍼클래스를 가지고 있기 때문에 원래 객체가 들어갈 자리에 데코레이터 객체를 집어넣어도 상관 없습니다. </li>
<li>데코레이터는 자신이 장식하고 있는 객체에서 어떤 행동을 위임하는 것 외에 원하는 추가적인 작업을 수행할 수 있습니다.</li>
<li>객체는 언제든지 감쌀 수 있기 때문에 실행 중에 필요한 데코레이터를 마음대로 적용할 수 있습니다.</li>
</ol>
<p>데코레이터 패턴은 빌더 패턴과 팩토리 패턴과 함께 사용하면 더 &quot;잘 캡슐화 되어 있다&quot;를 깨달을 수 있습니다.</p>
<p>하지만, 데코레이터 패턴을 사용하면 자잘한 객체들이 매우 많이 추가될 수 있고, 데코레이터를 너무 ㅁ낳이 사용하면 코드가 필요 이상으로 복잡해질 수 있으니 유의하여 사용하여야 합니다. </p>
<h1 id="자바-io에서-적용된-데코레이터-패턴decorator-pattern">자바 I/O에서 적용된 데코레이터 패턴(Decorator Pattern)</h1>
<p><a href="http://java.io">java.io</a> 하위 클래스들도 데코레이터 패턴을 이용하여 만들어져 있습니다. </p>
<p><img src="https://images.velog.io/images/ye-geeee/post/183ea55d-6dbc-46d9-81f0-7600ccb1e75b/DecoratorPattern-java.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Observer Pattern]]></title>
            <link>https://velog.io/@ye-geeee/Observer-Pattern</link>
            <guid>https://velog.io/@ye-geeee/Observer-Pattern</guid>
            <pubDate>Fri, 28 May 2021 23:47:43 GMT</pubDate>
            <description><![CDATA[<h1 id="옵저버-패턴observer-pattern-동작-방식">옵저버 패턴(Observer Pattern) 동작 방식</h1>
<p>옵저버 패턴(Observer Pattern)에서는 한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체들한테 연락이 가고 자동으로 내용이 갱신되는 방식으로 일대다(one-to-many) 의존성을 정의합니다.</p>
<p><a href="https://github.com/ye-geeee/headfirst-designpattern-practice/tree/31a2c5038f4876cb4b7f0f276119c7c007e736ba/observer-pattern/src">code reference</a></p>
<ol>
<li>주제 객체에 옵저버를 옵저버 목록에 추가합니다.</li>
<li>주제 객체의 값이 바뀌면 등록된 옵저버들에게 연락을 합니다.</li>
<li>데이터를 받을 필요가 없는 옵저버들은 옵저버 목록에서 삭제합니다.</li>
</ol>
<p><img src="https://images.velog.io/images/ye-geeee/post/fdb1012e-7070-4ee1-84d0-5742ebd6a2d5/ObserverPattern.png" alt=""></p>
<h1 id="느슨한-결합loose-coupling의-위력">느슨한 결합(Loose coupling)의 위력</h1>
<p>옵저버 패턴에서는 주제와 옵저버가 느슨하게 결합되어 있는 객체 디자인을 제공합니다.</p>
<ul>
<li>주제가 옵저버에 대해서 아는 것은 옵저버가 특정 인터페이스를(Observer Interface)를 구현한다는 것 뿐입니다.</li>
<li>옵저버는 언제든지 새로 추가할 수 있습니다.</li>
<li>새로운 형식의 옵저버를 추가하려고 할 때도 주제를 전혀 변경할 필요가 없습니다.</li>
<li>주제와 옵저버는 서로 독립적으로 재사용할 수 있습니다.</li>
<li>주제나 옵저버나 바뀌더라도 서로한테 영향을 미치ㅈ는 않습니다.</li>
</ul>
<blockquote>
<p>Design Principal 4.
서로 상호작용을 하는 객체 사이에서는 가능하면 느슨하게 결합하는 디자인을 사용해야 한다.</p>
</blockquote>
<h1 id="자바-내장-옵저버-패턴observer-pattern-사용하기">자바 내장 옵저버 패턴(Observer Pattern) 사용하기</h1>
<p><a href="https://github.com/ye-geeee/headfirst-designpattern-practice/tree/master/observer-pattern/src">code reference</a></p>
<p><img src="https://images.velog.io/images/ye-geeee/post/fa84ddda-9773-49af-9f5a-b5298ddc4d7c/ObserverPattern-java.png" alt=""></p>
<p>자바 내장 옵저버 패턴을 사용하면 푸시 방식으로 갱신할 수도 있고, 풀 방식으로도 갱신할 수 있다는 장점이 있습니다. </p>
<ul>
<li><p>객체가 옵저버(Observer)가 되는 방법</p>
<p>  Observer 인터페이스를 구현하고 addObservers를 호출합니다. </p>
<pre><code class="language-java">  import java.util.Observable;
  import java.util.Observer;

  public class CurrentConditionsDisplay implements Observer, DisplayElement {
      Observable observable;
      private float temperature;
      private float humidity;

      public CurrentConditionsDisplay(Observable observable) {
          this.observable = observable;
          observable.addObserver(this);
      }

      @Override
      public void update(Observable o, Object arg) {
          if (o instanceof WeatherData) {
              WeatherData weatherData = (WeatherData) o;
              this.temperature = ((WeatherData) o).getTemperature();
              this.humidity = ((WeatherData) o).getHumidity();
              display();
          }
      }

      @Override
      public void display() {
          System.out.println(&quot;Current condition : &quot; + temperature + &quot;F degress and &quot; + humidity + &quot;% humidity&quot;);
      }
  }</code></pre>
</li>
<li><p>Observable에서 연락을 돌리는 방법</p>
<ol>
<li><p>setChanged() 메소드를 호출해서 객체의 상태가 바뀌었다는 것을 알립니다.</p>
</li>
<li><p>그 다음으로 <code>notifyObservers()</code> 또는 <code>notifyObservers(Object args)</code> 를 호출합니다.</p>
<pre><code class="language-java">import java.util.Observable;

public class WeatherData extends Observable {
 private float temperature;
 private float humidity;
 private float pressure;

 public WeatherData() {
 }

 public void measurementsChanged() {
     setChanged();
     notifyObservers();
 }

 public void setMeasurements(float temperature, float humidity, float pressure) {
     this.temperature = temperature;
     this.humidity = humidity;
     this.pressure = pressure;
     measurementsChanged();
 }

 public float getTemperature() {
     return temperature;
 }

 public float getHumidity() {
     return humidity;
 }

 public float getPressure() {
     return humidity;
 }
}</code></pre>
</li>
</ol>
</li>
<li><p>옵저버(Observer)가 연락을 받는 방법</p>
<p>  <code>update(Observable o, Object args)</code> 를 통해 메소드를 구현합니다. </p>
</li>
</ul>
<h3 id="observable에-setchanged의-사용법">Observable에 setChanged()의 사용법</h3>
<p>데이터가 수없이 변화할 때에 모든 변화에 대해서 옵저버(Observer)들에게 호출하지 않고 특정 조건일 때에만 호출을 할 수 있도록 연락을 최적화해주는 용도로 사용하게 됩니다. </p>
<h3 id="java-obervable을-사용했을-경우의-특징">Java Obervable을 사용했을 경우의 특징</h3>
<p>옵저버(Observer)들에게 연락을 순차적으로 돌리지 않습니다.</p>
<h1 id="javautilobservable의-단점">java.util.Observable의 단점</h1>
<ol>
<li><p>interface가 아니고 class이기 때문에 재사용성에 있어 제약조건이 발생합니다.</p>
</li>
<li><p>Observable 인터페이스라는 것이 엇기 때문에 Observer API하고 잘 맞는 클래스를 직접 구현하는 것이 불가능합니다.</p>
</li>
<li><p>Observable 클래스의 핵심 메소드를 외부에서 호출할 수 없습니다.</p>
<p> Observable의 subclass에서만 setter를 호출할 수 있기 때문에 값 변경이 불가합니다.</p>
<p> 이는 <code>상속보다 구성</code> 이라는 디자인 원칙에도 위배됩니다.</p>
</li>
</ol>
<p>Java의 Observer &amp; Observable은 Java9부터 <code>deprecated</code> 되었으니 참고 부탁드립니다. 
<a href="https://docs.oracle.com/javase/9/docs/api/java/util/Observable.html">Java SE 9 문서의 Observable</a></p>
<blockquote>
<p>Deprecated. 
This class and the Observer interface have been deprecated. The event model supported by Observer and Observable is quite limited, the order of notifications delivered by Observable is unspecified, and state changes are not in one-for-one correspondence with notifications. For a richer event model, consider using the java.beans package. For reliable and ordered messaging among threads, consider using one of the concurrent data structures in the java.util.concurrent package. For reactive streams style programming, see the Flow API.</p>
</blockquote>
]]></description>
        </item>
    </channel>
</rss>