<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>DOOWN</title>
    <link>https://down-develope.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Thu, 13 Aug 2026 23:50:34 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>DOWN</managingEditor>
    <item>
      <title>백준 2513번 : 통학버스 (C++)</title>
      <link>https://down-develope.tistory.com/46</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsxlMu/btrnd6cBDSc/7j09uU8jS1jlIbjvKWHsyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsxlMu/btrnd6cBDSc/7j09uU8jS1jlIbjvKWHsyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsxlMu/btrnd6cBDSc/7j09uU8jS1jlIbjvKWHsyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsxlMu%2Fbtrnd6cBDSc%2F7j09uU8jS1jlIbjvKWHsyK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;75&quot; height=&quot;42&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제: &lt;a href=&quot;https://www.acmicpc.net/problem/2513&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/2513&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1638786865429&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;2513번: 통학버스&quot; data-og-description=&quot;첫째 줄에는 세 개의 양의 정수 N, K, S가 빈칸을 사이에 두고 순서대로 주어진다. 첫 번째 정수 N은 아파트 단지의 수이며 2 &amp;le; N &amp;le; 30,000이다. 두 번째 정수 K는 1 &amp;le; K &amp;le; 2,000이며, 통학버스의 정원&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/2513&quot; data-og-url=&quot;https://www.acmicpc.net/problem/2513&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/izRgT/hyMB9WdsRF/uZjF4a1aXapORoSPZgXMjK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2513&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/2513&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/izRgT/hyMB9WdsRF/uZjF4a1aXapORoSPZgXMjK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;2513번: 통학버스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;첫째 줄에는 세 개의 양의 정수 N, K, S가 빈칸을 사이에 두고 순서대로 주어진다. 첫 번째 정수 N은 아파트 단지의 수이며 2 &amp;le; N &amp;le; 30,000이다. 두 번째 정수 K는 1 &amp;le; K &amp;le; 2,000이며, 통학버스의 정원&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수용 한계량이 있는 통학버스가 존재할 때, 모든 학생을 태울 수 있는 최소거리를 찾는 문제입니다.&lt;br /&gt;생각을 해보면 모든 학생을 태워야 하므로 멀리 있는 학생 위치도 결국엔 한 번 이상은 지나야 합니다. 그래서 멀리 있는 학생들부터 태워서 오는 길에 수용량이 남으면 태우는 방법으로 하면 최소거리를 구할 수 있는 그리디 문제입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;통학버스의&amp;nbsp;시작&amp;nbsp;위치를&amp;nbsp;s라&amp;nbsp;하면&amp;nbsp;s의&amp;nbsp;왼쪽에&amp;nbsp;존재하는&amp;nbsp;학생과&amp;nbsp;오른쪽에&amp;nbsp;존재하는&amp;nbsp;학생들을&amp;nbsp;서로&amp;nbsp;다른&amp;nbsp;vector에&amp;nbsp;집어넣고&amp;nbsp;멀리&amp;nbsp;있는&amp;nbsp;학생들부터&amp;nbsp;처리할&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;sort를&amp;nbsp;해줍니다.&amp;nbsp;그리고&amp;nbsp;while&amp;nbsp;loop을&amp;nbsp;돌면서&amp;nbsp;해당&amp;nbsp;vector가&amp;nbsp;빈&amp;nbsp;vector가&amp;nbsp;되도록&amp;nbsp;로직을&amp;nbsp;실행하게&amp;nbsp;하면&amp;nbsp;쉽게&amp;nbsp;구현&amp;nbsp;가능한&amp;nbsp;문제입니다. &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1638786880897&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;vector&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;algorithm&amp;gt;

using namespace std;


int caculateDistance(vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; &amp;amp; Students, int k, int s){
    int nowPos, nowNum, ans;

    nowPos = s;
    nowNum = 0;
    ans = 0;
    
    while(!Students.empty()){
        int pos = Students.back().first;
        int num = Students.back().second;
        
        if(num + nowNum &amp;lt;= k){
            Students.pop_back();
            nowNum += num;
        }
        else{
            Students.back().second -= k - nowNum;
            nowNum += k - nowNum;
        }

        ans += abs(nowPos - pos);
        nowPos = pos;

        if(nowNum == k || Students.empty()){
            ans += abs(nowPos - s);
            nowPos = s;
            nowNum = 0;
        }
    }

    return ans;
}

int main(){

    int n, k, s;
    cin &amp;gt;&amp;gt; n &amp;gt;&amp;gt; k &amp;gt;&amp;gt; s;
    
    vector&amp;lt;pair&amp;lt;int, int&amp;gt;&amp;gt; leftStudents, rightStudents;

    for(int i=0; i&amp;lt;n; i++){
        int pos, num;
        cin &amp;gt;&amp;gt; pos &amp;gt;&amp;gt; num;
        if(pos &amp;lt; s){
            leftStudents.push_back(make_pair(pos, num));
        }
        else if(pos &amp;gt; s){
            rightStudents.push_back(make_pair(pos, num));
        }
    }

    sort(leftStudents.begin(), leftStudents.end(), greater&amp;lt;&amp;gt;());
    sort(rightStudents.begin(), rightStudents.end(), less&amp;lt;&amp;gt;());

    cout &amp;lt;&amp;lt; caculateDistance(leftStudents, k, s) + caculateDistance(rightStudents, k , s);

    return 0;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘/BOJ</category>
      <author>DOWN</author>
      <guid isPermaLink="true">https://down-develope.tistory.com/46</guid>
      <comments>https://down-develope.tistory.com/46#entry46comment</comments>
      <pubDate>Mon, 6 Dec 2021 19:39:36 +0900</pubDate>
    </item>
    <item>
      <title>논문리뷰  A Study of BFLOAT16 for Deep Learning Training</title>
      <link>https://down-develope.tistory.com/45</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Abstraction &amp;amp; Introduction&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 논문은 19년도에 발표된 논문으로 딥러닝 half precision 기법에서 INT16, FP16 대신 Bfloat16을 제안합니다. Bfloat16란 16bit floating 숫자로 아래 사진에 나와있듯이 FP32와 지수 부분 비트수가 같다는 특징이 있습니다. 그래서 FP32보다는 정확도는 떨어지지만 표현할수 있는 범위가 같다는 특징이 있습니다. 원래 BFloat16는 구글의 &lt;span style=&quot;color: #000000;&quot;&gt;DistBelief 머신러닝 프레임워크에서 처음 제안됬습니다. 멀티 node 환경에서 shared memory의 volume을 줄이기 위해 제안된 데이터 타입으로 지금은 이제 딥러닝의 computing에 있어서 사용됩니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;894&quot; data-origin-height=&quot;253&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCX6vO/btrdITAO0sY/sVKhyyU1IQc5h6htvi7Yq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCX6vO/btrdITAO0sY/sVKhyyU1IQc5h6htvi7Yq1/img.png&quot; data-alt=&quot;출처 - 구글 클라우드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCX6vO/btrdITAO0sY/sVKhyyU1IQc5h6htvi7Yq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCX6vO%2FbtrdITAO0sY%2FsVKhyyU1IQc5h6htvi7Yq1%2Fimg.png&quot; data-origin-width=&quot;894&quot; data-origin-height=&quot;253&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/p&gt;
&lt;div id=&quot;dicLayer&quot; style=&quot;color: #000000; font-size: 12px; font-family: Arial; background: -webkit-linear-gradient(bottom, #ffeb00, #ffdc00); width: 400px; height: 150px; display: none; left: 132px; top: 1470px;&quot;&gt;
&lt;div id=&quot;dicLayerContents&quot;&gt;f  &lt;input id=&quot;ee&quot; type=&quot;checkbox&quot; /&gt;Eng&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1.f&lt;br /&gt;&lt;br /&gt;[약어] 여성(female)&lt;br /&gt;&lt;br /&gt;2.f1&lt;br /&gt;&lt;br /&gt;[명사] 에프 ((영어 알파벳의 제6자))&lt;br /&gt;&lt;br /&gt;3.f.&lt;br /&gt;&lt;br /&gt;farthing; fathom; feet; female; feminine; field; filly; folio; following; foot; [야구] foul(s); franc(s); frequency;&lt;br /&gt;&lt;br /&gt;4.f.&lt;br /&gt;&lt;br /&gt;forte ((It. = loud))&lt;br /&gt;&lt;br /&gt;5.f.&lt;br /&gt;&lt;br /&gt;[L fortasse]perhaps; [G f&amp;uuml;r]for&lt;br /&gt;&lt;br /&gt;6.정상2 正常&lt;br /&gt;&lt;br /&gt;(제대로인 상태) normality, (formal) normalcy&lt;br /&gt;&lt;br /&gt;7.패러다임 paradigm&lt;br /&gt;&lt;br /&gt;(인식 체계)(formal) paradigm&lt;br /&gt;&lt;br /&gt;8.조우하다 遭遇하다&lt;br /&gt;&lt;br /&gt;(우연히 만나다) (formal) encounter, run into, run across, come across, bump into, (literary) come upon&lt;br /&gt;&lt;br /&gt;9.수정능력 受精能力&lt;br /&gt;&lt;br /&gt;(의학) F, fertility&lt;br /&gt;&lt;br /&gt;10.역[힘] 力&lt;br /&gt;&lt;br /&gt;(의학) F&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div id=&quot;dicLayerSub&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;dicRawData&quot; style=&quot;display: none;&quot;&gt;{&quot;mean&quot;:[&quot;f&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;[약어]\n\t\t \t\t여성(female)&quot;,&quot;f1&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;[명사]\n\t\t \t\t에프 ((영어 알파벳의 제6자))&quot;,&quot;f.&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;farthing; fathom; feet; female; feminine; field; filly; folio; following; foot; [야구] foul(s); franc(s); frequency;&quot;,&quot;f.&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;forte ((It. = loud))&quot;,&quot;f.&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;[L fortasse]perhaps; [G f&amp;uuml;r]for&quot;,&quot;정상2\n \t\t\t正常&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;(제대로인 상태) normality, (formal) normalcy&quot;,&quot;패러다임\n \t\t\tparadigm&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;(인식 체계)(formal) paradigm&quot;,&quot;조우하다\n \t\t\t遭遇하다&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;(우연히 만나다) (formal) encounter, run into, run across, come across, bump into, (literary) come upon&quot;,&quot;수정능력\n \t\t\t受精能力&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;(의학)\n\t\t \t\tF, fertility&quot;,&quot;역[힘]\n \t\t\t力&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;(의학)\n\t\t \t\tF&quot;],&quot;word&quot;:&quot;\n\t\t\t\t\t\tf\n \t\t\t\n\t \t\n\t &quot;,&quot;soundUrl&quot;:&quot;https://dict-dn.pstatic.net/v?_lsu_sa_=3e08d75fbd7131b67494012d32245dfafd836aa5810b8fb46e42ee7e9b816d717c5157846ca5ae79890e62a5122070cc70f885a796164785e0414c3f5a8dabe66381d8b01193765c26732f2dbbedda1125e2c46af65db5eafcdfce1488633927a92f8a21a3a581fcc5f652b37109070c1d8d53aa59f22d7ec0347fc6934f5165&quot;,&quot;phoneticSymbol&quot;:&quot;&quot;}&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;dicLayerLoader&quot; class=&quot;&quot; style=&quot;top: 1484px; left: 100px;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;INT16과 FP16은 FP32보다 표현할 수 있는 값의 범위가 더 작습니다. 그래서 딥러닝의 순전파나 역전파에서 사용하기 위해서는 overflow나 underflow를 방지용으로 scaling 작업이 필요합니다. 이러한 overhead가 bfloat16의 중요성을 대두 시켰고, 이 논문에서 다양한 도메인의 모델에서 직접 Bfloat16을 실험해 보아 sota만큼의 성능을 달성할 수 있음을 증명합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Emulation&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;829&quot; data-origin-height=&quot;443&quot; width=&quot;638&quot; height=&quot;341&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dmrtMd/btrdK6e6SlK/rl9JVb6jMAm7KivWhtQevk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dmrtMd/btrdK6e6SlK/rl9JVb6jMAm7KivWhtQevk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dmrtMd/btrdK6e6SlK/rl9JVb6jMAm7KivWhtQevk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdmrtMd%2FbtrdK6e6SlK%2Frl9JVb6jMAm7KivWhtQevk%2Fimg.png&quot; data-origin-width=&quot;829&quot; data-origin-height=&quot;443&quot; width=&quot;638&quot; height=&quot;341&quot; data-ke-mobilestyle=&quot;widthOrigin&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;지금 21년도 기준으로, Nvidia Ampere 시리즈인 A100, Rtx 3000번대 GPU와 구글의 TPU V2, V3는 Bfloat16을 하드웨어 적으로 지원합니다. 하지만 이 논문이 발표됬을 당시에는 그러하지 않았으므로 Bfloat16 방식으로 traing을 시키기 위해 Emulation하는 방법을 사용합니다. 위 그림에서 Q는 Quantlib이라는 라이브러리로 FP32 -&amp;gt; BF16으로 typecasting 해주는 소프트웨어로 직접 개발하였다고 합니다. 그래서 이 Quantlib을 이용하여 input activation과 weight를 BF16으로 typecasting 시켜주고 GEMM 연산 후, Accumlation에서는 정확도를 위해 FP32 타입을 사용했다고 합니다. 이러한 방식으로 실제 실험에 사용되는 GPU는 BF16을 지원하지 않지만 동일한 결과를 내놓는 Emulation 환경을 만들었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Result &amp;ndash; CNN Image classification&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;977&quot; data-origin-height=&quot;400&quot; width=&quot;662&quot; height=&quot;271&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0KQDT/btrdKVLn287/Lfx6X6q8m0XKTS6euJyfq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0KQDT/btrdKVLn287/Lfx6X6q8m0XKTS6euJyfq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0KQDT/btrdKVLn287/Lfx6X6q8m0XKTS6euJyfq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0KQDT%2FbtrdKVLn287%2FLfx6X6q8m0XKTS6euJyfq1%2Fimg.png&quot; data-origin-width=&quot;977&quot; data-origin-height=&quot;400&quot; width=&quot;662&quot; height=&quot;271&quot; data-ke-mobilestyle=&quot;widthOrigin&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;첫번째는 CNN 기반인 AlexNet과 ResNET-50을 &lt;span style=&quot;color: #000000;&quot;&gt;ImageNet Large Scale Visual Recognition Competition (ILSVRC)을 학습시킨 결과입니다. 보시면 알겠지만 FP32와 비교했을 때, AlexNet 같은경우 0.5% 포인트 내외로 차이가 나는것을 확인할 수 있고 ResNet-50 같은 경우 동일하게 학습 되었다는 것을 확인할 수 있습니다. 이로서 CNN 도메인에서 BF16을 이용한 학습이 유효하다는 것을 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Result - Recurrent neural networks (RNN)&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1096&quot; data-origin-height=&quot;419&quot; width=&quot;701&quot; height=&quot;268&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cobJuF/btrdITU9CRi/gRyLDpAEnCxhf8LG9tDra0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cobJuF/btrdITU9CRi/gRyLDpAEnCxhf8LG9tDra0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cobJuF/btrdITU9CRi/gRyLDpAEnCxhf8LG9tDra0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcobJuF%2FbtrdITU9CRi%2FgRyLDpAEnCxhf8LG9tDra0%2Fimg.png&quot; data-origin-width=&quot;1096&quot; data-origin-height=&quot;419&quot; width=&quot;701&quot; height=&quot;268&quot; data-ke-mobilestyle=&quot;widthOrigin&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;div id=&quot;dicLayer&quot;&gt;
&lt;div id=&quot;dicLayerContents&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;dicLayerSub&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;dicRawData&quot; style=&quot;display: none;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;dicLayerLoader&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;909&quot; data-origin-height=&quot;170&quot; width=&quot;486&quot; height=&quot;91&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dpEaEM/btrdK58lMXI/BKYjZFTiquDChMsYqqzUt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dpEaEM/btrdK58lMXI/BKYjZFTiquDChMsYqqzUt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dpEaEM/btrdK58lMXI/BKYjZFTiquDChMsYqqzUt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdpEaEM%2FbtrdK58lMXI%2FBKYjZFTiquDChMsYqqzUt1%2Fimg.png&quot; data-origin-width=&quot;909&quot; data-origin-height=&quot;170&quot; width=&quot;486&quot; height=&quot;91&quot; data-ke-mobilestyle=&quot;widthOrigin&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;다음으로는 언어모델에서 많이 사용되는 RNN기반의 모델들 입니다. 바이두의 DeepSpeech2와 구글의 GNMT모델에서 실험하였습니다. 평가를 위해 BLEU지표를 사용하였고 점수가 낮을수록 더 좋은 평가를 의미합니다. 비록 FP32에 비해 약간 점수가 높아진 것을 확인할 수 있지만 심각할 정도는 아닌것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;GAN - DC-GAN&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;812&quot; data-origin-height=&quot;166&quot; width=&quot;494&quot; height=&quot;101&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lpaDB/btrdHfxzp0U/zbTpO7Z47tdniRtdKQT8xk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lpaDB/btrdHfxzp0U/zbTpO7Z47tdniRtdKQT8xk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lpaDB/btrdHfxzp0U/zbTpO7Z47tdniRtdKQT8xk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlpaDB%2FbtrdHfxzp0U%2FzbTpO7Z47tdniRtdKQT8xk%2Fimg.png&quot; data-origin-width=&quot;812&quot; data-origin-height=&quot;166&quot; width=&quot;494&quot; height=&quot;101&quot; data-ke-mobilestyle=&quot;widthOrigin&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 data-ke-size=&quot;size16&quot;&gt;다음으로는 이미지 생성 모델인 DC-GAN입니다. 사용한 평가 지표는 Inception score와 MS-SSIM를 사용하였고, 전자는 작을수록, 후자는 1에 가까울수록 더 좋은 결과를 의미합니다. BF16의 학습 결과가 성능이 약간 저하된것을 확인할 수 있지만 아주 작은 차이인것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;GAN - SR-GAN&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;707&quot; data-origin-height=&quot;419&quot; width=&quot;543&quot; height=&quot;322&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1cKfY/btrdI9XForm/MXVcrY632iICMR7KpnXayk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1cKfY/btrdI9XForm/MXVcrY632iICMR7KpnXayk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1cKfY/btrdI9XForm/MXVcrY632iICMR7KpnXayk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1cKfY%2FbtrdI9XForm%2FMXVcrY632iICMR7KpnXayk%2Fimg.png&quot; data-origin-width=&quot;707&quot; data-origin-height=&quot;419&quot; width=&quot;543&quot; height=&quot;322&quot; data-ke-mobilestyle=&quot;widthOrigin&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;다음으로는 저해상도 이미지를 고해상도로 바꿔주는 SR-GAN 모델입니다. PSNR 지표에서는 FP32가 더 좋은 성능을 보였지만 SSIM 지표에서는 BF16가 오히려 더 좋은 결과를 보이는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Industrial Scale Recommendation System&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;978&quot; data-origin-height=&quot;221&quot; width=&quot;598&quot; height=&quot;135&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bw2nnV/btrdFnQdC1b/u46wUkAA99xuy2kxuU9rv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bw2nnV/btrdFnQdC1b/u46wUkAA99xuy2kxuU9rv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bw2nnV/btrdFnQdC1b/u46wUkAA99xuy2kxuU9rv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbw2nnV%2FbtrdFnQdC1b%2Fu46wUkAA99xuy2kxuU9rv0%2Fimg.png&quot; data-origin-width=&quot;978&quot; data-origin-height=&quot;221&quot; width=&quot;598&quot; height=&quot;135&quot; data-ke-mobilestyle=&quot;widthOrigin&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 data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;마지막으로는 추천시스템입니다. 실험에 사용된 모델은 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Deep &amp;amp; Cross Network, &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DNN recommender system 이고 평가 지표는 log loss입니다. 유저의 ad 클릭수를 예측하고 데이터와 얼마나 다른지를 나타내는 지표입니다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt; 이 log loss가 0.001 손실은 실사용에 못사용될정도로 큰 수치라고 합니다. 이번에에는 round-to-nearest(RND) 방법과 하위 16bit를 단순히 버리는 (TRUNC)에 각가에 대해서 실험을 한 것을 확인할 수 있습니다. 결과를 보면 단순히 0으로 치환하는것 보다 반올림을 한것이 성능이 더 좋다는 것을 확인할 수 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Conculsion&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 논문에서는 BF16을 활용한 딥러닝 학습이 다양한 도메인에서 유효하다는 것을 보였고 INT16, FP16과 다르게 추가적인 scaling 작업도 필요없음을 보였습니다. 요즘 나오는 SOTA모델들을 보면 FP16 mixed precision 기법을 활용한 모델들이 많습니다. 이제 Nvidia gpu도 BF16을 지원하기 시작하였으니 FP16이 아닌 BF16을 활용하여 딥러닝 발전에 이바지 하지 않을까 저는 생각합니다.&lt;/p&gt;</description>
      <category>Study/ML</category>
      <author>DOWN</author>
      <guid isPermaLink="true">https://down-develope.tistory.com/45</guid>
      <comments>https://down-develope.tistory.com/45#entry45comment</comments>
      <pubDate>Mon, 30 Aug 2021 22:16:10 +0900</pubDate>
    </item>
    <item>
      <title>논문 리뷰 DoReFa-Net : CNN 모델에서 weight, activation, gradient의 quantization</title>
      <link>https://down-develope.tistory.com/44</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;DoReFa&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;-Net&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;i&gt;&lt;span style=&quot;color: #7f7f7f;&quot;&gt;TRAINING LOW BITWIDTH CONVOLUTIONAL NEURAL NETWORKS WITH LOW BITWIDTH GRADIENTS&lt;/span&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://arxiv.org/abs/1606.06160&quot;&gt;https://arxiv.org/abs/1606.06160&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1628067689603&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;DoReFa-Net: Training Low Bitwidth Convolutional Neural Networks with Low Bitwidth Gradients&quot; data-og-description=&quot;We propose DoReFa-Net, a method to train convolutional neural networks that have low bitwidth weights and activations using low bitwidth parameter gradients. In particular, during backward pass, parameter gradients are stochastically quantized to low bitwi&quot; data-og-host=&quot;arxiv.org&quot; data-og-source-url=&quot;https://arxiv.org/abs/1606.06160&quot; data-og-url=&quot;https://arxiv.org/abs/1606.06160v3&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bb6Nvq/hyK7rcRxsL/FVG6PMF6ikjGg3fZHMr9yK/img.png?width=1000&amp;amp;height=1000&amp;amp;face=0_0_1000_1000&quot;&gt;&lt;a href=&quot;https://arxiv.org/abs/1606.06160&quot; data-source-url=&quot;https://arxiv.org/abs/1606.06160&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bb6Nvq/hyK7rcRxsL/FVG6PMF6ikjGg3fZHMr9yK/img.png?width=1000&amp;amp;height=1000&amp;amp;face=0_0_1000_1000');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;DoReFa-Net: Training Low Bitwidth Convolutional Neural Networks with Low Bitwidth Gradients&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;We propose DoReFa-Net, a method to train convolutional neural networks that have low bitwidth weights and activations using low bitwidth parameter gradients. In particular, during backward pass, parameter gradients are stochastically quantized to low bitwi&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;arxiv.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;0.&amp;nbsp; Introduction&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dorefa-Net 논문이 발표되기 전 논문(BNN, XNOR-Net)에서는 weight와 activation의 quantization 시도는 있었지만 gradient 까지는 없었습니다. Dorefa-Net은 gradient까지 quantization을 시도하여 foward propagation 뿐만 아니라 back propagration까지 low bitwidth로 효율적인 연산을 할 수 있도록 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. Prior knowledge&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1.1 Bit Convolution Kernel&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;443&quot; height=&quot;99&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;139&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCNIju/btrbgjBIgHI/gDj8vy35qxADrfeYaOdTv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCNIju/btrbgjBIgHI/gDj8vy35qxADrfeYaOdTv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCNIju/btrbgjBIgHI/gDj8vy35qxADrfeYaOdTv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCNIju%2FbtrbgjBIgHI%2FgDj8vy35qxADrfeYaOdTv1%2Fimg.png&quot; width=&quot;443&quot; height=&quot;99&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;139&quot; data-ke-mobilestyle=&quot;widthOrigin&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 data-ke-size=&quot;size16&quot;&gt;weight, activation, gradient를 low bitwidth로 quantize시켜 효율적인 계산을 한다고 하였습니다. 그때 효율적인 계산은 bit convolution kernel을 이용한 방법으로 위와 같습니다. 기존의 CNN모델이라면 32bit의 floating point number 끼리 산술연산을 하겠지만, 위 bit convolution kernel을 사용하면 bitwise operation만으로 dot product을 계산할 수 있습니다. 그래서 Dorefa-Net에서는 최대한 모든 계산을 위 방법을 이용하여 model을 압축하는 것이 목표입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1.2 STRAIGHT-THROUGH ESTIMATOR (STE)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dorefa-Net 에서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #050505;&quot;&gt;Geoffrey Everest Hinton가 제안한&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;STE 기법을 사용합니다. STE 기법이란 back propagration에서 foward propagation에서 사용한 함수의 미분을 사용하지 않고 임의의 다른 값을 사용하는 기법으로 아래의 간단한 예시를 보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;309&quot; height=&quot;109&quot; data-origin-width=&quot;346&quot; data-origin-height=&quot;122&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wJJuz/btra9WgrXNd/aneaVgwwToBZNBAwwE0eRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wJJuz/btra9WgrXNd/aneaVgwwToBZNBAwwE0eRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wJJuz/btra9WgrXNd/aneaVgwwToBZNBAwwE0eRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwJJuz%2Fbtra9WgrXNd%2FaneaVgwwToBZNBAwwE0eRK%2Fimg.png&quot; width=&quot;309&quot; height=&quot;109&quot; data-origin-width=&quot;346&quot; data-origin-height=&quot;122&quot; data-ke-mobilestyle=&quot;widthOrigin&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 data-ke-size=&quot;size16&quot;&gt;만약 위와 같이, Foward에서 베르누이 함수를 사용한다고 가정해보겠습니다. 베르누이 함수는 미분할 수 없으므로 Backward에서 gradient를 계산할 수 없습니다. 그래서 Backward에서 위와 같이 대신 다른 임의의 정해진 도함수를 사용하는 것으로 이와 같이 바꿔도 성능에는 큰 영향을 미치지 않는다고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;431&quot; height=&quot;123&quot; data-origin-width=&quot;494&quot; data-origin-height=&quot;141&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzgEnH/btrbe6W4Z8L/N8StoV9TpUgzS42mJVPIP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzgEnH/btrbe6W4Z8L/N8StoV9TpUgzS42mJVPIP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzgEnH/btrbe6W4Z8L/N8StoV9TpUgzS42mJVPIP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzgEnH%2Fbtrbe6W4Z8L%2FN8StoV9TpUgzS42mJVPIP1%2Fimg.png&quot; width=&quot;431&quot; height=&quot;123&quot; data-origin-width=&quot;494&quot; data-origin-height=&quot;141&quot; data-ke-mobilestyle=&quot;widthOrigin&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 data-ke-size=&quot;size16&quot;&gt;위 Foward 함수는 이번 Dorefa-Net에서 사용할 quantize 함수입니다. [0,1]의 floating point input ri를 입력받고 k-bit인 ro를 output으로 내놓습니다. Backward를 보면 Foward의 도함수가 아닌 다른 임의의 도함수가 있는 것을 확인할 수 있는데 이는 STE를 적용한 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. Quantization&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2.1 Weight&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;313&quot; height=&quot;104&quot; data-origin-width=&quot;409&quot; data-origin-height=&quot;136&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5qeJN/btrbe4Zguxn/VhzFDVw52EOKWcEKgpGkd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5qeJN/btrbe4Zguxn/VhzFDVw52EOKWcEKgpGkd1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5qeJN/btrbe4Zguxn/VhzFDVw52EOKWcEKgpGkd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5qeJN%2Fbtrbe4Zguxn%2FVhzFDVw52EOKWcEKgpGkd1%2Fimg.png&quot; width=&quot;313&quot; height=&quot;104&quot; data-origin-width=&quot;409&quot; data-origin-height=&quot;136&quot; data-ke-mobilestyle=&quot;widthOrigin&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 data-ke-size=&quot;size16&quot;&gt;Dorefa-Net에서는 Weight를 quantize 할 때 2가지 방법으로 나뉩니다. 첫 번째는 output이 1bit 일 때이고, 두 번째는 1bit 보다 큰 bit로 quantize 시킬 때입니다. 첫 번째 quantization같은 경우는 위 식과 같습니다. weight를 signal function으로 binarize 시킨 다음에 E(|ri|)를 곱해줍니다. E(|ri|) 은 전체 weight의 기댓값으로 scaling factor라고 부릅니다. 이 scaling factor를 곱해줌으로써 weight의 표현 범위를 늘릴 수 있는데 여전히 bit convolution kernel 으로 계산할 수 있는 이점을 얻습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;574&quot; height=&quot;111&quot; data-origin-width=&quot;776&quot; data-origin-height=&quot;150&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nnED9/btra6IJGbeJ/rRks99zbw2Ay8I4O6zdjx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nnED9/btra6IJGbeJ/rRks99zbw2Ay8I4O6zdjx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nnED9/btra6IJGbeJ/rRks99zbw2Ay8I4O6zdjx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnnED9%2Fbtra6IJGbeJ%2FrRks99zbw2Ay8I4O6zdjx1%2Fimg.png&quot; width=&quot;574&quot; height=&quot;111&quot; data-origin-width=&quot;776&quot; data-origin-height=&quot;150&quot; data-ke-mobilestyle=&quot;widthOrigin&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 data-ke-size=&quot;size16&quot;&gt;1bit 보다 큰 k-bit로 quantize 시킬때는 위와 같습니다. tanh 함수를 이용하여 quantize 함수의 input의 범위를 [0,1]로 만들었고 output의 범위를 [-1,1]로 만들기 위해 2를 곱하고 1를 빼준것을 확인할 수 있습니다. 또한 Backward에서 dro/dri는 quantize 함수로 부터 쉽게 구할수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2.2 Activation&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;261&quot; data-origin-height=&quot;52&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/czlhqN/btra9WtWpOf/Al9JxlxKDJySCOnhuGW4DK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/czlhqN/btra9WtWpOf/Al9JxlxKDJySCOnhuGW4DK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/czlhqN/btra9WtWpOf/Al9JxlxKDJySCOnhuGW4DK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FczlhqN%2Fbtra9WtWpOf%2FAl9JxlxKDJySCOnhuGW4DK%2Fimg.png&quot; data-origin-width=&quot;261&quot; data-origin-height=&quot;52&quot; data-ke-mobilestyle=&quot;widthOrigin&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 data-ke-size=&quot;size16&quot;&gt;Dorefa-Net 이전 논문들(BNN, XNOR-Net)에서는 activation된 값을 quantize 할 때도 weight를 binarized할 때와 같은 방법을 사용했다고 합니다. 하지만 Dorefa-Net에서도 그렇게 했을 때, 심각한 성능저하 문제가 생겼고 그래서 위와 같이 quantize 함수를 직접 이용하여 low bit로 바꿔줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2.3 Gradient&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;591&quot; height=&quot;76&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;105&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FZzxG/btrbe5RqdC6/mnAWlT1SUhcAi9ywdtejoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FZzxG/btrbe5RqdC6/mnAWlT1SUhcAi9ywdtejoK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FZzxG/btrbe5RqdC6/mnAWlT1SUhcAi9ywdtejoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFZzxG%2Fbtrbe5RqdC6%2FmnAWlT1SUhcAi9ywdtejoK%2Fimg.png&quot; width=&quot;591&quot; height=&quot;76&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;105&quot; data-ke-mobilestyle=&quot;widthOrigin&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;figure class=&quot;imageblock alignCenter&quot; width=&quot;276&quot; height=&quot;110&quot; data-origin-width=&quot;349&quot; data-origin-height=&quot;139&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r7K9R/btra8zTio45/qT7v2k1Ubb9MifaqDVFqn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r7K9R/btra8zTio45/qT7v2k1Ubb9MifaqDVFqn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r7K9R/btra8zTio45/qT7v2k1Ubb9MifaqDVFqn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr7K9R%2Fbtra8zTio45%2FqT7v2k1Ubb9MifaqDVFqn1%2Fimg.png&quot; width=&quot;276&quot; height=&quot;110&quot; data-origin-width=&quot;349&quot; data-origin-height=&quot;139&quot; data-ke-mobilestyle=&quot;widthOrigin&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 data-ke-size=&quot;size16&quot;&gt;Gradient의 quantization 같은 경우 앞에서 나온 2가지 방식하고는 다른 점이 있습니다. 첫 번째 다른 점은 gradient의 quantization 값이 unbound 하여 더 많은 범위의 값을 표현할 수 있다는 점이고, 두 번째 다른 점은 deterministic 한 방법이 아니라 stochastically 한 방법이라는 것입니다. 이를 위해 quantize 함수의 output에 2max(|dr|)을 곱하고 noise function인 N(k)를 사용한 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2.4 Algorithm&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;555&quot; height=&quot;492&quot; data-origin-width=&quot;794&quot; data-origin-height=&quot;704&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cO9T50/btra9WU110i/B5BTWeKEXVqVI5NcvKJJs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cO9T50/btra9WU110i/B5BTWeKEXVqVI5NcvKJJs1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cO9T50/btra9WU110i/B5BTWeKEXVqVI5NcvKJJs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcO9T50%2Fbtra9WU110i%2FB5BTWeKEXVqVI5NcvKJJs1%2Fimg.png&quot; width=&quot;555&quot; height=&quot;492&quot; data-origin-width=&quot;794&quot; data-origin-height=&quot;704&quot; data-ke-mobilestyle=&quot;widthOrigin&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;&lt;b&gt;3. Result&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;819&quot; height=&quot;379&quot; data-origin-width=&quot;1457&quot; data-origin-height=&quot;674&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/775se/btrbgoXt6dK/oyhlJ6XrUtTrKb1CivU9g1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/775se/btrbgoXt6dK/oyhlJ6XrUtTrKb1CivU9g1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/775se/btrbgoXt6dK/oyhlJ6XrUtTrKb1CivU9g1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F775se%2FbtrbgoXt6dK%2FoyhlJ6XrUtTrKb1CivU9g1%2Fimg.png&quot; width=&quot;819&quot; height=&quot;379&quot; data-origin-width=&quot;1457&quot; data-origin-height=&quot;674&quot; data-ke-mobilestyle=&quot;widthOrigin&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 data-ke-size=&quot;size16&quot;&gt;왼쪽은 SVHN dataset, 오른쪽은 ImageNet dataset에 대한 결과입니다. 전체적으로 gradient의 bit가 낮아지면 가장 성능저하게 심하게 일어나는 것을 확인할 수 있습니다. 저자는 W,A,G의 각 bit수가 1,2,6 일 때 가장 성능이 좋다고 판단하였고 이를 음계와 합쳐 도레파로 논문 이름을 지었다고 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4. Concolusion&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 1241번 인용한 논문으로 quantization을 폭 넓게 다루고 전체적인 개념을 잡기에 좋은 논문이라고 생각합니다. 그러나 저는 아무래도 4-bit 이하로 quantization을 하는것은 데이터 손실이 크다고 생각하여 8-bit 이상으로 quantization하는 논문을 찾아볼 예정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/ML</category>
      <author>DOWN</author>
      <guid isPermaLink="true">https://down-develope.tistory.com/44</guid>
      <comments>https://down-develope.tistory.com/44#entry44comment</comments>
      <pubDate>Wed, 4 Aug 2021 17:59:26 +0900</pubDate>
    </item>
    <item>
      <title>[Design Pattern] Template Method Pattern 템플릿 메소드 패턴</title>
      <link>https://down-develope.tistory.com/43</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;662&quot; width=&quot;138&quot; height=&quot;78&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdr43o/btraWv3lIao/HmRVZWiTt25T3LTVzp9Fj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdr43o/btraWv3lIao/HmRVZWiTt25T3LTVzp9Fj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdr43o/btraWv3lIao/HmRVZWiTt25T3LTVzp9Fj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcdr43o%2FbtraWv3lIao%2FHmRVZWiTt25T3LTVzp9Fj1%2Fimg.png&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;662&quot; width=&quot;138&quot; height=&quot;78&quot; data-ke-mobilestyle=&quot;widthOrigin&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 data-ke-size=&quot;size16&quot;&gt;템플릿 메소드 패턴이란 비지니스 로직은 세부 구현으로 부터 분리하는 디자인 패턴으로 GOF에 따르면 다음과 같다. 즉 간단하게 말하자면 여러 클래스에서 공통된 행위를 상위 클래스에서 정의하고, 하위 클래스에서 각각의 상세부분을 구현하는 것을 말한다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;알고리즘의 구조를 메소드에 정의하고, 하위 클래스에서 알고리즘 구조의 변경없이 알고리즘을 재정의 하는 패턴이다. 알고리즘이 단계별로 나누어 지거나, 같은 역할을 하는 메소드이지만 여러곳에서 다른형태로 사용이 필요한 경우 유용한 패턴이다. &lt;span style=&quot;color: #c6c6c6;&quot;&gt;&amp;ndash; GoF Design Patterns&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 다음과 같이 Gun이라는 추상클래스가 존재하고 shoot이라는 메소드를 가진다고 가정하자. shoot은 3가지 단계로 이루어진것을 확인할 수 있다. 하지만 각 단계의 구현은 총의 종류에 따라 달라질 수 있으므로 구현은 하위클래스에서 오버라이드하여 완성하는것이다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1627734188571&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public abstract class Gun{
	
    public shoot(){
    	bullet();
        load();
        trigger();
    }
    
    abstract bullet();
    abstract load();
    abstract trigger();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 아래처럼 K2 클래스가 Gun 추상클래스를 상속하여 메소드들을 직접 구현하는 것이다. 그래서 클라이언트에서 shoot 메소드를 사용하면 구현클래스에 따라 다르게 실행 되는것을 확인할 수 있을것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1627734456626&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class K2 extends Gun{
	
    @Override
    public void bullet(){
    	System.out.println(&quot;5.56mm 10발 준비!&quot;);
    }
    
    @public void load(){
    	System.out.println(&quot;노리쇠 전진!&quot;);
    }
    
    @public void trigger(){
    	System.out.println(&quot;빵야 !~&quot;);
    }
    
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1627734501006&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class TemplateMethodPattern {
    public static void main(String[] args) {
        Gun k2 = new K2();
        k2.shoot();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;얼핏 보면 템플릿 메소드 패턴은 전략 패턴과 매우 유사하다는 것을 느낄수 있다. 차이점으로는 전략 패턴은 인터페이스를 활용하여 알고리즘의 동작을 다르게 하고, 동일 이름의 메소드 중에서 상황에 맞게 필요한 전략를 선택하여 사용하는 패턴이다. 템플릿 메소드 패턴은 상속을 이용하여 알고리즘 동작을 직접 구현하고, 공통된 메소드를 구현하는데 중점을 둔다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;템플릿 메소드 패턴의 장점으로는 비슷한 기능을 하는 코드의 중복을 피할 수 있다. 또 추상 클래스라는 틀이 있기때문에 하위 클래스에서 쉽게 생성 및 추가를 할 수 있는, 즉 간편한 확장성을 보장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단점으로는 만약 관리하는 하위 클래스가 많아지면, 상위 클래스를 수정해야 할 일이 생기면 하위 클래스를 일일이 다 수정해야하는 상황이 발생할 수 있다. 또한 하위클래스가 구현해야 하는 추상 메소드가 너무 많으면 관리가 힘들어 질 수 있다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;dicLayer&quot; style=&quot;color: #000000; font-size: 12px; font-family: Arial; background: -webkit-linear-gradient(bottom, #ffeb00, #ffdc00); width: 400px; height: 150px; display: none;&quot;&gt;
&lt;div id=&quot;dicLayerContents&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;dicLayerSub&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;dicRawData&quot; style=&quot;display: none;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;dicLayerLoader&quot;&gt;&amp;nbsp;&lt;/div&gt;</description>
      <category>Study/Design Pattern</category>
      <author>DOWN</author>
      <guid isPermaLink="true">https://down-develope.tistory.com/43</guid>
      <comments>https://down-develope.tistory.com/43#entry43comment</comments>
      <pubDate>Sat, 31 Jul 2021 21:39:50 +0900</pubDate>
    </item>
    <item>
      <title>[Design Pattern] Observer Pattern  옵저버 패턴</title>
      <link>https://down-develope.tistory.com/42</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;141&quot; height=&quot;80&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;662&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVhtu7/btraGPuAinQ/uS648my5Jrnfs76kP1szA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVhtu7/btraGPuAinQ/uS648my5Jrnfs76kP1szA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVhtu7/btraGPuAinQ/uS648my5Jrnfs76kP1szA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVhtu7%2FbtraGPuAinQ%2FuS648my5Jrnfs76kP1szA1%2Fimg.png&quot; width=&quot;141&quot; height=&quot;80&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;662&quot; data-ke-mobilestyle=&quot;widthOrigin&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 객체를 구현하면 객체끼리 의존 관계를 가지기도 합니다. 예를 들어 '오늘의 메뉴'라는 객체가 있고 학생들 객체가 있으면, 오늘의 메뉴 객체의 내용에 따라 학생들이 먹는 음식 또한 달라질 것입니다. 이처럼 의존성을 가지는 다른 객체들에게 변경 상황을 알릴 필요가 있는데 이때 사용되는 디자인 패턴이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;u&gt;옵저버 패턴&lt;/u&gt;&lt;/b&gt;입니다. 옵저버 패턴은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #503e2b;&quot;&gt;객체 사이에 일 대 다의 의존 관계를 정의해 두어, 어떤 객체의 상태가 변할 때 그 객체에 의존성을 가진 다른 객체들이 그 변화를 통지받고 자동으로 갱신될 수 있게 만듭니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1628347625644&quot; class=&quot;java&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class TodayMenu {
    public String meal;
    public String soup;
    public String sideDish1;
    public String sideDish2;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1628347625644&quot; class=&quot;java&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public abstract Student{
    public void eat();
    public String allergy;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 오늘의 메뉴를 저장하는 class와 Student 추상클래스가 존재하는 상황을 가정해보겠습니다. 학생 구성원은 Student 를 상속받아 구현될 것이고 eat 추상메소드도 구현할 것입니다. 그런데 만약 특정 음식에 알레르기가 있는 학생은 오늘의 메뉴에 해당 메뉴가 있다면 밥을 못 먹을것입니다. 이처럼 Student의 구현 클래스들은&amp;nbsp; TodayMenu 클래스에 의존성을 가질 것이고 TodayMenu 메뉴의 변경에 따라 eat 메소드의 실행도 바뀌어야 할 것입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1628347625645&quot; class=&quot;java&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&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(String meal, String soup, String sideDish1, String sideDish2);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 위와 같이 구독의 대상이 될 Subject 인터페이스와 구독을 받을 Observer 인터페이스를 생성해주어 Subject의 변화를 Observer 객체들에게 알릴수 있도록 해줄 수 있습니다. 위 인터페이스로 직접 구현을 해보면 아래와 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1628347625645&quot; class=&quot;java&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class TodayMenu implements Subject{
    private String meal;
    private String soup;
    private String sideDish1;
    private String sideDish2;
    private List&amp;lt;Observer&amp;gt; observers;
    
    public void setTodayMenu(String meal, String, soup, String s1, String s2){
    	this.meal = meal;
        this.soup = soup;
        this.sideDish1 = s1;
        this.sideDish2 = s2;
    }
    
    @Override
    public void registerObserver(Observer o){
    	observers.add(o);
    }
    
    @Override
    public void removeObserver(Observer o){
    	observers.remove(o);
    }
    
    @Override
    public void notifyObservers(){
    	for (Observer observer : observers) {
             observer.update(meal, soup, sideDish1, sideDish2);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1628347625646&quot; class=&quot;java&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class CheolSu extends Student implements Observer{
	
    private bool canEat;
    
	public setAllergy(String allergy){
    	this.allergy = allergy;
    }
    
    @Override
    public void eat(){
    	if(catEat){
        	System.out.println(&quot;냠냠냠냠냠&quot;);
        }
        else{
        	System.out.println(&quot;알러지때문에 오늘은 굶는다.&quot;);
        }
    }
    
    @Override
    public void update(String meal, String soup, String sideDish1, String sideDish2) {
        canEat = true;
        if(allergy.equals(meal)){
        	canEat = false;
        }
        if(allergy.equals(soup)){
        	canEat = false;
        }
        if(allergy.equals(sideDish1)){
        	canEat = false;
        }
        if(allergy.equals(sideDish2)){
        	canEat = false;
        }
	}

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TodayMenu 클래스는 멤버 변수로 옵저버 리스트를 두어 현재 구독하고있는 옵저버 객체들을 관리하고, 만약 클래스에 변경이 생기면 notifyObservers 메소드를 통해 알리는 것을 확인할 수 있습니다. 옵저버의 객체인 Cheolsu는 update 메소드를 통해 Subject의 변화를 받아오고 변화에 따라 멤버 변수인 canEat를 변경함으로써 eat 메소드의 동작을 제어합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 옵저버 패턴을 통해 실시간으로 한 객체의 변경사항을 다른 객체에 전파할 수 있으며,&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;/span&gt;느슨한 결합으로 시스템이 유연하고 객체 간의 의존성을 제거할 수 있습니다. (느슨한 결합이란 어느 두 객체가 서로 상호작용을 해도, 서로의 구현에 대해 구체적으로 모르는 것을 뜻합니다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 너무 많이 과하게 사용하면, 상태 관리가 힘들 수 있고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;데이터 배분에 문제 등 새로운 문제를 야기할 수 있으므로 주의 깊게 사용해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;dicLayer&quot; style=&quot;display: none;&quot;&gt;
&lt;div id=&quot;dicLayerContents&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;dicLayerSub&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;dicRawData&quot; style=&quot;display: none;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;dicLayerLoader&quot;&gt;&amp;nbsp;&lt;/div&gt;</description>
      <category>Study/Design Pattern</category>
      <author>DOWN</author>
      <guid isPermaLink="true">https://down-develope.tistory.com/42</guid>
      <comments>https://down-develope.tistory.com/42#entry42comment</comments>
      <pubDate>Wed, 28 Jul 2021 19:10:38 +0900</pubDate>
    </item>
    <item>
      <title>[Design Pattern] Builder Pattern 빌더 패턴</title>
      <link>https://down-develope.tistory.com/41</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;145&quot; height=&quot;82&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;662&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/N09GB/btraawJDMwh/G8Kx1UcnkEkz2FpP3OXnI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/N09GB/btraawJDMwh/G8Kx1UcnkEkz2FpP3OXnI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/N09GB/btraawJDMwh/G8Kx1UcnkEkz2FpP3OXnI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FN09GB%2FbtraawJDMwh%2FG8Kx1UcnkEkz2FpP3OXnI0%2Fimg.png&quot; width=&quot;145&quot; height=&quot;82&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;662&quot; data-ke-mobilestyle=&quot;widthOrigin&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1628347650746&quot; class=&quot;java&quot; style=&quot;display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Person{

    private final String name;
    private final int age;
    private final String country;
    private final String gender;
    
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌더 패턴은 객체를 생성하는 패턴으로 팩토리 패턴과는 또 다른 디자인 패턴입니다. 만약 위와 같은 Person이라는 클래스를 가정해보겠습니다. 만약 이 클래스를 생성자로 직접 생성한다면 다음과 같은 문제점이 발생할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 클라이언트에서 생성자로 파라미터를 넘겨줄 때, 파라미터 수가 많으면 타입, 순서 관리가 어려워지고 가독성이 떨어집니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 Person의 멤버 변수가 위와 같이 4개가 아닌 10개, 20개처럼 많으면 아래 코드처럼 생성자의 파라미터 부분이 길어 질 테고 가독성이 떨어집니다. 그리고 만약 추후에 새로운 멤버 변수가 추가되면 기존 코드를 모두 변경해 줘야 하는 번거로운 점이 발생합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1628347650749&quot; class=&quot;java&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Person person = new Person(&quot;오태식&quot;, 14, &quot;한국&quot;, &quot;남자&quot;, &quot;빌더대학교&quot;, &quot;180&quot;, &quot;43&quot;,......);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 필요 없는 멤버변수에 따라 생성자에 일일이 null 값을 건네줘야 합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 Person 클래스에서 country와 gender 정보가 필요 없으면 아래처럼 일일이 null 값을 입력해 줘야 합니다. 그럼 그냥 빈 클래스를 생성하고 setter함수를 통해 각 멤버변수값을 지정해 주면 되면 아닌가라고 생각하실 수 있는데 setter 메소드를 사용한다는 자체가 불필요한 수정과 확장을 열어두는 거기 때문에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Open-Closed 원칙에 위반되기 때문에 좋은 방법이 아닙니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1628347650752&quot; class=&quot;java&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Person person = new Person(&quot;오태식&quot;, 42, null, null);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #424242;&quot;&gt;3. 속성값이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;많아질수록&lt;span style=&quot;color: #424242;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;팩토리 클래스가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;생성해야 할&lt;span style=&quot;color: #424242;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;서브 클래스도 복잡해지고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;무거워질 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1628347650755&quot; class=&quot;java&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Person{

    private final String name;
    private final int age;
    private final String country;
    private final String gender;
    
    
    public static class Builder{
    	private String name;
        private int age;
        private String country;
        private String gender;
        
        public Builder(){}
        
        public Builder name(String name){
        	this.name = name;
            return this;
        }
        
        public Builder age(int age){
        	this.age = age;
            return age;
        }
        
        public Builder country(String country){
        	this.country = country;
            return this;
        }
        
        public Builder gender(String gender){
        	this.gender = gender;
            return age;
        }
        
        public Person build(){
        	return new Person(this);
        }
    }
    
    private Person(Builder builder){
    	name = builder.name;
    	age = builder.age;
    	country = builder.country;
    	gender = builder.gender;
    }
    
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1628347650755&quot; class=&quot;java&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 클라이언트

Person person = new Person.Builder
	.name(&quot;오태식&quot;)
    .age(14)
    .country(&quot;한국&quot;)
    .gender(&quot;남자&quot;)
    .build();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 위와 같이 Builder 클래스를 구현하여 사용하면 setter 메소드를 구현하지 않아도 원하는 속성값만 넘겨줄 수 있고 객체를 원할 때 생성할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;dicLayer&quot; style=&quot;display: none;&quot;&gt;
&lt;div id=&quot;dicLayerContents&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;dicLayerSub&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;dicRawData&quot; style=&quot;display: none;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;dicLayerLoader&quot;&gt;&amp;nbsp;&lt;/div&gt;</description>
      <category>Study/Design Pattern</category>
      <author>DOWN</author>
      <guid isPermaLink="true">https://down-develope.tistory.com/41</guid>
      <comments>https://down-develope.tistory.com/41#entry41comment</comments>
      <pubDate>Thu, 22 Jul 2021 01:23:03 +0900</pubDate>
    </item>
    <item>
      <title>[Design Pattern] Strategy Pattern 전략 패턴</title>
      <link>https://down-develope.tistory.com/40</link>
      <description>&lt;div id=&quot;dicLayer&quot; style=&quot;color: #000000; font-size: 12px; font-family: Arial; background: -webkit-linear-gradient(bottom, #ffeb00, #ffdc00); width: 400px; height: 150px; left: 158px; top: 3757px; display: none;&quot;&gt;
&lt;div id=&quot;dicLayerContents&quot;&gt;client [ˈklaɪənt] &lt;input id=&quot;ee&quot; type=&quot;checkbox&quot; /&gt;Eng&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1.client&lt;br /&gt;&lt;br /&gt;[명사] (전문가의 서비스를 받는) 의뢰인[고객]&lt;br /&gt;&lt;br /&gt;2.Client&lt;br /&gt;&lt;br /&gt;(호텔) 고객을 말한다.&lt;br /&gt;&lt;br /&gt;3.client state&lt;br /&gt;&lt;br /&gt;[명사] 의존국(더 큰 강대국의 지원과 보호에 기대는 나라)&lt;br /&gt;&lt;br /&gt;4.client-server&lt;br /&gt;&lt;br /&gt;[형용사] (명사 앞에만 씀) (컴퓨터) 컴퓨터 시스템이 클라이언트 서버형인(중앙의 서버로 연결된 여러 대의 컴퓨터가 데이터를 공유하는 시스템인) 참조 peer-to-peer&lt;br /&gt;&lt;br /&gt;5.mail client&lt;br /&gt;&lt;br /&gt;(컴퓨터) 이메일 고객 ((이메일 송수신 서비스를 받는 컴퓨터))&lt;br /&gt;&lt;br /&gt;6.고객 顧客&lt;br /&gt;&lt;br /&gt;(상점 등의) customer; (호텔 등의) guest; (단골 ) (formal) patron; (변호사&amp;middot;은행 등의) client; (집합적) clientele&lt;br /&gt;&lt;br /&gt;7.의뢰인 依賴人&lt;br /&gt;&lt;br /&gt;client&lt;br /&gt;&lt;br /&gt;8.위임인&lt;br /&gt;&lt;br /&gt;(지식재산권_법률) client&lt;br /&gt;&lt;br /&gt;9.의뢰자 依賴者&lt;br /&gt;&lt;br /&gt;(법률) client&lt;br /&gt;&lt;br /&gt;10.촉탁인 囑託人&lt;br /&gt;&lt;br /&gt;(법률) client; person who entrusts/comissions&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div id=&quot;dicLayerSub&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;dicRawData&quot; style=&quot;display: none;&quot;&gt;{&quot;mean&quot;:[&quot;client&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;[명사]\n\t\t \t\t(전문가의 서비스를 받는) 의뢰인[고객]&quot;,&quot;Client&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;(호텔)\n\t\t \t\t고객을 말한다.&quot;,&quot;client state&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;[명사]\n\t\t \t\t의존국(더 큰 강대국의 지원과 보호에 기대는 나라)&quot;,&quot;client-server&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;[형용사]\n\t\t \t(명사 앞에만 씀)\n\t\t (컴퓨터)\n\t\t 컴퓨터 시스템이\n\t\t \t\t클라이언트 서버형인(중앙의 서버로 연결된 여러 대의 컴퓨터가 데이터를 공유하는 시스템인)\n\n\t\t 참조 peer-to-peer&quot;,&quot;mail client&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;(컴퓨터)\n\t\t \t\t이메일 고객 ((이메일 송수신 서비스를 받는 컴퓨터))&quot;,&quot;고객\n \t\t\t顧客&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;(상점 등의) customer; (호텔 등의) guest; (단골 ) (formal) patron; (변호사&amp;middot;은행 등의) client; (집합적) clientele&quot;,&quot;의뢰인\n \t\t\t依賴人&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;client&quot;,&quot;위임인&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;(지식재산권_법률)\n\t\t \t\tclient&quot;,&quot;의뢰자\n \t\t\t依賴者&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;(법률)\n\t\t \t\tclient&quot;,&quot;촉탁인\n \t\t\t囑託人&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;(법률)\n\t\t \t\tclient; person who entrusts/comissions&quot;],&quot;word&quot;:&quot;\n\t\t\t\t\t\tclient\n \t\t\t\n\t \t\n\t &quot;,&quot;soundUrl&quot;:&quot;https://dict-dn.pstatic.net/v?_lsu_sa_=38e838555d5c3236f697b16b3d148bfbddc665652c075f4b6862ea74fb016ec1975037a06e655572f9c767250920f0a7949640aa817b509fbacd2cc79a9f6dfb68c26c4c444e16b929fbb643cfabc74ed69363bcaaaf99666eb404190e88c36d0df3cf734ecb5d57872894e157fa85dbd55248124c47220022ff73cc229708f4&quot;,&quot;phoneticSymbol&quot;:&quot;[ˈklaɪənt]&quot;}&lt;/div&gt;
&lt;div id=&quot;dicLayerLoader&quot; class=&quot;&quot; style=&quot;top: 3737px; left: 158px;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;662&quot; width=&quot;138&quot; height=&quot;78&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3wCoI/btq9TfAh1DK/v2zF9oS8YkoMvUTZUFklc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3wCoI/btq9TfAh1DK/v2zF9oS8YkoMvUTZUFklc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3wCoI/btq9TfAh1DK/v2zF9oS8YkoMvUTZUFklc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3wCoI%2Fbtq9TfAh1DK%2Fv2zF9oS8YkoMvUTZUFklc1%2Fimg.png&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;662&quot; width=&quot;138&quot; height=&quot;78&quot; data-ke-mobilestyle=&quot;widthOrigin&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 style=&quot;position: absolute;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;전&lt;u&gt;&lt;b&gt;략 패턴&lt;/b&gt;&lt;/u&gt;이란 같은 기능을 하는 알고리즘들을 캡슐화하여 서로 간 상호 교체가 가능하도록 하게 하는 디자인 패턴입니다. 이를 통해 새로운 알고리즘이 추가되어도 기존의 코드를 수정할 필요 없이 쉽게 추가가 가능해집니다. 이는 SOLID 원칙에서 수정, 삭제에는 닫혀있고 추가에는 개방되어야 하는 개&lt;span style=&quot;color: #222222;&quot;&gt;방-폐쇄 원칙(OCP)을 만족합니다.&lt;/span&gt;&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1626600009871&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//Champion 클래스
 public abstract class Champion
 {
   private String name;
   public Champion(String name)
   {
     this.Champion = Champion;
   }
   public String getName()
   {
     return name;
   }
   public abstract void attack();
 }&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1626600088443&quot; class=&quot;java&quot; style=&quot;display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//티모 클래스
 public class 티모 extends Champion
 {
   public 티모(String name) 
   {
     super(name);
   }
   public void attack()
   {
     System.out.println(&quot;독침 공격!&quot;);
   }
 }&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1626600124253&quot; class=&quot;java&quot; style=&quot;display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//피즈 클래스
 public class 피즈 extends Champion
 {
   public 피즈(String name) 
   {
     super(name);
   }
   public void attack()
   {
     System.out.println(&quot;창 공격!&quot;);
   }
 }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #222222;&quot;&gt;위와 같이 챔피언 추상 클래스가 있고, 이를 확장하는 티모, 피즈 구현 클래스가 있다고 가정해보겠습니다. attack()이라는 공통된 메소드가 있는데 만약 티모의 공격 방법이 바뀌면 어떻게 해야 할까요? 만약 티모 클래스에서 코드를 직접 수정하면 OCP 원칙에 위배되게 됩니다. 그래서 아래와 같이 전략 패턴을 이용해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1626600357665&quot; class=&quot;java&quot; style=&quot;display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//Champion 클래스
 public abstract class Champion
 {
   private String name;
   private AttackStrategy attackstrategy;
   
   public Champion(String name)
   {
     this.Champion = Champion;
   }
   public String getName()
   {
     return name;
   }
   public void setAttackStrategy(AttackStrategy attackstrategy)
   {
     this.AttackStrategy = attackstrategy;
   }
   public abstract void attack(){
   	 attackstrategy.attack();
   }
 }&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1626600374717&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//티모 클래스
 public class 티모 extends Champion
 {
   public 티모(String name) 
   {
     super(name);
   }
 }&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1626600385285&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//피즈 클래스
 public class 피즈 extends Champion
 {
   public 피즈(String name) 
   {
     super(name);
   }
 }&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1626600418976&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//AttackStrategy 인터페이스
 interface AttackStrategy
 {
   public void attack();
 }&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1626600508283&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//Posion 클래스
 public class Posion implements AttackStrategy
 {
   public void attack()
   {
     System.out.println(&quot;독침 공격&quot;);
   }
 }&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1626600524295&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//Spear 클래스
 public class Spear implements AttackStrategy
 {
   public void attack()
   {
     System.out.println(&quot;창 공격&quot;);
   }
 }&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1626600549967&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//Rifle 클래스
 public class Rifle implements AttackStrategy
 {
   public void attack()
   {
     System.out.println(&quot;라이플 공격&quot;);
   }
 }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 챔피언의 attack 메소드를 하위 클래스에서 직접 구현하는것이 아닌 AttackStrategy라는 인터페이스로 추상화 하여 따로 구현하게 됩니다. 그래서 챔피언 객체의 attack 메소드를 사용하기전 AttackStrategy 객체를 주입해주어 attack 전략을 아래와 같이 클라이언트에서 고를수 있게해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1626600926210&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; public class Client
 {
   public static void main(String[] args)
   {
     Champion teemo = 티모(&quot;티모&quot;);
     Champion fizz = 피즈(&quot;피즈&quot;);
     
     teemo.setAttackStrategy(new PosionStrategy());
     fizz.setAttackStrategy(new SpearStrategy());
     
     System.out.println(teemo.getName());
     teemo.attack();
     
     System.out.println(fizz.getName());
     fizz.attack();
     
     teemo.setAttackStrategy(new RifleStrategy());
     System.out.println(teemo.getName());
     teemo.attack();
   }
 }
 
 // Output
 티모
 독침 공격
 
 피즈
 창 공격
 
 티모
 라이플 공격&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&quot;dicLayer&quot;&gt;
&lt;div id=&quot;dicLayerContents&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;dicLayerSub&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;dicRawData&quot; style=&quot;display: none;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;dicLayerLoader&quot;&gt;&amp;nbsp;&lt;/div&gt;</description>
      <category>Study/Design Pattern</category>
      <author>DOWN</author>
      <guid isPermaLink="true">https://down-develope.tistory.com/40</guid>
      <comments>https://down-develope.tistory.com/40#entry40comment</comments>
      <pubDate>Sun, 18 Jul 2021 18:36:51 +0900</pubDate>
    </item>
    <item>
      <title>[Design Pattern] Adapter Pattern 어댑터 패턴</title>
      <link>https://down-develope.tistory.com/39</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;662&quot; width=&quot;146&quot; height=&quot;83&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GcDM4/btq9MFgta5I/HfLlZ4K139GhezsYtRYOo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GcDM4/btq9MFgta5I/HfLlZ4K139GhezsYtRYOo1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GcDM4/btq9MFgta5I/HfLlZ4K139GhezsYtRYOo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGcDM4%2Fbtq9MFgta5I%2FHfLlZ4K139GhezsYtRYOo1%2Fimg.png&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;662&quot; width=&quot;146&quot; height=&quot;83&quot; data-ke-mobilestyle=&quot;widthOrigin&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어댑터 패턴이란 어떤 인터페이스를 상속받는 클래스를 다른 인터페이스로 변환하여 사용하고자 할 때 사용되는 디자인 패턴이다. 이를 통해 관계가 없는 인터페이스들을 같이 사용 가능하고, 클래스의 재활용성이 증가하는 장점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1626537185613&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Human 인터페이스
public interface Human{
	public void talk();
    public void walk();
}


// 구현 class
public class Asian implements Human{
	@Override
    public void talk(){
    	System.out.println(&quot;I am an Asian&quot;);
    }
    public void walk(){
    	System.out.println(&quot;Asian walks&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1626537300597&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Dog 인터페이스
public interface Dog{
	public void bark();
    public void walk();
}


// 구현 class
public class Poodle implements Dog{
	@Override
    public void bark(){
    	System.out.println(&quot;wak wak!&quot;);
    }
    public void walk(){
    	System.out.println(&quot;Poodle walks&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 Human, Dog 인터페이스를 각각 상속받는 Asian, Poodle 클래스가 존재한다고 생각해 봅시다. 그런데 만약 개를 사람처럼 다뤄야 하는 상황이라서 Dog 대신 Human 객체를 사용해야 하는 상황이라면, 인터페이스가 서로 다르기 때문에 바로는 사용을 불가능합니다. 그래서 아래와 같이 어댑터 클래스를 구현해 줄 필요가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1626537829036&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class DogAdapter implements Human{
	private Dog dog;
    
    public DogAdapter(Dog dog){
    	this.dog = dog;
    }
    
    @Override
    public void talk(){
    	dog.bark();
    }
    
    @Override
    public void walk(){
    	dog.walk();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1626538241269&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Dog poodle = new Poodle();
poodle.bark();  // wak wak!

Human poodleAdapter = new DogAdapter(poodle);
poodleAdapter.talk(); // wak wak!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드처럼 기존 dog 클래스 코드를 전혀 수정하지 않아도 타겟 인터페이스(Human)에 맞춰서 동작하는 것을 확인할 수 있다. 이를 통해 만약 프로젝트 중간부터 새로운 신 클래스를 사용한다 하더라도 기존 구식 클래스 객체들을 Adapter를 통해 신식으로 작동하게 할 수 있는 등 다양하게 활용할 수 있다.&lt;/p&gt;</description>
      <category>Study/Design Pattern</category>
      <author>DOWN</author>
      <guid isPermaLink="true">https://down-develope.tistory.com/39</guid>
      <comments>https://down-develope.tistory.com/39#entry39comment</comments>
      <pubDate>Sun, 18 Jul 2021 01:15:42 +0900</pubDate>
    </item>
    <item>
      <title>[Design Pattern] Factory Pattern 팩토리 패턴</title>
      <link>https://down-develope.tistory.com/38</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;662&quot; width=&quot;207&quot; height=&quot;117&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqTsoW/btq9RcDyM8K/ENlp0dcPqrewt7OJiZ0Ke1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqTsoW/btq9RcDyM8K/ENlp0dcPqrewt7OJiZ0Ke1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqTsoW/btq9RcDyM8K/ENlp0dcPqrewt7OJiZ0Ke1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqTsoW%2Fbtq9RcDyM8K%2FENlp0dcPqrewt7OJiZ0Ke1%2Fimg.png&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;662&quot; width=&quot;207&quot; height=&quot;117&quot; data-ke-mobilestyle=&quot;widthOrigin&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 data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #424242;&quot;&gt;인터페이스를 상속받는 구현 클래스들의 객체를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;생성할 때,&lt;span style=&quot;color: #424242;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;생성자를 통해 직접&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;생성하는 것이&lt;span style=&quot;color: #424242;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;아닌 해당 인터페이스를 상속하는 하위 클래스에서 객체를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;생성하는 것을&lt;span style=&quot;color: #424242;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;u&gt;팩토리 패턴&lt;/u&gt;&lt;/b&gt;이라고 한다. 즉 객체 생성을 다른 서브 클래스로 캡슐화하여 구현 클래스에 대한 의존성을 줄이는 것이다. &lt;/span&gt;&lt;span style=&quot;color: #424242;&quot;&gt;이를 통해 얻을수 있는 효과는 클래스간의 결합도를 낮춰, 변경과 제거를 최소화 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #424242;&quot;&gt;만약 음식이라는 클래스를 상속받는 여러 음료수 하위 클래스가 존재하는 상황을 가정해 보겠다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1626523966339&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Food 추상 클래스
public abstract class Food{
    public abstract String eat();
}


///////////////////////////////

public class Pizza extends Food{
    @Override
    public String eat(){
        return &quot;yammy~ pizza&quot;;
    }
}

public class Chicken extends Food{

    @Override
    public String eat(){
        return &quot;yammy~ chicken&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #424242;&quot;&gt;이때 각 객체를 생성할 때&amp;nbsp; new 연산자를 하위클래스에 직접사용하지 않고 간단한 팩토리 패턴을 이용해서 생성해보자&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1626524163915&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public abstract class FoodFactory{
    public abstract Food create(String type);
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1626524254584&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class MealFactory extends FoodFactory{

    @Override
    public create(String type){
        Food food = null;

        switch(type){
            case(&quot;pizza&quot;):
                food = new Pizza();
                break;
            case(&quot;chicken&quot;):
                food = new Chicken();
                break;
            default:
                food = null;
        }
        return food;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 FoodFactory 추상 클래스를 만든 다음에 하위 클래스에서 상속하여 create 매소드를 통해 객체를 반환하는 것을 확인할 수 있다. 만약 food 상속 클래스 중에 음료스는 meal과 먹는 방법이 달라 다른 방법으로 생성을 해야 한다면 마찬가지고 FoodFactory를 상속하는 BeverageFactory 클래스를 생성하여 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직접 팩토리를 이용하여 객체를 생성해보면 아래와 같다. 이렇게 mealFactory 객체 안에서 어떻게 객체가 생성되는지 모르는 것처럼 캡슐화하였고, 만약 Food 클래스에 변경이 일어나도 클래스 객체를 사용하는 모든 코드를 수정할 필요 없이 반환받은 객체만 이용하면 된다는 장점이 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1626524498582&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;MealFactory mealFactory = new MealFactory();
Food pizza = mealFactory.create(&quot;pizza&quot;);
Food chicken = mealFactory.create(&quot;chicken&quot;);

System.out.println(pizza.eat());
System.out.println(chicken.eat());


// output
// yammy~ pizza
// yammy~ chicken&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&quot;dicLayer&quot; style=&quot;color: #000000; font-size: 12px; font-family: Arial; background: -webkit-linear-gradient(bottom, #ffeb00, #ffdc00); width: 400px; height: 150px; display: none;&quot;&gt;
&lt;div id=&quot;dicLayerContents&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;dicLayerSub&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;dicRawData&quot; style=&quot;display: none;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;dicLayerLoader&quot;&gt;&amp;nbsp;&lt;/div&gt;</description>
      <category>Study/Design Pattern</category>
      <author>DOWN</author>
      <guid isPermaLink="true">https://down-develope.tistory.com/38</guid>
      <comments>https://down-develope.tistory.com/38#entry38comment</comments>
      <pubDate>Sat, 17 Jul 2021 21:24:20 +0900</pubDate>
    </item>
    <item>
      <title>[Design Pattern] Singleton Pattern 싱글톤 패턴</title>
      <link>https://down-develope.tistory.com/37</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;662&quot; width=&quot;354&quot; height=&quot;200&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/05pKu/btq9C8J2dIW/250rg8zyPzzWtyVnNEMgsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/05pKu/btq9C8J2dIW/250rg8zyPzzWtyVnNEMgsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/05pKu/btq9C8J2dIW/250rg8zyPzzWtyVnNEMgsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F05pKu%2Fbtq9C8J2dIW%2F250rg8zyPzzWtyVnNEMgsK%2Fimg.png&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;662&quot; width=&quot;354&quot; height=&quot;200&quot; data-ke-mobilestyle=&quot;widthOrigin&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 data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;싱글턴 패턴이란(Singleton Pattern)&lt;/b&gt; 어떤 구현 클래스의 인스턴스를 단 1개만 생성하는 패턴입니다. 인스턴스가 남용돼서&amp;nbsp; 자원을 낭비하는 경우를 없애고, 시스템 전반에 걸쳐 하나의 자원을 공유하여 사용하고자 할때 유용한 패턴입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 싱글톤 패턴을 간단하게 구현해보면 아래와 같이 구현 가능합니다. 기본생성자, 복사생성자, 제거자를 private으로 지정하여 외부의 접근을 막고, getInstance 맴버함수로만 instance를 생성할 수 있게 하는 것입니다.&lt;/p&gt;
&lt;div id=&quot;dicLayer&quot; style=&quot;color: #000000; font-size: 12px; font-family: Arial; background: -webkit-linear-gradient(bottom, #ffeb00, #ffdc00); width: 400px; height: 150px; display: none; left: 480px; top: 1316px;&quot;&gt;
&lt;div id=&quot;dicLayerContents&quot;&gt;locking &lt;input id=&quot;ee&quot; type=&quot;checkbox&quot; /&gt;Eng&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1.locking&lt;br /&gt;&lt;br /&gt;[명사] (브레이크댄스의) 로킹(과장된 동작의 코미디 댄스); 〈컴퓨터〉 잠그기.&lt;br /&gt;&lt;br /&gt;2.locking&lt;br /&gt;&lt;br /&gt;[명사] (기계공학) 로킹&lt;br /&gt;&lt;br /&gt;3.lock&lt;br /&gt;&lt;br /&gt;[동사] (자물쇠로) 잠그다[잠기다]&lt;br /&gt;&lt;br /&gt;4.lock1&lt;br /&gt;&lt;br /&gt;[명사] 자물쇠&lt;br /&gt;&lt;br /&gt;5.lock2&lt;br /&gt;&lt;br /&gt;[명사] (머리의) 타래, 머리채&lt;br /&gt;&lt;br /&gt;6.잠금&lt;br /&gt;&lt;br /&gt;(의학) locking&lt;br /&gt;&lt;br /&gt;7.레코드 잠금&lt;br /&gt;&lt;br /&gt;record locking.&lt;br /&gt;&lt;br /&gt;8.잠금 방법&lt;br /&gt;&lt;br /&gt;(전력) locking method&lt;br /&gt;&lt;br /&gt;9.잠금장치&lt;br /&gt;&lt;br /&gt;(전력) locking device&lt;br /&gt;&lt;br /&gt;10.제1안전핀&lt;br /&gt;&lt;br /&gt;(군사) locking safety&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div id=&quot;dicLayerSub&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;dicRawData&quot; style=&quot;display: none;&quot;&gt;{&quot;mean&quot;:[],&quot;word&quot;:&quot;getInstance&quot;,&quot;phoneticSymbol&quot;:&quot;&quot;}&lt;/div&gt;
&lt;div style=&quot;display: none;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div style=&quot;display: none;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div style=&quot;display: none;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1626339650481&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class SingleTon{

   private static SingleTon instance = null;
   private SingleTon(){}

   public static SingleTon getInstance(){
        if(instance==null){
            instance = new SingleTon();
        }
        return instance;
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단 위 같은 코드는 문제가 있습니다. 만약 다중 쓰레딩 환경이면 getInstance 메소드를 통해 instance를 가져오는 것이 &lt;u&gt;thread-safe&lt;/u&gt; 하지 않을 수 있습니다. 만약 instance = null인 상황에서, 2개의 thread가 동시에 getInstance 메소드를 호출하면 각각 new 연산자로 할당받을 수 있을 수 있기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 해결하기 위해 synchronized 키워드를 이용할 수 있습니다. 아래처럼 getInstance 메소드 앞에 synchronized&lt;span style=&quot;color: #292929;&quot;&gt;&lt;span&gt; 키워드를 붙이게 되면 thread-safe하게 동작합니다.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #292929;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;dicLayer&quot;&gt;
&lt;div id=&quot;dicLayerContents&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;dicLayerSub&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;dicRawData&quot; style=&quot;display: none;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;dicLayerLoader&quot; class=&quot;&quot; style=&quot;top: 560px; left: 523px;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;pre id=&quot;code_1626345165219&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class SingleTon{

   private static SingleTon instance = null;
   private SingleTon(){}

   public static synchronized SingleTon getInstance(){
        if(instance==null){
            instance = new SingleTon();
        }
        return instance;
   }
}​&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 방법은 확실히 thread-safe합니다. 하지만 치명적인 단점이 존재합니다. 바로 인스턴스를 호출하기 위해서는 항상 동기화 블록을 지나게 됩니다. synchronized&lt;span style=&quot;color: #292929;&quot;&gt;&lt;span&gt; 키워드는 성능을 엄청 떨어트리는 단점이 있으므로 성능까지 고려해야 하는 상황이면 좋지 않은 방법이 돼버립니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #292929;&quot;&gt;&lt;span&gt;그래서 이럴 때는 Double Checking Locking (DCL) 방법을 사용하면 됩니다.&amp;nbsp; 동기화 블록에 들어가기 전에 instance의 생성 여부를 확인해 주고 진입합니다. 그리고 동기화 블록에 진입하자마자 다시 한번 더 검사해 주는 방법입니다. 이때 instance 변수가 volatile 키워드로 선언되어 있는 것을 확인할 수 있는데, votaile로 선언하면 변수에 접근할 때 캐시를 참조하지않고 항상 메모리를 참조하게 됩니다. 그래서 쓰레드간 캐시가 달라 생기는 문제를 방지할 수 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1626345637665&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class SingleTon{

   private volatile static SingleTon instance = null;
   private SingleTon(){}

   public static SingleTon getInstance(){
        if(instance==null){
            synchronized(SingleTon.class){
                if(instance==null){
                    instance = new SingleTon();
                }
            }
        }
        return instance;
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&quot;dicLayer&quot;&gt;
&lt;div id=&quot;dicLayerContents&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;dicLayerSub&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;dicRawData&quot; style=&quot;display: none;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;dicLayerLoader&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;dicLayer&quot;&gt;
&lt;div id=&quot;dicLayerContents&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;dicLayerSub&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;dicRawData&quot; style=&quot;display: none;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;dicLayerLoader&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;dicLayer&quot;&gt;
&lt;div id=&quot;dicLayerContents&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;dicLayerSub&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;dicRawData&quot; style=&quot;display: none;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;dicLayerLoader&quot;&gt;&amp;nbsp;&lt;/div&gt;</description>
      <category>Study/Design Pattern</category>
      <author>DOWN</author>
      <guid isPermaLink="true">https://down-develope.tistory.com/37</guid>
      <comments>https://down-develope.tistory.com/37#entry37comment</comments>
      <pubDate>Thu, 15 Jul 2021 19:16:47 +0900</pubDate>
    </item>
  </channel>
</rss>