#Template Method Pattern

 

 

1. 개념

 

탬플릿 메소드 패턴여러 클래스에서 공통된 행위는 상위 클래스에서 정의하고

하위 클래스에서 각각의 상세부분을 구현하는 것을 말한다. 

 

템플릿이란 큰 구조를 정의한 틀로서

전체적인 틀은 동일하되 상세적인 부분은 다르게 찍어낼 수 있는 것을 말한다.

블로그를 꾸며본 사람은 알겠지만

대부분 블로그들은 여러 디자인의 템플릿을 제공해주고

일정한 틀 안에서 자신만의 블로그를 쉽게 꾸밀 수 있도록 도와준다.

 

이러한 개념을 객체에 적용한다면

여러 객체들은 추상클래스 또는 인터페이스를 통해서

동일한 이름의 메소드를 구현하되

기타 메소드는 각 객체에 맞게 구현하는 것이다.

 

 

2. Why? 왜 사용해야 할까?

 

객체를 생성하다 보면 비슷한 동작을 하는 객체들이 많다.

비슷한 동작을 하는 객체들에서 변하지 않는 부분을 한 번 정의해 놓고

다양해질 수 있는 부분은 하위 클래스에 정의할 수 있는 경우

템플릿 메소드 패턴을 이용하면

코드의 중복을 피할 수 있고

상위 클래스로 묶여있기 때문에

if - else 문을 쓰지 않고 다양한 객체를 생성할 수 있다.

 

 

3. 장단점

 

템플릿 메소드의 장점은 쉬운 확장성에 있다.

일정한 틀이 있기 때문에

추상 클래스를 상속받아

쉽게 하위 클래스를 생성, 추가해 나갈 수 있다.

 

또한 앞서 언급했듯이

로직을 공통화하게 되면

비슷한 알고리즘은 일일히 기술할 필요가 없어져

코드의 중복을 줄일 수 있다.

 

그러나 템플릿 메소드는 조심해야한다.

상위 클래스가 관리하는 하위 클래스가 많을 때

상위 클래스를 수정하게 될 때

모든 하위 클래스들을 일일히 수정해야 하는 상황이 발생한다.

 

 

4. 추가내용

 

템플릿 메소드처럼 상속을 통해 확장하는 패턴이 팩토리 메소드 패턴이다.

두 패턴은 비슷하지만 명확한 차이가 있다.

팩토리 메소드 패턴객체의 생성을 리턴하는 메소드를 만드는 것이고

템플릿 메소드 패턴객체의 행위를 동작하는 공통된 메소드를 만드는 것이다.

 

템플릿 메소드 패턴과 비교할 때 빠지지 않는 패턴은 바로 전략 패턴이다.

전략 패턴은 템플릿 메소드 패턴과 구성은 동일하지만 사용관점이 틀리다고 볼 수 있다.

템플릿 메소드 패턴객체의 행위를 동작하는 공통된 메소드를 만드는 것이고

전략 패턴은 동일 이름의 메소드 중 상황에 맞는 필요한 전략을 사용하는 패턴이다.

 

 

5. 클래스 다이어그램

6. 예제 코드

 

탑 라인에서 티모와 블라디가 맞붙는다.

서로의 스킬과 소환사의 주문을 출력하는 코드를 통해

템플릿 메소드 패턴을 알아보자.

 

먼저 탑라이너라는 추상클래스에는 점멸과 순간이동 메소드가 구현되어 있고

스킬과 궁극기 스킬은 추상 메소드로 명시되어 있다.

public abstract class TopLiner {
	
	public void flashing() {
		System.out.println("점멸!");
	}
	
	public void warp() {
		System.out.println("순간이동!");
	}
	
	public abstract void skill();
	
	public abstract void ultimateSkill();
	
}

 

티모와 블라디는 추상클래스를 상속받아 각자의 스킬을 구현한다.

public class Teemo extends TopLiner{

	@Override
	public void skill() {
		System.out.println("실명!");
		
	}

	@Override
	public void ultimateSkill() {
		System.out.println("독버섯!");
	}

}

public class Vladimir extends TopLiner{

	@Override
	public void skill() {
		System.out.println("수혈!");
		
	}

	@Override
	public void ultimateSkill() {
		System.out.println("혈사병!");
		
	}

}

 

메인 클래스에서 각자의 스킬 및 소환사 주문을 확인하면

다음의 결과가 나온다.

public class SummorsGorge {

	public static void main(String[] args) {
		
		System.out.println("소환사의 협곡에 오신 것을 환영합니다.\n");
		
		TopLiner top1 = new Teemo();
		TopLiner top2 = new Vladimir();
		
		System.out.println("티모 스킬");
		top1.skill();
		top1.ultimateSkill();
		System.out.println("소환사 주문");
		top1.flashing();
		top1.warp();
		
		System.out.println("");
		
		System.out.println("블라디 스킬");
		top2.skill();
		top2.ultimateSkill();
		System.out.println("소환사 주문");
		top2.flashing();
		top2.warp();
		
	}

}

 

 

7. 참고

 

https://leetaehoon.tistory.com/47

https://dlucky.tistory.com/145

https://kimddochi.tistory.com/55

https://hyeonstorage.tistory.com/146

https://rearrangingall.blogspot.com/2017/01/01-strategy-pattern.html

GoF의 디자인 패턴

 

 

Made by 꿩

'스터디 > GoF의 디자인패턴' 카테고리의 다른 글

Chain of Responsibility  (0) 2019.05.06
Strategy Pattern  (0) 2019.04.30
Decorator Pattern  (0) 2019.04.28
Factory Method Pattern  (0) 2019.04.23

#Decorator Pattern

 

 

1. 개념

 

데코레이터 패턴(Decorator pattern)은 객체의 추가적인 요건을 동적으로 추가하는 패턴이다.

Decorator는 글자 그대로 장식가로서, 중심이 되는 객체가 반환하는 값에

추가적으로 더해져서 결과값을 반환합니다. 

 

쉽게 스타벅스를 생각해보자

스타벅스는 자신만의 커스터마이징 음료를 만들 수 있다.

나같은 경우는 그린 티 크림 프라푸치노(Green Tea Cream Frappuccino)를 주문해서

에스프레소 샷 추가, 저지방 우유, 라이트 시럽, 휘핑크림, 자바칩 갈아 만든

커스터마이징 음료를 산다.

 

이와 같이 하나의 객체에 옵션들을 여러개 추가해서

만드는 패턴을 장식하는 것과 같다하여

데코레이터 패턴이라 한다.

 

 

 

(출처: http://i.stack.imgur.com/O7pqc.png )

 

2. Why? 왜 사용해야 할까?

 

하나의 객체에 부가적인 기능을 덧붙여야 할 때가 있다.

또한 동일한 객체를 여러개 만들어야 하지만

각기 다른 기능을 첨가할 필요가 있을 때

데코레이터 패턴을 이용하면

많은 객체에게 다양한 부가기능을 쉽고 빠르게 적용할 수 있다.

 

 

 

 

3. 장단점

 

데코레이터 패턴의 핵심은

중심이 되는 객체를 놔두고 추가적인 사항을 첨가하는 방식이라

객체에 기능을 추가 또는 삭제 할 때

 중심이 되는 객체를 수정하지 않고 동적으로 추가 또는 삭제할 수 있다.

객체지향의 원칙 중 OCP에 충실한 패턴인데

OCP는 Open-Close Principle로서 확장에는 열려있고 변경에는 닫혀 있어야 한다는 원칙이다.

 

데코레이터 패턴을 사용하게 되면

기존 객체는 변경하지 않고 자유로운 확장을 구현할 수 있으며

기존 객체가 수정되더라도 또는 데코레이터가 수정되더라도

해당 클래스의 내용만 수정해주면 되기 때문에 변경에 대해서도 닫혀있다.

 

또한,

기본적인 데이터에 첨가하는 데이터가 일정하지 않고 다양할 때

데코레이터 패턴을 사용하면 효율적으로 사용할 수 있다.

 

반면에

데코레이터를 너무 많이 사용하게 되면

자질한 객체가 많이 추가될 수 있고

오히려 코드가 복잡해 질 수 있다는 단점이 있다.

 

 

4. 추가내용

 

비슷하게 확장을 하는 상속과 데코레이터 패턴의 차이는 무엇일까?

상속은 하위 클래스를 생성하는 방법으로 확장을 하며

데코레이터 패턴은 기본 객체에 추가하는 객체를 생성하는 방법으로 확장을 한다.

상속은 오버라이딩을 통해 기능을 전부 명시해 줘야 하지만

데코레이터 패턴은 기본 기능은 놔두고 추가되는 기능만 명시해 줄 수 있다는 차이가 있다.

 

데코레이터 패턴은 여러 패턴들과 유사한 구조를 가지고 있다.

 

다양하고 일정하지 않은 여러 객체들을 하나의 객체로 묶는 것Composite 패턴이라 하는데

데코레이터 패턴은 한 구성요소 만을 갖는 Composite 패턴이라 볼 수 있다.

그러나 목적에서 차이가 있다.

Composite 패턴은 목적이 생성되어 있는 객체들 간의 합성에 있고

데코레이터 패턴은 목적이 객체에 새로운 행동을 추가하는 데에 있다.

 

Strategy 패턴유사한 행위를 캡슐화하는 인터페이스를 정의하여

객체들의 행위를 유연하게 확장하는 방법으로 데코레이터 패턴과 구조가 비슷하다.

하지만 Strategy 패턴은 객체의 내부를 변화시키며

데코레이터 패턴은 새로운 객체를 추가하여 객체를 변경한다는 점에서 차이가 있다.

 

마지막으로 Adaptor 패턴서로 다른 인터페이스를 통일시켜 사용하는 패턴으로서

데코레이터가 기준 객체와 부가 객체를 연결하는 어댑터 역할을 하는 것과 유사하다.

그러나 데코레이터 패턴은 어댑터 패턴과 달리 인터페이스를 변경 없이

객체에 새로운 행동을 추가한다는 점에서 차이가 있다.

 

 

5. 클래스 다이어그램

 

 

6. 예제 코드

 

스타벅스에서 그린티 크림 프라푸치노에

샷추가, 저지방 우유, 자바칩을 추가했을 때 가격을 알아본다.

 

public interface StarbucksMenu {
	
	public int cost();

}

public class GreenTeaCreamFrappuccino implements StarbucksMenu{
	
	public GreenTeaCreamFrappuccino() {
		System.out.println("그린티 크림 프라푸치노를 선택하셨습니다.");
	}

	@Override
	public int cost() {
		System.out.println("그린티 크림 프라푸치노 가격 : 5000");
		return 5000;
	}

}

public abstract class CoffeeDecorator implements StarbucksMenu{

	public abstract int cost();
	
}

스타벅스 메뉴 인터페이스에

기본메뉴인 그린티 크림 프라푸치노와

부가메뉴인 커피데코레이터가 연결되어있다.

 

public class EspressoShot extends CoffeeDecorator{
	
	StarbucksMenu starbucksMenu;

	public EspressoShot(StarbucksMenu starbucksMenu) {
		System.out.println("샷 추가 + 1000원 추가");
		this.starbucksMenu = starbucksMenu;
	}

	@Override
	public int cost() {
		return starbucksMenu.cost() + 1000;
		
	}
}

public class JavaChip extends CoffeeDecorator{
	
	StarbucksMenu starbucksMenu;

	public JavaChip(StarbucksMenu starbucksMenu) {
		System.out.println("자바 칩 +500원 추가");
		this.starbucksMenu = starbucksMenu;
	}

	@Override
	public int cost() {
		return starbucksMenu.cost() + 500;
	}
}

public class LowFatMilk extends CoffeeDecorator{
	
	StarbucksMenu starbucksMenu;

	public LowFatMilk(StarbucksMenu starbucksMenu) {
		System.out.println("저지방 우유 +300원 추가");
		this.starbucksMenu = starbucksMenu;
	}

	@Override
	public int cost() {
		return starbucksMenu.cost() + 300;
	}
}

추상클래스인 커피데코레이터의 구현은

자식클래스인 자바칩, 저지방우유, 에스프레소샷에 구현된다.

 

public class Customer {

	public static void main(String[] args) {
		System.out.println("그린티 프라푸치노에 자바칩, 저지방우유, 샷 추가 해주세요.");
		
		StarbucksMenu order = new EspressoShot(new LowFatMilk(new JavaChip(new GreenTeaCreamFrappuccino())));
		
		System.out.println("총 가격은 " + order.cost() + "입니다.");
	}
}

고객이 위와 같이 주문을 하면

기본 메뉴를 먼저 생성한 후

기본 메뉴에 추가메뉴를 더해 총 가격을 구할 수 있다.

결과 창은 다음과 같다.

 

7. 참고

https://lalwr.blogspot.com/2016/02/decorator-pattern.html

https://secretroute.tistory.com/entry/Head-First-Design-Patterns-%EC%A0%9C3%EA%B0%95-Decorator-%ED%8C%A8%ED%84%B4

https://meaownworld.tistory.com/91

https://meylady.tistory.com/53

https://free-strings.blogspot.com/2016/04/adapter-decorator-facade-proxy.html

https://jusungpark.tistory.com/9

 

Made by 꿩

'스터디 > GoF의 디자인패턴' 카테고리의 다른 글

Chain of Responsibility  (0) 2019.05.06
Strategy Pattern  (0) 2019.04.30
Template Method Pattern  (0) 2019.04.30
Factory Method Pattern  (0) 2019.04.23

#Factory Method Pattern

 

 

1. 개념

 

팩토리 메서드 패턴(Factory method pattern)은 객체를 생성하는 공장을 만드는 것으로서

어떤 객체를 만드는 지는 자식클래스에서 결정하게 하는 디자인 패턴이다.

 

 

2. Why? 왜 사용해야 할까?

 

그렇다면 이 팩토리 메서드 패턴을 왜 사용해야 할까?

한마디로 말하자면

객체 간의 결합도를 낮추고 유지보수를 용이하게 하기 위해서이다.

 

객체만 생성하는 공장을 통해서 간접적으로 객체를 생성하게 하며

인터페이스를 정의하되, 실제 구현내용은 자식클래스에서 구현이 되므로

세부 구현 코드를 몰라도 부모클래스에서 자유롭게 사용이 가능하여

객체 간의 결합도가 낮아지는 효과를 볼 수 있다.

 

객체 간의 결합도가 낮춰진다는 말은

한 클래스에 변화가 생겼을 때 다른 클래스에 영향이 끼치는 정도가 낮아진다는 말이고

유지보수를 할 때 최소의 클래스만 수정이 가능하게 되어

유지보수가 용이하게 되는 결과를 낳는다.

 

3. 장점

 

팩토리 메서드 패턴은

직접 객체를 생성하는 것이 아니라

객체만을 생성하는 공장을 만들어서

객체 생성을 중간 매개체인 공장에서 불러오는 것이다.

객체들은 한 공장에서만 생성되기 때문에

객체들을 한 곳에서 관리할 수 있다는 장점이 있으며

객체의 생명주기를 관리하기 쉬워진다.

 

동일한 인터페이스에서 구현이 되기 때문에

새로운 클래스가 추가되거나 확장하게 되어도

기존 소스코드를 변경할 필요 없이 새로운 하위 클래스를 만들면 되기 때문에

새로운 객체를 생성하는 것보다 유연하고 확장성 있는 구조가 된다.

 

프로그램 내에서 동일한 객체의 호출이 잦고

객체를 생성하는 비용이 클경우

객체를 반복하여 반환하여 사용할 경우 성능을 높일 수 있다.

 

또한,

생성자가 아닌 메소드로 작동하기 때문에 리턴 값을 가질 수 있다.

이는 리턴 값으로 상황에 따라 서로 다른 객체를 반환 할 수 있다는 뜻이다.

객체를 선택함에 있어서 유연함을 가질 수 있는 방법이다.

 

 

4. 단점

 

다만, 팩토리 메서드는 계속해서 새로운 하위클래스를 정의한다는 점이 있다.

이는 불필요하게 많은 클래스를 정의하게 될 수 있고

이로 인해 복잡해 질 수 있다는 단점이 있다.

 

 

5. 클래스 다이어그램

 

 

6. 예제 코드

 

우선, Furniture 인터페이스 하위에 DeskMaker, ChairMaker, BedMaker 하위 클래스가 존재한다.

public interface Furniture {
	
	public void make();
	
	public void newDesign();

}

public class DeskMaker implements Furniture{

	public DeskMaker() {
		System.out.println("책상메이커 삼삼대기");
	}

	@Override
	public void make() {
		System.out.println("책상을 만들었습니다.");
	}
	
	@Override
	public void newDesign() {
		System.out.println("새로운 책상 디자인을 연구합니다.");
		
	}
}

public class ChairMaker implements Furniture{

	public ChairMaker() {
		System.out.println("의자메이커 삼삼대기");
	}
	
	@Override
	public void make() {
		System.out.println("의자를 만들었습니다.");
	}
	
	@Override
	public void newDesign() {
		System.out.println("새로운 의자 디자인을 연구합니다.");
		
	}
}

	public BedMaker() {
		System.out.println("침대메이커 삼삼대기");
	}

	@Override
	public void make() {
		System.out.println("침대를 만들었습니다.");
	}

	@Override
	public void newDesign() {
		System.out.println("새로운 침대 디자인을 연구합니다.");
		
	}
}

 

클라이언트, 즉 Ikea는 각 가구를 생성하기 위해 IkeaFactory를 통해 객체를 불러들인다.

IkeaFactory는 입력받은 값으로 불러올 객체를 구분한다.

public class Ikea {

	public static void main(String[] args) {
		
		IkeaFactory ikeaFactory = new IkeaFactory();
		
		System.out.println("주문 1: 책상 생성");
		ikeaFactory.order("책상").make();
		
		System.out.println("주문 2: 의자 생성");
		ikeaFactory.order("의자").make();
		
		System.out.println("주문 3: 침대 디자인 연구");
		ikeaFactory.order("침대").newDesign();
		
	}

}

public class IkeaFactory {
	
	public Furniture order(String type){
		
		if (type == "침대") {return new BedMaker();}
		if (type == "의자") {return new ChairMaker();}
		if (type == "책상") {return new DeskMaker();}
		
		return null;
		
	}

}

 

main으로 부터 나온 결과값은 다음과 같다.

 

7. 참고

http://egloos.zum.com/ani2life/v/2887675

https://m.blog.naver.com/itperson/220885347418

https://xxxelppa.tistory.com/36

http://egloos.zum.com/sakula99/v/2976589

 

Made by 꿩

'스터디 > GoF의 디자인패턴' 카테고리의 다른 글

Chain of Responsibility  (0) 2019.05.06
Strategy Pattern  (0) 2019.04.30
Template Method Pattern  (0) 2019.04.30
Decorator Pattern  (0) 2019.04.28

#The Good Fight

 

내 인생 스토리에서 미드는 결코 빠질 수 없는 필수요소이다.

몇몇 사람들은 내가 포켓몬을 좋아하는 줄 알지만

그건 재미를 위해 사용하는 요소일 뿐이고

내가 진정으로 좋아하는 것은 바로 미국드라마이다.

(가끔 미드를 보며 나는 미드를 보기 위해 인간으로 태어난 게 아닐까라는 생각을 한다;;ㅎㅎ)

 

이번 포스팅은 The Good Fight라는 미드를 소개해보는 글을 써볼까한다.

 

The Good FightThe Good Wife의 스핀오프 드라마이다.

The Good Wife의 배경과 등장인물에 기초하여 새로운 드라마를 만들어낸 것이다.

 

The Good Fight의 주인공은 The Good Wife의 서브 캐릭터였던

Diane LockHart를 중심으로 새로운 변호사들이 등장한다.

기존의 The Good Wife가 Alicia Florrick이라는 주인공을 기반으로 풀어낸 드라마였다면

The Good Fight에서는 주인공이 한 명이 아니다.

 

Diane LockHart

 

Lucca Quinn

 

Maia Lindell

 

기본적으로 이 3명의 변호사가 주인공으로 이루어져있지만

 

Adrian Boseman, Liz Riddick, Colin morello, Marissa Gold, Jay Dipersia

이들도 조연보다도 거의 주인공급으로 나온다.

 

The Good FightThe Good Wife의 단점을 버리고 장점을 모두 흡수했다.

The Good Wife도 굉장히 잘 만든 작품이지만

동료와 변호사 간의 권력다툼, 배신, 음모 등 지나치게 부정적인 면이 많았다.

이러한 점은 드라마를 한 번은 보게끔 만들지만

여러번 보는 것은 꺼려지게 만든다.

이건 당연한 현상이다.

인간이란 이기적인 동물이라

부정적인 면은 꺼려하고 긍정적인 면을 보고 싶어한다.

 

The Good FightThe Good Wife의 이러한 문제점을 개선했다.

물론 인간의 부정적인 요소를 완전히 없애지는 못했다.

 

시즌 1을 보면 아직도 The Good Wife의 잔재인 동료간의 불화합을 볼 수 있지만

시즌 2부터 이런 잔재를 싹 없앤 The Good Fight의 방향을 뚜렷히 볼 수 있었다.

시즌1에서 Diane을 싫어하던 Barbara Kolstad 캐릭터가

시즌2에서 다른 로펌으로 떠나도록 했고

Adrian은 리더로써 동료 간의 연결고리 역할을 해주며

항상 동료애를 강조한다.

 

시즌 2 마지막 에피소드에서 Lucca는 자신의 아파트 앞에서 기다리고 있는

Maia와 Marissa를 보고 기쁜 표정으로 'I want them here'라고 얘기하는 장면이 있다.

앞으로 The Good Fight가 어떤 방향으로 스토리를 이끌어 나갈지 예상되는 마지막 장면이었다.

 

The Good Wife의 가장 강력한 요소는 바로 매력 넘치는 조연들이다.

 

치명적인 매력을 가진 싸이코 아내살인범 Colin Sweeney

 

내가 가장 사랑하는 캐릭터인 3차원 별종 변호사 Elsbeth Tascioni

 

쾌활한 매력과 핵인싸의 모습을 보여주는 Marissa Gold

 

등 이들을 한치의 수정없이 그대로 흡수했다.

이전에 조연이었던 Lucca와 Diane은 주인공이 되었으며

Marissa는 조연이라긴 애매하고 주인공이라기에는 조금 부족한 서브 주인공이 되었다.

또한 Felix Staples등처럼 기존에 보지 못했던 새로운 조연을 가미하면서

더욱더 Yummy한 드라마가 되었다.

 

개인적으로 Carry Agos와 Kalinda Sharma가 등장하지 않는다는 게 아쉽긴 했다.

나중에라도 깜짝 게스트로 그들의 활약을 볼 수 있었으면 좋겠다.

 

처음 The Good Fight를 봤을 때 깜짝 놀랐다.

Diane이 흑인 로펌에 들어가서 새로운 시작을 하는 설정 때문이었다.

기존의 The Good Wife의 Lockhart & Gardner가 철저히 White Base의 로펌이었다면

The Good Fight의 Riddick & Boseman은 철저한 African-American Base의 로펌이다.

속으로는 스핀오프 드라마를 기획하면서 투자자가 흑인으로 바뀌었나라는 생각이 들었지만

굉장히 신선한 설정이었다.

 

기존 The Good Wife의 백인 상류층의 로펌 느낌이 완전히 사라지고

좀더 서민을 위한 로펌이라는 느낌이 많이 들었기 때문이다.

 

The Good WifeThe Good Fight는 절대 빠지지 않고 나오는 것이 있다.

바로 Diversity이다.

첫번째로 레즈비언은 항상 나온다.

Karlinda가 The Good Wife에서 레즈비언 역할이었다면

Maia가 The Good Fight에서 레즈비언 역할을 한다.

 

두번째는 Interracial Love이다.

항상 잘생긴 백인 남자가 다른 인종의 여성을 사랑한다.

Carry Agos가 Karlinda를 사랑했고

Colin은 Lucca를 사랑한다.

TV 드라마의 Diversity를 고려해 만든 설정인지는 모르겠지만

비슷한 설정을 계속 그대로 가져간다는 느낌이 든다.

 

최종적으로 정리하자면

The Good Wife는 Alicia가 역경을 헤쳐나가는 과정과 선택의 과정 및 성격의 변화를 잘 그려냈다.

그러나 동료간의 불화가 도를 넘어섰고 음모, 배신, 정치싸움 등

인간의 더러운 욕망과 이기심을 적나라하게 볼 수 있으며

드라마를 계속해서 보기 불편하게 만든다.

 

The Good FightThe Good Wife의 매력 넘치는 조연들을 모두 흡수했으며

변호사들 간의 의리와 정이 넘치는 팀워크를 볼 수 있다.

현재 시즌 3이 방영중인데

개인적인 바람으로 오래오래 방영했으면 좋겠다.

Elsbeth 분량도 좀 많이 넣어주고 ㅎㅎㅎ

 

To be continued.........

 

Made by 꿩

#SSL인증서



포켓몬스터 게임을 하다보면

통신교환을 해야 최종진화가 되는 포켓몬들이 있다.

나는 어떻게 하는지도 모르고

방법도 귀찮아서 통신교환을 전혀 하지 않아

후딘, 강철톤, 괴력몬 등을 한번도 키워본 적이 없다.

진화의 돌 진화나 레벨업 진화만 있었으면 좋겠다.



통신교환을 하는 것은 데이터를 주고 받는 행위이다.

근데 이 데이터를 주고 받을 때

누가 가로채거나 엿본다면 데이터가 유출된다.


HTTP 통신에서도 마찬가지이다.

HTTP 통신은 암호화되지 않은 방법으로 통신하기 때문에

데이터가 쉽게 유출된다.


HTTP의 보안상 문제점을 보완하기 위해 나온 것이 HTTPS이다.

HTTPS는 SSL 프로토콜 위에서 돌아가는 프로토콜을 말하는데

쉽게 말하자면

SSL 인증서를 이용하여 웹에서 데이터를 암호화하여 주고 받을 수 있게 해준다.

SSL 인증서의 역할은 2가지이다.

첫째, 인증서 정보를 통해서 신뢰할 수 있는 서버인지 인증하는 것

둘째, 공개키로 데이터를 암호화하는 것


우선 대칭키와 공개키에 대해서 알아둘 필요가 있다.

대칭키는 암호화, 복호화 모두 하나의 키로 가능하다.

그렇기 때문에 대칭키가 유출이 되면 암호화 하는 의미가 없어진다.


반대로 공개키는 2개의 키 쌍으로 이루어져있다.

보통 다른 사람에게 공개하는 것을 공개키

나만 알고있는 것을 비밀키라 한다.

하나의 키로 암호화를 하게 되면

복호화는 다른 하나의 키로만 가능하다.

두 개의 키 모두 암호화, 복호화가 되지만

자신의 키로 암호화한 것을 복호화할 수 없고

다른 키로 암호화가 된 것만을 복호화 할 수 있다.


공개키와 대칭키에 대해 알아봤다면

SSL 인증서의 동작과정을 살펴보자.



첫번째 과정은 핸드쉐이킹이다.

이 과정은 본격적으로 데이터를 주고 받기 전에

서로가 지원하는 암호화 방식을 알아내고

데이터를 암호화하는 세션 키를 찾는 과정이다.


클라이언트가 서버에 접속을 하게 될 때

클라이언트는 자신이 사용할 수 있는 암호화 방식과

클라이언트가 생성한 랜덤 데이터를 서버에 전송한다.


서버는 클라이언트에게 받은 암호화 방식 중 자신이 지원가능한 암호화 방식을 고른다.

그리고 다시 클라이언트에게

서버가 고른 암호화 방식과

서버가 생성한 랜덤 데이터,

비밀키로 암호화된 SSL 인증서를 전송한다.


클라이언트는 SSL 인증서가

CA에 의해 발급된 인증서인지 확인하고

이미 내장된 CA의 공개키를 이용해 SSL 인증서를 복호화한다.

복호화가 정상적으로 되었다면

해당 서버는 CA에서 인증된 SSL 인증서를 가진 서버라는 것을 인증되는 것이다.


해당 서버가 신뢰할 수 있는 판단이 되는 순간

클라이언트는 자신이 생성한 랜덤 데이터와 서버가 생성한 랜덤 데이터를 조합하여

pre master secret이라는 키를 생성한다.

pre master secret을 공개키로 암호화를 하여 서버에 보내면

서버는 pre master secret을 비밀키로 복호화를 하게 된다.


클라이언트와 서버 모두 pre master secret을 이용하여 master secret을 만들고

master secret을 이용하여 세션 키를 만들게 된다.


여기까지가 핸드쉐이킹 단계이며

다음은 핸드쉐이킹 단계에서 만들었던 세션 키를 가지고

데이터를 암호화하여 주고 받는 세션 단계이다.


세션 단계에서 사용되는 세션 키는 대칭키로 암호화와 복호화가 모두 가능하다.

이미 핸드쉐이킹 단계에서 공개키를 이용한 방식으로 세션키를 만들었기 때문에

세션키를 외부로 노출할 일은 없게 된다.


결국 HTTPS는 공개키와 대칭키를 혼합하여 사용한다.

공개키는 대칭키를 암호화하여 전달하는데 사용이 되고

대칭키는 실제 데이터를 암호화하여 송수신하는데 사용이 된다.

공개키는 많은 컴퓨팅 파워를 사용하기 때문에

실제 데이터를 암호화하여 주고받는 방식은 대칭키를 이용한 방식이 더 좋다.


데이터 전송이 모두 끝나게 되면

통신에 사용하게 된 세션키는 폐기된다.


시간이 된다면 AWS를 이용하여

SSL 인증서로 HTTPS 서버를 구축해보는 것도 좋은 연습이 될 것 같다.


<참고자료>

https://opentutorials.org/course/228/4894


To be continued.........




Made by 꿩

'IT > 보안' 카테고리의 다른 글

[방화벽] 인바운드 & 아웃바운드  (0) 2022.01.31
[Spring] Google reCAPTCHA v3  (6) 2019.07.07
OAuth  (0) 2019.06.17
CSRF  (0) 2018.12.25
XSS 공격과 방어  (2) 2018.10.25

#Hash Table



해시란 무엇일까?

위키피디아에 따르면 해시 함수에 의해 얻어진 값을 해시라 한다.

그럼 해시 함수란?

임의의 길이의 데이터를 고정된 길이의 데이터로 매핑하는 함수를 말한다.

마지막으로 해시 테이블이란?

해시를 이용한 테이블이겠지..ㅎ


해시 테이블은 해시 값이 인덱스가 되도록 원래의 키 값을 저장한 배열을 말한다.

좀 더 쉽게 풀어서 설명하자면

데이터를 어떠한 알고리즘으로 고유한 숫자를 만든다.

그리고 이것을 인덱스로 사용해 저장하는 방법이다.

배열을 사용하여 데이터를 저장하며

데이터 고유의 인덱스로 접근하게 되므로

매우 빠른 검색 속도를 갖는 자료구조이다.


이미 배열이 생성되어 있고 비어있는 곳을 굳이 채워 넣을 필요가 없기 때문에

삽입 또는 삭제도 효율적으로 수행할 수 있다.

물론 이때문에 충분한 메모리 공간이 필요하다는 단점이 있다.


포켓몬 이름으로 포켓몬의 정보를 해시방법으로 저장한다고 가정해보자.

샤미드, 쥬피썬더, 부스터를 각 이름을 해시 함수에 넣어 인덱스를 구하고

해당 인덱스에 데이터를 저장한다.

나중에 해당 포켓몬의 정보를 얻을 때

이름만 입력하면 바로 데이터를 가져올 수 있다.


그런데 해시 함수의 결과 값은 항상 고유값은 아니라는 문제가 있다.

중복값이 발생할 때를 해시 충돌이라 하고 보통 두가지 해결 방법이 제시된다.

다음과 같이 충돌이 난다고 가정해보자.

버터플과 도나리 모두 해시함수에 넣었을 때

동일한 인덱스 값이 나온다.


이처럼 해시 충돌에 대한 첫번째 해결 방법은 Separate Chaining 방식이 있다.

이는 나중에 들어온 데이터를 추가하는 방법이다.

LinkedList 또는 Tree를 사용하는 방식이 있다.

이 둘을 사용하는 기준은 버킷에 할당된 key-value 쌍의 개수이다.

트리는 기본적으로 메모리 사용량이 많고

데이터 개수가 적을 때

Worst Case를 살펴보면 이 둘의 성능 상 차이가 거의 없으므로

메모리 측면에서 볼 때 LinkedList를 사용하는 것이 맞다.


LinkedList를 이용하면 다음과 같이 저장이 된다.


두번째 방법은 Open Address 방식이 있다.

해시 충돌이 발생하면 다른 해시 버킷에 해당 데이터를 삽입하는 방식이다.

이 방법에서 또 3가지로 나뉘어진다.


1. Linear Probing: 순차적으로 비어있는 버킷 탐색

2. Quadratic Probing: 선형 탐사와 비슷하지만 폭을 제곱수로 넓게 탐색

3. Double hashing Probing: 해시 출동 발생 시 2차 해시 함수 이용하여 새로운 주소 할당


 이중 Linear Probing으로 충돌을 해결하면 다음과 같이 저장된다.


그렇다면 어떤 기준을 가지고 Separate Chaining과 Open Addressing을 사용해야 할까?

둘 모드 Worst Case O(M)이다.

그러나 Open Addressing은 연속된 공간에 데이터를 저장하기 때문에

Separate Chaining보다 캐시 효율이 높다.


따라서 데이터 개수가 적다면 Open Addressing이 성능이 좋지만

데이터 개수가 커질수록 Worst Case 발생빈도가 높아지기 때문에

Open Addressing이 Separate Chaining보다 느려진다.

Separate Chaining은 충돌 빈도를 보조 해시 함수를 이용하여 조절할 수 있기 때문에

Worst Case에 가까운 일이 발생하는 것을 줄일 수 있다.

(보조 해시 함수는 key의 해시 값을 변형하여 해시 충돌 가능성을 줄이는 것이다)


해싱에는 정적 해싱과 동적 해싱이 있다.

정적 해싱은 데이터를 입력하기 전에 일정 크기의 메모리를 미리 할당받는 것이며

해시 테이블의 크기가 할당된 메모리의 크기를 넘어갈 수 있다.


이러한 문제점을 해결하기 위해서 동적 해싱이 등장했는데

동적해싱은 오버플로우 발생시 버킷 안의 엔트리들 재조정하고

동적으로 해시 테이블의 크기를 변화시키면서 성능을 높여주는 방법이다.


동적 해싱은 데이터가 증가해도 검색의 성능이 유지되고 메모리 낭비를 줄일 수 있다는 장점이 있지만

로직이 복잡하고 버킷을 쪼개거나 합치는 과정 중에 부하가 발생하는 단점도 가지고 있다.


참고

https://k39335.tistory.com/18

https://d2.naver.com/helloworld/831311

http://blog.naver.com/PostView.nhn?blogId=skyjjw79&logNo=220875535595&parentCategoryNo=&categoryNo=61&viewDate=&isShowPopularPosts=true&from=search

To be continued.........




Made by 꿩













#[Firebase] FCM 푸시 메세지 - Notification



프로젝트 도중 Firebase FCM을 적용하다가

내가 올린 포스팅으로는 설명이 좀 부족하다는 죄책감이... ㅎ

이번 글에서는

기존 포스팅에 올린 것을 좀 더 상세히 설명할 것이다.


부디 잘 참고해서

적용하기 바람 ㅎㅎ


1. firebase-messaging-sw.js

firebase-messaging-sw.js는 service worker 파일이다.

크롬에서 F12 -> Application -> Service Workers에

firebase-messaging-sw.js이 있다면 정상작동하는 것이다.



FCM을 통해 푸시메세지를 보냈을 때

사용자가 브라우저를 꺼놓거나 다른 페이지 화면을 보고 있을 경우

이 service worker에 등록되어있는 파일이 작동하는 것이다.


2. Background

다음은 저번 포스팅때 올린 코드의 일부분이다.


1
2
3
4
5
6
7
8
9
10
11
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function(payload){
 
    const title = "Hello World";
    const options = {
            body: payload.data.status
    };
 
    return self.registration.showNotification(title,options);
});
 
cs


FCM으로 데이터가 들어오면 Notification을 보여주는 코드이다.

BackgroundMessageHandler라는 용어를 볼 때,

백그라운드 상태일 때 동작한다는 것을 알 수 있다.


3. foreground

그렇다면 백그라운드의 반대인 포그라운드 상태일 때는???

그 동작을 onMessage에서 관리한다.

다음은 포그라운드 상태일 때 메세지 동작 코드이다.


1
2
3
4
5
6
7
8
9
messaging.onMessage(function(payload){
        console.log('onMessage: ', payload);
        var title = "고라니 서비스";
        var options = {
                body: payload.notification.body
        };
        
        var notification = new Notification(title, options);
});
cs


이 코드를 원하는 html 페이지에 삽입한다면

해당 페이지로 직접 <div>를 설정하여 실시간으로 메세지를 보여주던가

alert창 또는 나처럼 Notification을 새로 생성해도 된다.

브라우저 마다 Notification 지원기능이 다르기 때문에 다음 표를 참고하기 바란다.



4. options

Notification에는 다양한 옵션을 지정해 줄 수 있다.

https://developer.mozilla.org/en-US/docs/Web/API/notification/Notification

이 링크에 들어가면 굉장히 많은 옵션을 Notification에 줄 수 있다는 것을 알 수 있다.

난 그중에서 icon 옵션을 써봤는데

코드는 option에 icon만 추가해주면 된다.


1
2
3
4
5
6
7
8
9
10
messaging.setBackgroundMessageHandler(function(payload){
 
    const title = "고라니 서비스";
    const options = {
            body: payload.notification.body,
            icon: payload.notification.icon
    };     
    
    return self.registration.showNotification(title,options);
});
cs


icon 주소를 잘 보냈다면

다음처럼 푸시메세지에 이미지가 들어갈 것이다.



동그랗게 고라니 그림이 들어간 것을 볼 수 있다.

참고로

나는 웹 앱을 만들어서 AWS를 이용해 서버를 올렸다.

그래서 스마트폰으로 푸시메세지를 테스트 할 수 있었다.

모바일 환경과 데스크톱 환경은 생각보다 다른 점이 많아서

정말 며칠동안 FCM 하나가지고 삽질을 했다 ㅠㅠ

단순히 기능이 된다고 끝이 아니라

기능 구현하는 코드를 이해해야

해당 기능을 자신의 프로젝트에 맞게 구현할 수 있다는 것을 명심해야 한다.



To be continued.........




Made by 꿩

'Database > Firebase' 카테고리의 다른 글

[Firebase] FCM 푸시 메세지  (1) 2018.12.09

#CSRF



CSRF는 Cross-site request forgery로 사이트 간 요청 위조라 불린다.


위키피디아의 설명에 의하면,

사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위를

특정 웹사이트에 요청하게 되는 공격이라 한다.



나만의 언어로 바꿔보자면

인터넷뱅킹에 로그인한 상태에서

메일을 들어가보니까

평소 내가 사고 싶었던 100cm 냐옹 인형을 싸게 구입할 수 있다는 광고메일이 왔어.

나는 궁금해서 링크를 클릭하겠지?

나는 냐옹 인형을 구입할 수 있는 웹사이트를 요청했지만

알고 봤더니

해커에게 돈을 송금한 요청이 보내진거지.


옥션 사례가 대표적인데

관리자가 로그인을 한 상태이고

자주 가는 사이트가 있었다.

공격자가 사이트에 악성스크립트를 넣은 글을 올렸고

관리자가 그 글을 본 순간

아이디와 비밀번호가 해커는 관리자권한을 획득했고

해커는 관리자로 로그인을 하여 개인정보 데이터를 빼내온 것이다.

XSS와 CSRF는 비슷하면서도 다르다.

둘 모두 악성 스크립트를 이용한다는 점은 동일하지만

XSS는 사용자의 화면에서 악성 스크립트가 실행되는 것이고

CSRF는 사용자 권한을 이용해 악성 스크립트를 서버에 요청을 한다는 점이 다르다.


마치

도둑이 내 물건을 훔쳐간 것과

보이스피싱처럼 내가 도둑에게 돈을 송금해 준 것

이 차이랄까?



물론 CSRF 공격을 막는 방법도 있다.

그 중 하나가 CSRF 토큰을 이용한 방법이다.

CSRF 토큰은 랜덤으로 들어가는 키값인 난수이다.


화면 호출 시 세션에 CSRF 토큰인 난수값이 저장된다.

해당 화면에 대한 요청이 들어올 때

CSRF 토큰 값과 비교해서

토근 값이 일치하면 요청을 실행하고

그렇지 않으면 해당 요청을 막는 방법이다.



앞서 언급한 예시를 이용해 설명해본다면

인터넷뱅킹에 로그인한 상태로 메일의 링크를 클릭했어

근데 그 링크는 해커에게 돈을 송금하도록 요청하는 링크야

서버에서 해커에게 송금하라는 요청을 받았는데

송금하는 화면에서 생성되는 CSRF 토큰을 검사해

근데 해커가 미리 지정한 메일의 링크에 CSRF 토큰인 난수값이 없으면

요청이 금지되는 거지


해커 입장에서는 CSRF 토큰은 난수값으로

랜덤으로 생성되므로 알 수 있는 방법이 없지

그래서 메일 링크에 CSRF 토큰값을 넣을 수가 없어

물론 천재 해커들은 뚫을 방법을 찾을 수도 있겠지만....ㅎ

내가 프로젝트를 수행하면서

CSRF 토큰을 지정하는 방법은 두가지이다.


첫번째는 input hidden으로 넣는방법

1
<input type="hidden" id="csrfToken" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
cs

두번째는 ajax요청시 header에 csrf 토큰을 넣는 방법(javascript)

1
2
3
4
5
6
7
8
9
10
11
<meta id="_csrf" name="_csrf" th:content="${_csrf.token}"/>
<meta id="_csrf_header" name="_csrf_header" th:content="${_csrf.headerName}"/>    
    
    //여기부터는 자바스크립트 
    var csrftoken = $('#_csrf').attr('content');
    var csrfheader = $('#_csrf_header').attr('content');
 
                    //ajax에 추가해야함.
                    beforeSend: function(xhr) {
                        xhr.setRequestHeader(csrfheader, csrftoken);
                    },
cs



To be continued.........




Made by 꿩




'IT > 보안' 카테고리의 다른 글

[방화벽] 인바운드 & 아웃바운드  (0) 2022.01.31
[Spring] Google reCAPTCHA v3  (6) 2019.07.07
OAuth  (0) 2019.06.17
SSL인증서  (0) 2019.03.21
XSS 공격과 방어  (2) 2018.10.25

+ Recent posts