전략 패턴 (strategy pattern)
전략 패턴(strategy pattern)란?
전략 패턴(strategy pattern) 또는 정책 패턴(policy pattern)은 실행 중에 알고리즘을 선택할 수 있게 하는 행위 소프트웨어 디자인 패턴이다.
📌참조: https://ko.wikipedia.org/wiki/%EC%A0%84%EB%9E%B5_%ED%8C%A8%ED%84%B4
스트래지 패턴(strategy pattern)
서로 다른 알고리즘이 존재하고, 실행 중 적합한 알고리즘을 선택해서 적용한다.
클라이언트에 모든 알고리즘을 포함시키면 생기는 문제들.
- 클라이언트에 모든 알고리즘을 포함시키면 클라이언트 코드의 양이 늘어나고 복잡해지며 결과적으로는 유지 보수가 어려워지게 된다.
- 모든 알고리즘이 동시에 사용되는 것이 아니라면 굳이 같이 넣어야 할 이유가 없다.
- 새로운 알고리즘 추가가 어려워지게 되고 기존 코드를 수정해야 하는 번거로움이 생긴다.
👉 결과적으로 이러한 문제점을 해결하기 위해서 전략 패턴 즉, 스트래지 패턴을 사용하는 것이다.
# Duck이라는 클래스를 오버라이드해서 사용하는 클래스의 경우 RubberDuck과 같이 필요하지 않는 메소드(함수)까지 상속 받게 된다.
인터페이스를 사용한다면?
인터페이스 안에 코드를 넣을 수 없어 실제적으로 인터페이스를 상속받아 그 기능을 구현해야 하기 때문에 여러 클래스들에서 같은 코드를 반복해서 구현해야 하는 경우가 발생할 수 있게 된다. 👉 Java8에서는 디폴트 메소드를 이용하면 일부 해결이 가능하다 한다.
인터페이스란 무엇인가?
인터페이스는 간단하게 말하면 동일한 목적 아래서 동일한 기능을 보장하기 위한 방법으로 자바의 다형성을 극대화하여 개발코드의 수정을 줄일 수 있게하고 유지 보수성을 높여주는 역할을 한다
ex) 과제를 제출하는 교수가 여러 제약을 두고 비슷한 형식의 과제물 제출을 할 수 있게 하는 경우가 인터페이스의 역할과 유사하다고 볼 수 있다. 이렇게 교수가 제약을 두지 않을 때 학생들의 과제 제출 결과물은 중구난방으로 제각각일 수 있기 때문에 인터페이스 역시 이와 같은 상황을 막고자 여러 방면으로 동일 목적의 동일 기능의 보장을 위한 규약? 비슷한 개념이라 생각하면 편하다.
아래의 티스토리에는 인터페이스에 대한 개념과 더불어 문법, 다형성과 관련된 이야기를 써내려가고 있으니 다들 한 번씩 들어가서 보는 것을 추천한다.
📌출처: https://limkydev.tistory.com/197
바뀌는 부분과 그렇지 않은 부분 분리하기
Duck 함수 안에 메소드가 전부 있을 경우에 생기는 문제점을 해결하기 위해서 자주 바뀌는 행동을 인터페이스로 따로 구현하여 캡슐화하여 분리해서 사용하게 한다.
스트래티지(Strategy) 패턴이 필요한 경우
- 경우에 따라 서로 다른 여러 알고리즘이 존재한다.
- 알고리즘이 실행 시점에 결정되어 조건문 등을 이용해서 다른 알고리즘을 선택하는 경우에 필요하다.
요소 | 설명 |
이름 | 스트래티지(Strategy) |
문제 | 알고리즘의 다른 버전이 존재해서, 중복으로 존재하거나 if문을 이용해서 선택해야 한다. 👉 OCP 위반(개방-폐쇄원칙 위반) |
해결 방안 | 중복을 공통화시키고, 실행 시점에 맞는 알고리즘을 호출하도록 한다. (상속 또는 인터페이스를 활용한다.) |
결과 | OCP 수정할 경우 Strategy를 추가하고, 나머지는 변경하지 않아도 된다. |
Context 클래스
- 캡슐화된 알고리즘을 멤버 변수로 포함
- 캡슐화된 알고리즘을 교환해서 적용시킬 수 있음
Strategy 클래스(인터페이스)
- 컴파일 시점에서 사용하는 캡슐화된 알고리즘을 나타냄
- 실제 구현은 하위 Strategyn 클래스에 위임
- 인터페이스 또는 추상 클래스로 구현 가능
Strategy n
- 실행시점에 적용될 알고리즘을 캡슐화
- Context에서 실행될 알고리즘을 구현
package oop_2;
import java.util.Date;
public class FileInfo {
private String name;
private String type;
private int size;
private Date modifiedDate;
public FileInfo(String name, String type, int size, Date modifiedDate) {
this.name =name;
this.modifiedDate = modifiedDate;
this.size = size;
this.type = type;
}
public String getName() {return name;}
public String getype() {return type;}
public int getSize() {return size;}
public Date getModifiedDate() {return modifiedDate;}
public String toString() {
return "Name: " + name + "\n"
+ "Type: " + type + "\n"
+"Size: " + size + "\n"
+ "ModifiedDate: " + modifiedDate.toString();
}
}
package oop_2;
interface Comparable {
int compareTo(Object o1, Object o2);
}
package oop_2;
public class Sorter {
private Comparable comparable;
public Sorter(Comparable comparable) {
this.comparable = comparable;
}
public void setComparable(Comparable comparable) {
this.comparable = comparable;
}
public void bubbleSort(Object[] objs) {
for (int i = 0; i < objs.length - 1; i++) {
for (int j = 0; j < objs.length - i - 1; j++) {
if (comparable.compareTo(objs[j],objs[j + 1]) > 0) { // swap
Object temp = objs[j];
objs[j] = objs[j + 1];
objs[j + 1] = temp;
}
}
}
}
}
package oop_2;
public class CompareFileName implements Comparable {
@Override
public int compareTo(Object o1, Object o2) {
FileInfo f1 = (FileInfo) o1;
FileInfo f2 = (FileInfo) o2;
return f1.getName().compareTo(f2.getName());
}
}
package oop_2;
public class CompareFileType implements Comparable {
@Override
public int compareTo(Object o1, Object o2) {
FileInfo f1 = (FileInfo) o1;
FileInfo f2 = (FileInfo) o2;
return f1.getype().compareTo(f2.getype());
}
}
package oop_2;
public class CompareModifiedDate implements Comparable {
@Override
public int compareTo(Object o1, Object o2) {
FileInfo f1 = (FileInfo) o1;
FileInfo f2 = (FileInfo) o2;
return f1.getModifiedDate().compareTo(f2.getModifiedDate());
}
}
package oop_2;
public class CompareSize implements Comparable {
@Override
public int compareTo(Object o1, Object o2) {
FileInfo f1 = (FileInfo) o1;
FileInfo f2 = (FileInfo) o2;
return f1.getSize() - f2.getSize();
}
}
package oop_2;
import java.text.ParsePosition;
import java.util.Date;
import java.text.SimpleDateFormat;
public class Main {
String[] names = { "CompareModifiedDate", "CompareFileType", "CompareFileName", "Main", "CompareSize" };
String[] types = { "java", "java", "class", "java", "Class" };
int[] sizes = { 120, 80, 150, 85, 100 };
String[] dateStrings = { "2020-09-13T21:59:00", "2020-09-12T21:59:00",
"2020-09-13T16:54:00", "2020-09-12T21:54:00", "2020-09-13T11:59:00" };
public FileInfo[] createFileInfoArrays() {
FileInfo[] fileLists = new FileInfo[names.length];
SimpleDateFormat dateTimeInstance = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
for (int i = 0; i < fileLists.length; i++) {
Date date = dateTimeInstance.parse(dateStrings[i], new ParsePosition(0));
fileLists[i] = new FileInfo(names[i], types[i], sizes[i], date);
}
return fileLists;
}
public void printFileLists(FileInfo[] fileLists) {
for (FileInfo fi : fileLists) {
System.out.println(fi);
}
}
public static void main(String[] args) {
Main m = new Main();
FileInfo[] fileLists = m.createFileInfoArrays();
System.out.println("�썝蹂� 由ъ뒪�듃");
m.printFileLists(fileLists);
Sorter sorter = new Sorter(new CompareFileName());
System.out.println("\n\n�뙆�씪 �씠由꾩쑝濡� �젙�젹�맂 由ъ뒪�듃");
sorter.bubbleSort(fileLists);
m.printFileLists(fileLists);
System.out.println("\n\n�뙆�씪 醫낅쪟濡� �젙�젹�맂 由ъ뒪�듃");
sorter.setComparable(new CompareFileType());
sorter.bubbleSort(fileLists);
m.printFileLists(fileLists);
System.out.println("\n\n�뙆�씪 �겕湲곕줈 �젙�젹�맂 由ъ뒪�듃");
sorter.setComparable(new CompareSize());
sorter.bubbleSort(fileLists);
m.printFileLists(fileLists);
System.out.println("\n\n�뙆�씪 �닔�젙 �떆媛꾩쑝濡� �젙�젹�맂 由ъ뒪�듃");
sorter.setComparable(new CompareModifiedDate());
sorter.bubbleSort(fileLists);
m.printFileLists(fileLists);
}
}
'Java > 고급객체지향' 카테고리의 다른 글
고급객체지향 프로그래밍 - 데코레이터 패턴 (Decorator Pattern) (0) | 2021.10.19 |
---|---|
고급객체지향 프로그래밍 - 스윙 (Swing) (0) | 2021.10.18 |
고급객체지향 프로그래밍 - 옵서버 패턴 (Observer Pattern) (0) | 2021.10.18 |
고급객체지향 프로그래밍 - 제네릭스(Generics) (0) | 2021.10.06 |
#1. 과제 (0) | 2021.09.17 |