일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 단기개발자코스
- 디자인 패턴
- 취업리부트코스
- 인프콘 2024
- jwttoken
- 빈 조회 2개 이상
- JavaScript
- 커스텀 헤더
- 개발자부트캠프추천
- Python
- @FeignClient
- 개발자 취업
- 디자인패턴
- jwt
- 빈 충돌
- 코딩테스트 준비
- 전략패턴 #StrategyPattern #디자인패턴
- 1주일회고
- Spring multimodule
- infcon 2024
- TiL
- 항해99
- 파이썬
- 99클럽
- 프로그래머스
- DesignPattern
- 프로그래머스 이중우선순위큐
- spring batch 5.0
- KPT회고
- 구글 OAuth login
- Today
- Total
m1ndy5's coding blog
전략 패턴(Strategy Pattern) 본문
전략 패턴의 정의
실행 중에 알고리즘을 선택할 수 있게 하는 행위 소프트웨어 디자인 패턴이다. 전략 패턴은 특정한 계열의 알고리즘들을 정의하고 각 알고리즘을 캡슐화하며 이 알고리즘들을 해당 계열 안에서 상호 교체가 가능하게 만든다. (출처 : 위키백과)
즉, 변화할 수 있는 알고리즘을 따로 빼서 캡슐화하고 수정하기 용이하게 만든 패턴이라고할 수 있다.
왜 전략패턴을 사용해야하는가?
우리가 현재 사용하고 있는 애플리케이션 중에 한번에 뚝딱 만들어지고 수정을 거치지 않은 애플리케이션은 없을 것이다.
사용자의 요구를 반영해야하거나 기존 코드가 후져보일 때(?)등 무조건 수정을 거쳐야한다.
이 때 규칙없이 맘대로 짜여 있는 코드를 고쳐야한다면 아주 힘들 것이다!
자바를 배울 때 상속이라는 개념을 배우게 되는데 상속을 사용하게 되면 부모클래스(슈퍼클래스)의 멤버들을 자식클래스(서브클래스)가 모두 갖게 된다.
여러개의 서브클래스가 하나의 슈퍼클래스를 상속받고 있다고 생각해보자
예를 들어 떡볶이 슈퍼클래스가 있고 내가 만든 떡볶이, 동생이 만든 떡볶이 서브클래스가 있다고 가정해보자
public class 떡볶이{
public void 떡넣기(){...}
public void 어묵넣기(){...}
public void 마늘넣기(){...}
}
public class 내가만든떡볶이 extends 떡볶이{}
public class 동생이만든떡볶이 extends 떡볶이{}
이렇게 되면 내가 만든 떡볶이, 동생이 만든 떡볶이 모두 떡, 어묵, 마늘이 다 들어가야한다.
근데 난 오뎅이 싫은걸??? 그래도 들어가야한다.
그럼 상속을 쓰면 안되겠다!!
인터페이스로 바꿔보자
public interface 떡볶이{
public void 떡넣기();
public void 어묵넣기();
public void 마늘넣기();
}
public class 내가만든떡볶이 implements 떡볶이{
@Override
public void 떡넣기(){...};
@Override
public void 어묵넣기(){// 대충 어묵 안넣는다는 코드};
@Override
public void 마늘넣기(){...};
}
interface로 바꾸니까 내가 원하는 애들만 골라서 넣을 수 있다.
하지만 인터페이스도 문제가 있다.
만약에 마늘이 썩었을 때 마늘넣은 애들을 일일히 찾아서 마늘 빼세요 마늘 빼세요 해야된다!!
이럴 때 바로 전략패턴을 사용하면 일일히 마늘 넣은 애들 찾아서 수정하지 않아도 된다.
어떻게 사용할까?
- 달라지는 부분을 찾아서 달라지지 않는 부분과 분리한다.
일단 떡볶이니까 떡은 무조건 들어간다고 하고 어묵넣기와 마늘넣기는 기호에 따라 달라진다고 생각해보자
그러면 어묵넣기와 마늘넣기는 따로 분리해서 캡슐화를 시킨다public interface 어묵넣는행동{ public void 어묵넣기(); } public interface 마늘넣는행동{ public void 마늘넣기(); }
- 이제 따로 캡슐화한 인터페이스를 구현한다.
public class 어묵많이넣기 implements 어묵넣는행동{
@Override
public void 어묵넣기(){// 대충 어묵 많이 넣는다는 뜻}
}
public class 어묵안넣기 implements 어묵넣는행동{
@Override
public void 어묵넣기{// 대충 어묵 시러시러란 뜻}
}
public abstract class 떡볶이{
어묵넣는행동 어넣;
public void 어묵넣어라(){
어넣.어묵넣기();
}
public void 떡넣기(){
System.out.println("떡볶이에 떡은 필수입니다.");
}
}
public class 내가만든떡볶이 extends 떡볶이{
public 내가만든떡볶이() {
어넣 = new 어묵안넣기();
}
}
public class Main{
public static void main(String\[\] args){
떡볶이 iMade = new 내가만든떡볶이();
iMade.어묵넣어라();
}
}
이렇게 하면 어묵안넣기 클래스의 어묵넣기 메서드가 실행됨으로 어묵을 안넣을 수 있다.
근데 갑자기 내 마음이 변해서 어느날 어묵이 좋아져서 다시 넣고 싶다면?
public abstract class 떡볶이{
어묵넣는행동 어넣;
public void 어묵넣어라(){
어넣.어묵넣기();
}
public void 떡넣기(){
System.out.println("떡볶이에 떡은 필수입니다.");
}
public void set어넣(어묵넣는행동 b){
어넣 = b;
}
}
public class 내가만든떡볶이 extends 떡볶이{
public 내가만든떡볶이() {
어넣 = new 어묵안넣기();
}
}
public class Main{
public static void main(String\[\] args){
떡볶이 iMade = new 내가만든떡볶이();
iMade.어묵넣어라();
iMade.set어넣(new 어묵많이넣기());
iMade.어묵넣어라();
}
이렇게 슈퍼클래스에 setter을 만들어주면 setter를 통해 어묵많이넣기 클래스로 바꿔줄 수 있다.
이 때 떡볶이 클래스는 어묵넣는행동 interface를 implements 받는 것이 아니라 구성(Composition)으로 갖고있다는 점!!
따라서 위에는 안썼지만 마늘넣는행동 또한 떡볶이 클래스에 구성요소로 넣어서 사용하면 된다.
이렇게 사용하게 되면 만약에 썩은마늘을 넣게되서 마늘많이넣기 클래스의 마늘넣기 메서드를 사용한 클래스가 있다면
각 클래스를 찾아가서 고치는게 아니라 마늘많이넣기 클래스의 마늘넣기 메서드만 마늘넣지마세요!!로 바꿔주면 된다.
'백엔드 with java > Design Pattern' 카테고리의 다른 글
싱글톤(Singleton) feat. 스프링 (0) | 2023.12.04 |
---|---|
추상 팩토리 패턴(Abstract Factory Pattern) (0) | 2023.11.26 |
팩토리 메소드 패턴(Factory Method Pattern) (0) | 2023.11.26 |
데코레이터 패턴(Decorator Pattern) (1) | 2023.11.23 |
옵저버 패턴(Observer Pattern) (1) | 2023.11.22 |