스트레티지 패턴(Strategy Pattern)에 대해서 알아보자


환경

  • Java


스트레티지 패턴(Strategy Pattern)이란?

스트레티지 패턴(Strategy Pattern)

  • 스트레티지 패턴(Strategy Pattern): 특정한 알고리즘을 정의하고 이를 캡슐화하여 해당 알고리즘이 필요한 대상들이 이를 상호 교체 가능하게 하는 구조
  • Java의 경우 인터페이스를 생성하고 해당 부분을 구현해서 캡슐화 하고 이를 원하는 객체의 메소드에 붙여주면 된다. 자세한 설명과 예제는 아래 참고
  • 이미지 출처: https://en.wikipedia.org/wiki/Strategy_pattern


필요성

로봇 사례

  • 로봇을 만든다고 생각해보자. 로봇은 태권V도 있고 아톰도 있고 건담도 있다. 이때 어떤 방법으로 만들어야할까? 가장 기본틀인 로봇을 추상 클래스로 만들고 상속을 통해 각각을 만들어보자.
  • 우선 로봇 추상 클래스를 만들고 태권V와 아톰만 만들어보자.


예제

Robot

public abstract class Robot {
    private String name;
    public Robot(String name){ this.name = name; }

    public String getName(){ return name;}

    public abstract void attack();
    public abstract void move();
}

TaekwonV

public class TaekwonV extends Robot {

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

    @Override
    public void attack() {
        System.out.println("kick");
    }

    @Override
    public void move() {
        System.out.println("walk");
    }
}

Atom

public class Atom extends Robot {

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

    @Override
    public void attack() {
        System.out.println("punch");
    }

    @Override
    public void move() {
        System.out.println("fly");
    }
}

Main

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

        Robot taekwonV = new TaekwonV("TaekwonV");
        Robot atom = new Atom("Atom");

        System.out.println("I am " + taekwonV.getName());
        taekwonV.attack();
        taekwonV.move();

        System.out.println();

        System.out.println("I am " + atom.getName());
        atom.attack();
        atom.move();
    }
}


해당 코드의 문제점

  • 기존 로봇의 공격 방법을 수정하려면 새로운 기능을 위해 기존 코드를 수정하기 때문에 OCP(Open-Closed Principle)에 위반된다. 예를들어 위의 예제에서 아톰이 태권V와 똑같은 move()를 사용하려 하면 코드를 직접 수정해야하고 나아가 중복이 발생하며 로봇의 종류가 많아질수록 코드의 관리는 어려워진다.
  • 새로운 로봇을 만들어서 아톰과 같은 공격과 태권V와 같은 이동을 하게 하고 싶다면? 동일한 코드를 복사하게 작성하게 되면 중복이 발생하게 된다. 예를 들어서 건담을 만들때 아톰의 attack()과 태권V의 move() 코드를 또 동일하게 작성하기 때문에 중복이 발생한다.


해결 방법

  • 로봇을 만드는 과정에 있어서 변화하는 부분이 무엇인지 먼저 찾아야한다. 변화될 수 있는 부분을 찾아서 이를 캡슐화하고 상호 교체 가능하도록 만드는것이 중요하다.
  • 예제 코드들에서는 attack()과 move()의 코드들이 계속 변경될 수 있으며 이를 캡슐화해서 필요할때 붙여주면 코드의 중복도 줄이고 코드의 변경도 줄일 수 있다.
  • 직접적인 구현은 각각을 interface로 구현해서 객체를 만들때 붙여주면 된다.
  • 그림에서 보면 move()의 경우에 MovingStrategy라는 인터페이스를 만들고 각각의 방법에 대한 구현을 implements를 통해서 클래스화 시키면된다.


예제

Robot

public abstract class Robot {
    private String name;
    private AttackStrategy attackStrategy;
    private MovingStrategy movingStrategy;

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

    public String getName() {
        return name;
    }

    public void attack() {
        attackStrategy.attack();
    }

    public void move() {
        movingStrategy.move();
    }

    public void setAttackStrategy(AttackStrategy attackStrategy) {
        this.attackStrategy = attackStrategy;
    }

    public void setMovingStrategy(MovingStrategy movingStrategy) {
        this.movingStrategy = movingStrategy;
    }

}

AttackStrategy

public interface AttackStrategy {
    public void attack();
}

MovingStrategy

public interface MovingStrategy {
    public void move();
}

KickingStrategy

public class KickingStrategy implements AttackStrategy {
    @Override
    public void attack() {
        System.out.println("kick");
    }
}

PunchingStrategy

public class PunchingStrategy implements AttackStrategy {
    @Override
    public void attack() {
        System.out.println("punch");
    }
}

WalkingStrategy

public class WalkingStrategy implements MovingStrategy {
    @Override
    public void move() {
        System.out.println("walk");
    }
}

FlyingStrategy

public class FlyingStrategy implements MovingStrategy {
    @Override
    public void move() {
        System.out.println("fly");
    }
}

TaekwonV

public class TaekwonV extends Robot {
    public TaekwonV(String name) {
        super(name);
    }
}

Atom

public class Atom extends Robot {
    public Atom(String name) {
        super(name);
    }
}

Gundam

public class Gundam extends Robot {
    public Gundam(String name) {
        super(name);
    }
}

Main

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

        Robot taekwonV = new TaekwonV("TaekwonV");
        Robot atom = new Atom("Atom");
        Robot gundam = new Gundam("Gundam");

        taekwonV.setAttackStrategy(new KickingStrategy());
        taekwonV.setMovingStrategy(new WalkingStrategy());

        atom.setAttackStrategy(new PunchingStrategy());
        atom.setMovingStrategy(new FlyingStrategy());

        gundam.setAttackStrategy(new PunchingStrategy());
        gundam.setMovingStrategy(new WalkingStrategy());

        System.out.println("I am " + taekwonV.getName());
        taekwonV.attack();
        taekwonV.move();

        System.out.println();

        System.out.println("I am " + atom.getName());
        atom.attack();
        atom.move();

        System.out.println();

        System.out.println("I am " + gundam.getName());
        gundam.attack();
        gundam.move();

    }
}


참고자료

Post about Strategy Pattern.


Environment and Prerequisite

  • Java


What is Strategy Pattern?

Strategy Pattern

  • Strategy Pattern: It is a design pattern which define set of algorithms and interchange those algorithms when it is needed. Those algorithms are encapsulated by class. Instead of implementing a single algorithm directly, code receives run-time instructions as to which in a family of algorithms to use.
  • In case of java, define strategy to interface and implement it in class to encapsulate it. Add it to object’s method when you use it. There will be an examples below.
  • Image Source: https://en.wikipedia.org/wiki/Strategy_pattern


Necessity

Robot Example

  • Let’s imagine we make robots. Robots will be TaekwonV, Atom and Gundam. How to implement them then? Make basic form in abstract Robot class and use inheritance(‘extends’ keyword in java).
  • First, let’s make abstract Robot class, TaekwonV class and Atom class.


Example

Robot

public abstract class Robot {
    private String name;
    public Robot(String name){ this.name = name; }

    public String getName(){ return name;}

    public abstract void attack();
    public abstract void move();
}

TaekwonV

public class TaekwonV extends Robot {

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

    @Override
    public void attack() {
        System.out.println("kick");
    }

    @Override
    public void move() {
        System.out.println("walk");
    }
}

Atom

public class Atom extends Robot {

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

    @Override
    public void attack() {
        System.out.println("punch");
    }

    @Override
    public void move() {
        System.out.println("fly");
    }
}

Main

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

        Robot taekwonV = new TaekwonV("TaekwonV");
        Robot atom = new Atom("Atom");

        System.out.println("I am " + taekwonV.getName());
        taekwonV.attack();
        taekwonV.move();

        System.out.println();

        System.out.println("I am " + atom.getName());
        atom.attack();
        atom.move();
    }
}


Problems in above code.

  • To modify existed code to new code, we need to modify existed code and it violates OCP(Open-Closed Principle). For example in above code if we like to use same move() method in both Atom and TaekwonV we need to modify existed code and it also cause duplicate code. As the number of robots grows, it is hard to manage code.
  • What if we like to make new robot and use same method of TaekwonV’s move() and Atom’s attack()? There will be a code duplication if we copy and paste it.


Solution

  • In implementing robot, we need to find which part of code are changeable. Find changing part, encapsulate it and make it interchangeable.
  • In above code, attack() and move() are changeable. So encapsulate those methods and use it when it is needed. It prevents from code duplication and code modifying.
  • Make each to java’s interface and make object when it is needed.
  • In case of move() method, make MovingStrategy interface and implements it in class.


Example

Robot

public abstract class Robot {
    private String name;
    private AttackStrategy attackStrategy;
    private MovingStrategy movingStrategy;

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

    public String getName() {
        return name;
    }

    public void attack() {
        attackStrategy.attack();
    }

    public void move() {
        movingStrategy.move();
    }

    public void setAttackStrategy(AttackStrategy attackStrategy) {
        this.attackStrategy = attackStrategy;
    }

    public void setMovingStrategy(MovingStrategy movingStrategy) {
        this.movingStrategy = movingStrategy;
    }

}

AttackStrategy

public interface AttackStrategy {
    public void attack();
}

MovingStrategy

public interface MovingStrategy {
    public void move();
}

KickingStrategy

public class KickingStrategy implements AttackStrategy {
    @Override
    public void attack() {
        System.out.println("kick");
    }
}

PunchingStrategy

public class PunchingStrategy implements AttackStrategy {
    @Override
    public void attack() {
        System.out.println("punch");
    }
}

WalkingStrategy

public class WalkingStrategy implements MovingStrategy {
    @Override
    public void move() {
        System.out.println("walk");
    }
}

FlyingStrategy

public class FlyingStrategy implements MovingStrategy {
    @Override
    public void move() {
        System.out.println("fly");
    }
}

TaekwonV

public class TaekwonV extends Robot {
    public TaekwonV(String name) {
        super(name);
    }
}

Atom

public class Atom extends Robot {
    public Atom(String name) {
        super(name);
    }
}

Gundam

public class Gundam extends Robot {
    public Gundam(String name) {
        super(name);
    }
}

Main

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

        Robot taekwonV = new TaekwonV("TaekwonV");
        Robot atom = new Atom("Atom");
        Robot gundam = new Gundam("Gundam");

        taekwonV.setAttackStrategy(new KickingStrategy());
        taekwonV.setMovingStrategy(new WalkingStrategy());

        atom.setAttackStrategy(new PunchingStrategy());
        atom.setMovingStrategy(new FlyingStrategy());

        gundam.setAttackStrategy(new PunchingStrategy());
        gundam.setMovingStrategy(new WalkingStrategy());

        System.out.println("I am " + taekwonV.getName());
        taekwonV.attack();
        taekwonV.move();

        System.out.println();

        System.out.println("I am " + atom.getName());
        atom.attack();
        atom.move();

        System.out.println();

        System.out.println("I am " + gundam.getName());
        gundam.attack();
        gundam.move();

    }
}


Reference

cURL 사용 시 데이터(text/plain, x-www-form-urlencoded 또는 json)를 같이 보내는 법을 알아보자.


환경

  • Linux
  • cURL


cURL

옵션을 사용해 데이터를 포함한 요청 보내기

  • -d 옵션을 사용
curl -X<VERB> '<PROTOCOL>://<HOST>:<PORT>/<PATH>?<QUERY_STRING>' -d '<BODY>'


사용 예제

text/plain

  • -d 옵션을 사용하고 POST 방식으로 text 형태의 자료를 보내는 예제
curl -XPOST -H "Content-Type: text/plain" -d "raw text data" http://127.0.0.1:5000/test

application/x-www-form-urlencoded

  • -d 옵션을 사용하고 POST 방식으로 x-www-form-urlencoded 형태의 자료를 보내는 예제
curl -XPOST -H "Content-Type: application/x-www-form-urlencoded" -d "param1=value1&param2=value2" http://127.0.0.1:5000/test

application/json

  • -d 옵션을 사용하고 POST 방식으로 JSON 형태의 자료를 보내는 예제
curl -XPOST -H "Content-Type: application/json" http://127.0.0.1:5000/test -d '
{
   "test": "1234test",
   "child": {
      "child_1": "Hi",
      "cihld_2": "Hi"
   },
   "elements": [ "a", "b", "c" ]
}
'


참고자료

Summarize how to attach data(text/plain, x-www-form-urlencoded or json) when using cURL


Environment and Prerequisite

  • Linux
  • cURL


cURL

Send request with data using option

  • Use -d option.
curl -X<VERB> '<PROTOCOL>://<HOST>:<PORT>/<PATH>?<QUERY_STRING>' -d '<BODY>'


Usage Example

text/plain

  • Example of sending text format data with using -d option and POST method.
curl -XPOST -H "Content-Type: text/plain" -d "raw text data" http://127.0.0.1:5000/test

application/x-www-form-urlencoded

  • Example of sending x-www-form-urlencoded format data with using -d option and POST method.
curl -XPOST -H "Content-Type: application/x-www-form-urlencoded" -d "param1=value1&param2=value2" http://127.0.0.1:5000/test

application/json

  • Example of sending JSON format data with using -d option and POST method.
curl -XPOST -H "Content-Type: application/json" http://127.0.0.1:5000/test -d '
{
   "test": "1234test",
   "child": {
      "child_1": "Hi",
      "cihld_2": "Hi"
   },
   "elements": [ "a", "b", "c" ]
}
'


Reference

ssh 접속시 host의 key를 확인하지 않고 접속하는 방법을 알아보자.


환경

  • Linux
  • SSH(OpenSSH)


Host Key Checking

  • ssh를 이용해 원격에 있는 서버에 접근할 때 해당 서버에 대한 인증을 위해 로컬에 저장해둔 키와 서버의 키를 비교하는 작업을 진행한다.
  • 이런 작업을 통해 중간자 공격 같은 부분을 예방할 수 있다.


SSH 접속시 Host Key Checking 비활성화

  • 해당 옵션을 사용해도 만약 저장된 서버의 키가 없다면 ~/.ssh/known_hosts에 추가합니다.
  • 저장된 키가 서버의 키와 다르더라도 접속을 진행합니다.


1. ssh 명령어 사용 시 비활성화

  • StrictHostKeyChecking=no 옵션을 이용
ssh -o StrictHostKeyChecking=no [DOMAIN_OR_IP]


2. ssh config 파일을 수정

~/.ssh/config

  • 아래처럼 특정 호스트에 대해 옵션을 추가할 수 있다.
Host twpower-private-server
    HostName [IP ADDRESS]
    StrictHostKeyChecking no
    Port 22
    User [USERNAME]
    IdentityFile [IDENTITY KEY FILE]

/etc/ssh/ssh_config

  • 아래처럼 StrictHostKeyChecking no를 추가하며 *가 있기 때문에 접속하는 모든 호스트에 대해 Key 확인을 하지 않습니다.
  • /etc/ssh/ssh_config 파일은 해당 시스템에 있는 모든 유저에게 적용되는 옵션을 담고 있습니다.
Host *
    StrictHostKeyChecking no


참고자료