1. 전략 패턴이란?

전략 패턴은 실행 중에 알고리즘을 선택할 수 있게 하는 행위 소프트웨어 디자인 패턴이다. - 위키 백과

동일 계열의 알고리즘군을 정의하고, 각 알고리즘을 캡슐화하며, 이들을 상호교환이 가능하도록 만든다. 알고리즘을 사용하는 클라이언트와 상관없이 독립적으로 알고리즘을 다양하게 변경할 수 있게 한다. - GoF

특정 기능이 추가될 때, 전략 객체를 생성 후 주입하는 방식으로 유연하게 기능을 확장할 수 있습니다.

전략 패턴 클래스 다이어그램

 

2. 예제 소스

1) Strategy 인터페이스 및 Strategy 클래스

//전략 인터페이스
public interface PrintStrategy {

    public void print();
}

//프린터로 전달하는 전략
public class PrinterStrategy implements PrintStrategy {

    @Override
    public void print() {
        System.out.println("Printer로 전달");
    }

}

//구글 드라이브로 전달하는 전략
public class GoogleDriveStrategy implements PrintStrategy {

    @Override
    public void print() {
        System.out.println("구글 드라이브로 전달");
    }

}

//팩스로 전달하는 전략
public class FaxStrategy implements PrintStrategy {

    @Override
    public void print() {
        System.out.println("Fax로 전달");
    }

}
각 전략 클래스들은 PrintStrategy 인터페이스를 상속하고 print() 메소드를 오버라이딩합니다.

 

2) Context 클래스

import java.util.Objects;

public class Printing {

    private PrintStrategy printStrategy;

    public void print() {
        if (Objects.nonNull(printStrategy)) {
            printStrategy.print();
        }
    }

    public void setPrintStrategy(PrintStrategy printStrategy) {
        this.printStrategy = printStrategy;
    }

}
인쇄 관련 기능을 직접 구현하지 않고 전략을 주입하는 형식으로 인쇄 기능을 수행합니다.
setPrintStrategy(PrintStrategy printStrategy) 메소드를 통해 인쇄 전략을 주입받고, print() 메소드를 통해 주입받은 전략을 수행합니다.

 

3) Client 

public class ChromeBrower extends Printing {

}
public class Main {

    public static void main(String[] args) {
        ChromeBrower chromeBrower = new ChromeBrower();
        PrintStrategy printerStrategy = new PrinterStrategy();
        PrintStrategy googleDriveStrategy = new GoogleDriveStrategy();

        chromeBrower.setPrintStrategy(printerStrategy);
        chromeBrower.print();

        chromeBrower.setPrintStrategy(googleDriveStrategy);
        chromeBrower.print();

    }

}
ChromeBrower 클래스는 Printing 클래스를 상속 받고, 다양한 전략을 주입받아서 인쇄 기능을 수행합니다.
새로운 기능이 추가되어도 PrintStrategy 전략을 생성하고 주입하는 형식으로 유연하게 기능을 확장할 수 있습니다.

참조

https://ko.wikipedia.org/wiki/%EC%A0%84%EB%9E%B5_%ED%8C%A8%ED%84%B4
https://victorydntmd.tistory.com/292

리눅스 시간을 한국 표준 시간으로 맞추려면 timezone을 UTC+9 KST (Korea Standard Time)로 해주어야 합니다.

UTC (Universal Time, Coordinated, 협정 세계시)란 국제적인 표준시간의 기준으로 쓰이는 시간을 말합니다.
UTC의 기준 시간은 영국 런던이고 우리나라는 런던을 기준으로 9시간을 더해주면 됩니다.
// Seoul timezone이 있는지 확인
# ls /usr/share/zoneinfo/Asia

// 기존 타임존 삭제
# rm /etc/localtime
# ln -s /usr/share/zoneinfo/Asia/Seoul /etc/localtime

// KST timezone으로 바뀌었는지 확인
# date

 

1. 데코레이터 패턴이란?

기본 기능 객체와 부가 기능 객체를 결합해서 동적으로 기능을 확장할 수 있게 해주는 패턴

 

2. 데코레이터 패턴의 특징

1) 구조 패턴
클래스나 객체를 조합해서 더 큰 구조를 만드는 패턴

2) 합성 관계
생성자에서 필드의 객체를 생성하는 경우, 필드 객체의 라이프 사이클은 전체 객체에 의존적이게 된다.

 

3. 프록시 패턴과 데코레이터 패턴의 비교

프록시 패턴
제어의 흐름을 변경하거나 별도의 로직 처리를 목적으로한다. 특별한 경우가 아니라면 반환값을 변경하지 않는다.

데코레이터 패턴
데코레이터를 추가할수록 추상 메소드에 기능이 많아진다

 

4. 언제 사용하는가?

1) 기본 기능 객체의 기능을 그대로 유지하면서 새로운 기능을 동적으로 추가할 때 사용한다.

2) 탈부착 가능한 책임을 정의할 때 사용한다.

3) 상속을 통해 서브클래스를 만드는 방법이 비효율적 일 때 사용한다.

 

5. 예제 소스

public abstract class Window {

    abstract public void draw();
}

public class WindowConcrete extends Window {

    @Override
    public void draw() {
        System.out.println("draw Window");
    }
    
}
Window 추상 클래스와 구현체인 WindowConcrete 클래스를 생성한다. 
draw() 메소드에 데코레이터 클래스에서 구현한 부가기능이 추가된다.

 

public abstract class WindowDecorator extends Window {

    protected Window window;

    public WindowDecorator(Window window) {
        this.window = window;
    }
}

public class ScrollBarDecorator extends WindowDecorator {

    public ScrollBarDecorator(Window window) {
        super(window);
    }

    //중요
    @Override
    public void draw() {
        super.window.draw();
        drawScrollBar();
    }

    private void drawScrollBar() {
        System.out.println("draw Scroll Bar");
    }

}

public class ButtonDecorator extends WindowDecorator {

    public ButtonDecorator(Window window) {
        super(window);
    }

    //중요
    @Override
    public void draw() {
        window.draw();
        drawButton();
    }

    private void drawButton() {
        System.out.println("draw Button");
    }

}
WindowDecorator 추상클래스를 상속받아서 부가 기능을 수행하는 Decorator 클래스를 생성한다.
생성자로 Window 추상 클래스의 구현체를 받고, 해당 구현체에 기능을 추가하는 형식으로 진행된다.

 

public class Main {

    public static void main(String[] args) {
        Window window = new ButtonDecorator(new ScrollBarDecorator(new WindowConcrete()));

        window.draw();
    }
}
WindowConcrete 구현체 클래스를 생성하고, ScrollBar와 Button Decorator를 추가한다.

 

출력

draw Window
draw Scroll Bar
draw Button

참조 :

gmlwjd9405.github.io/2018/07/09/decorator-pattern.html
johngrib.github.io/wiki/decorator-pattern/#fn:head
https://server-engineer.tistory.com/79?category=625272
팩토리 메소드 패턴
객체의 생성을 팩토리 클래스로 위임하여 객체를 생성하는 패턴

추상 팩토리 패턴
팩토리를 추상화해서 관련있는 객체의 집합을 생성할 수 있는 팩토리를 만들고 조건에 따라 팩토리를 생성해서 서로 관련된 객체를 생성하는 패턴 

 

JAVA 소스 예제

public abstract class Phone {

    public abstract void power();
}

public class SamsungPhone extends Phone {

    @Override
    public void power() {
        System.out.println("samsung phone power on");
    }

}

public class ApplePhone extends Phone {

    @Override
    public void power() {
        System.out.println("apple phone power on");
    }

}
SamsungPhone 클래스와 ApplePhone 클래스는 Phone 추상클래스를 상속하고 power() 메소드를 오버라이딩한다.

 

public interface PhoneFactory {

    public Phone create();
}

public class ApplePhoneFactory implements PhoneFactory {

    @Override
    public Phone create() {
        return new ApplePhone();
    }

}

public class SamsungPhoneFactory implements PhoneFactory {

    @Override
    public Phone create() {
        return new SamsungPhone();
    }

}
ApplePhoneFactory 클래스와 SamsungPhoneFactory 클래스는 PhoneFactory를 상속하고 create()메소드를 오버라이딩한다.
create() 메소드는 각각 팩토리 클래스 별로 제조사에 맞는 Phone 클래스를 반환한다.

 

public enum PhoneType {
    SAMSUNG, APPLE
}

public class Main {

    public static void main(String[] args) {
        PhoneFactory phoneFactory = null;
        PhoneType phoneType = PhoneType.SAMSUNG;

        switch (phoneType) {
            case SAMSUNG:
                phoneFactory = new SamsungPhoneFactory();
                break;
            case APPLE:
                phoneFactory = new ApplePhoneFactory();
                break;
            default:
                throw new RuntimeException(phoneType.toString() + " is not existed");
        }

        Phone phone = phoneFactory.create();
        phone.power();

    }

}
enum 타입인 phoneType 별로 PhoneFactory를 생성하고 create() 메소드를 실행한 뒤, phone의 power() 메소드를 실행한다.
phoneType 별로 생성되는 Factory가 바뀌어서 생성되는 phone 또한 바뀌는 것을 볼 수 있다.

 

CASE WHEN Function은 다중 조건문을 사용하고 싶을 때, 사용하는 함수입니다.

SELECT 
    CASE 
        WHEN a.view_count > 50 THEN 'comment 1'
        WHEN a.view_count = 50 THEN 'comment 2'
        ELSE 'else comment'
    END
FROM board a;

 

CASE 문은 WHEN의 조건을 순차적으로 체크하고 조건이 충족되면 THEN에 명시된 값을 반환합니다.

모든 조건이 만족되지 않으면 ELSE 값을 반환합니다.

ELSE 부분이 없고 조건이 참이 아니면 NULL 값을 반환합니다. 

'IT > Mysql & MariaDB' 카테고리의 다른 글

[Mysql] Date_Format 날짜 포멧  (0) 2021.01.27
[MariaDB] Sequence 사용 방법  (0) 2021.01.15
[Mysql] 문자열 치환 함수 replace  (0) 2020.09.22
[Mysql] ON DUPLICATE KEY UPDATE ...  (0) 2020.07.24
[Mysql] GROUP_CONCAT 사용 방법  (1) 2020.04.14

1. aliases model

public class Board {

    private int id;
    private String title;
    private String content;
    
    //getter, setter 생략
}

2. board 테이블 SQL

CREATE TABLE `board` (
	`id` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
	`title` VARCHAR(100) NULL DEFAULT NULL,
	`content` VARCHAR(3000) NULL DEFAULT NULL,
	`writer` VARCHAR(100) NULL DEFAULT NULL
)

3. @Mapper 어노테이션이 선언된 Mapper 인터페이스

import com.example.demo.model.Board;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface BoardMapper {
    void saveBoard(Board board);
}

4. mapper-board.xml

<!DOCTYPE mapper
	PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
	"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.example.demo.mapper.BoardMapper">
    
    <insert id="saveBoard" parameterType="Board" useGeneratedKeys="true" keyProperty="id">
        insert into board (
            title,
            content
        ) values(
            #{title},
            #{content}
        )
    </insert>
</mapper>
userGeneratedKeys="true"로 해주고 keyProperty에는 auto_increment로 선언된 column 명을 입력해주면 됩니다.

BoardMapper의 saveBoard 메소드를 실행하면 board가 insert되고 파라메터로 넘겼던 Board 객체의 id 멤버 변수에 key 값이 입력됩니다.

'IT > mybatis' 카테고리의 다른 글

[mybatis] mybatis 동적 SQL 만들기  (0) 2021.02.01

1. 스프링 부트란?

스프링 프레임워크 기반 프로젝트를 복잡한 설정없이 쉽고 빠르게 만들어주는 라이브러리입니다.
사용자가 일일이 모든 설정을 하지 않아도 자주 사용되는 기본설정을 알아서 해줍니다.

2. 왜 스프링 부트를 사용해야할까?

스프링 프레임워크를 사용하려면 많은 XML 설정 파일(web.xml, rootContext.xml, ServletContext.xml 등)들을 작성해야하고, 설정 방법을 모두 외우지 못했다면 기존에 사용했던 설정을 Copy&Paste하거나 개발자가 일일이 인터넷 검색을 통해서 설정해주어야 했습니다. 이는 곧 생산성과 비용 문제로 직결될 수 있습니다.

하지만 스프링 부트를 사용하면 복잡한 설정없이 쉽고 빠르게 스프링 프레임워크를 사용할 수 있습니다.

3. Spring Boot 장점

1) 라이브러리 관리의 자동화

 스프링 부트의 Starter 라이브러리를 등록해서 라이브러리의 의존성을 간단하게 관리할 수 있습니다.

2) 라이브러리 버전 자동 관리

기존에는 스프링 라이브러리의 버전을 하나하나 직접 입력해야 했지만, 스프링 부트는 pom.xml에 스프링 부트 버전을 입력하면 스프링 라이브러리 뿐만 아니라 서드 파티 라이브러리들도 호환되는 버전으로 알아서 다운해줍니다.
<!-- maven -->
<project>
...
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.0-SNAPSHOT</version>
        <relativePath/>
    </parent>
...

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <!-- 버전을 입력하지 않아도 된다. -->
        </dependency>
    </dependencies>

</project>

3) 설정의 자동화

스프링 부트는 @EnableAutoConfiguration 어노테이션을 선언해서 스프링에서 자주 사용 했던 설정들을 알아서 등록해줍니다.
이것을 스프링 부트에 마법이라고 불린다고 합니다.

4) 내장 Tomcat

스프링 부트는 Tomcat을 내장하고 있기 때문에 @SpringBootApplication어노테이션이 선언되어있는 클래스의 main() 메소드를  실행하는 것만으로 서버를 구동시킬 수 있습니다.  내장 톰캣을 사용하려면 특별한 설정없이 Web Starter 의존성만 추가해주면 됩니다.
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

 

5) 독립적으로 실행 가능한 JAR

웹 프로젝트라면 WAR 파일로 패키징해야하지만 스프링 부트는 내장 톰캣을 지원하기 때문에 JAR 파일로 패키징해서 웹 애플리케이션을 실행시킬 수 있습니다.

 


참조 :
https://kimyhcj.tistory.com/373 [기억과 기록]
elevatingcodingclub.tistory.com/25

1. 팩토리 메소드 패턴이란?

객체를 생성하기 위한 인터페이스를 정의하고, 어떤 클래스의 인스턴스를 생성할지에 대한 처리는 서브클래스가 결정하는 디자인 패턴
- GoF

 

참조 : https://johngrib.github.io/wiki/factory-method-pattern/

 

2. 팩토리 메소드 패턴을 사용하는 이유

팩토리 메소드 패턴을 사용하는 이유는 클래스의 생성과 사용의 처리로직을 분리하여 결합도를 낮추기 위한 것 입니다. 
결합도는 간단히 말해서 클래스의 처리 로직에 대한 변경점이 생겼을 때 얼마나 사이드 이펙트를 주는가 인데, 팩토리 메소드 패턴을 사용할 경우 직접 객체를 생성해 사용하는 것을 방지하고 서브 클래스에 생성 로직을 위임함으로써 보다 효율적인 코드 제어를 할 수 있고 의존성을 제거 합니다.

 

3. 팩토리 메소드 패턴 예제

1) 음료수의 추상 클래스

public abstract class Drink {

    abstract public String info();
    
}
음료수의 베이스가 되는 추상클래스입니다. 모든 음료수는 info() 메소드를 오버라이딩해야 합니다.

 

2) 음료수 클래스

public class Coffee extends Drink {

    @Override
    public String info() {
        return "커피 맛";
    }

}
public class Coke extends Drink {

    @Override
    public String info() {
        return "콜라 맛";
    }

}
public class Tejava extends Drink {

    @Override
    public String info() {
        return "크래파스 맛";
    }

}
Drink 추상 클래스를 상속받는 음료수 클래스입니다. 각 클래스는 info() 메소드를 오버라이딩합니다.

 

3) 음료수 타입 (enum)

public enum DrinkType {
    Coke, Coffee, Tejava
}
음료수 타입은 enum으로 지정했습니다.

 

4) Factory Class

public abstract class DrinkFactory {
    abstract Drink create(DrinkType drinkType);
}
//factory class
public class VendingMachine extends DrinkFactory {

    @Override
    public Drink create(DrinkType drinkType) {

        switch (drinkType) {
            case Coffee:
                return new Coffee();
            case Coke:
                return new Coke();
            case Tejava:
                return new Tejava();
            default:
                throw new RuntimeException(drinkType.toString() + " is not existed");
        }
    }
}
DrinkFactory 클래스의 서브 클래스인 VendingMachine 클래스에서 create() 메소드를 오버라이딩합니다.
create 메소드의 파라미터로 drinkType을 전달받아 Drink 객체를 생성합니다.

 

5) Main

public class Main {

    public static void main(String[] args) {
        
        DrinkFactory drinkFactory = new VendingMachine();

        Drink drink1 = drinkFactory.create(DrinkType.Coffee);
        Drink drink2 = drinkFactory.create(DrinkType.Tejava);

        System.out.println(drink1.info());
        System.out.println(drink2.info());

    }

}
create 메소드에 DrinkType enum을 파라미터로 전달해 Drink 객체를 생성합니다.

 

6) 결과

커피 맛
크래파스 맛

참조 :
jdm.kr/blog/180
johngrib.github.io/wiki/factory-method-pattern/

+ Recent posts