학습일지/Language
[Design Pattern] Strategy
inspirit941
2020. 12. 24. 08:20
반응형
Strategy 패턴
여러 알고리즘을 하나의 추상적인 접근점 (인터페이스)을 만들어서, 인터페이스에서 알고리즘이 서로 교환 가능하도록 하는 패턴.
- 동일한 목적의 알고리즘 여러 개 중 특정 알고리즘을 선택해야 할 때.
인터페이스는 '기능의 선언 (구현부와 분리)' 역할을 담당. 하나의 인터페이스로 여러 가지 기능을 구현하기 위한 단일 통로를 생성하는 것.
ex) 워드에서 프린터 명령어 -> 어느 기종의 프린터를 사용하건 상관없이 프린트 명령어가 실행됨
기능 위임 (Delegation) 예시코드.
// AObject : 객체 정의. 이 객체에서 수행할 기능을 인터페이스에 위임하는 방식
public class AObject {
BInterface bInterface;
// 객체 생성 시, 기능을 담당할 인터페이스 구현체를 등록
public AObject() { bInterface = new BImplement(); }
public void doFunc() {
// 메소드 내부에서 직접 기능구현을 담당하지 않음
// System.out.println("doFunction in AObject");
// 기능을 실행할 인터페이스에 구현 위임 (Delegate)
bInterface.funcA();
}
}
public BInterface() {
// 기능 선언
void funcA();
}
public class BImplement implements BInterface {
@Override
public void funcA() { System.out.println("doFunction in BImplement"); }
}
public class TestStrategyPattern {
public static void main(String[] args) {
AObject aobj = new AObject();
// A Object 기능 호출
aobj.doFunc(); // return doFunction in BImplement
}
}
상황에 따라 데이터베이스를 바꿔 사용해야 하는 경우
public abstract class Database {
public String name;
public double rows;
// DB마다 접속 라이브러리는 다름
public abstract void connectDatabase();
// 표준SQL 형태를 사용한다 (업무처리 방식이 같다)
public void insertData() {
System.out.println(name + "에 데이터를 추가했습니다.");
}
public void selectData() {
System.out.println(rows + " rows are selected from " + name);
}
}
// 각각의 DB종류마다 필요한 로직을 구현
public class MySQL extends Database {
public MySQL() { name = "MySQL"; rows = 20;}
@Override
public void connectDatabase(){
// MySQL의 DB Connection 로직 입력
}
}
public class Infomix extends Database {
public Infomix() { name = "MySQL"; rows = 20;}
@Override
public void connectDatabase(){
// Infomix의 DB Connection 로직 입력
}
}
enum DBTYPE { MySQL, Infomix }
public class DatabaseUse {
private Database db;
// 기능 선택하기
public void connect(DBTYPE dbType) {
if (dbType == DBTYPE.MySQL) {
db = new MySQL();
}
else if (dbType == DBTYPE.Infomix) {
db = new Infomix();
}
if (db == null) {
System.out.println("DB를 선택하세요.");
} else {
db.connnectDatabase();
}
}
public void select() { db.selectData(); }
}
public class TestStratgyPattern {
public static void main(String[] args) {
DatabaseUse myDB = new DatabaseUse();
// 특정 DB 선택해서 작업 수행
myDB.connect(DBTYPE.MYSQL);
myDB.select();
// db connection close 이후
// 다른 DB를 사용하고 싶으면, 동일한 객체에 파라미터만 변경하면 됨
myDB.connect(DBTYPE.Infomix);
myDB.select();
}
}
Oracle DB 연결로직을 구현해야 할 경우?
- Database 클래스를 상속받은 Oracle 객체 생성, Enum에 ORACLE 생성
- DatabaseUse에서 DBTYPE 파라미터가 ORACLE일 때의 로직 구현 (connect 메소드 수정)
즉, 매번 코드를 수정할 때마다 이곳저곳의 값을 변경해야 함
기능부 / 구현부를 보다 명확히 정의하는 식으로 해결
public class DatabaseUse {
// 접근점 = 인터페이스
private Database db;
// DB 교환이 가능하도록 하는 메소드
public void setDatabase(Database db) { this.db = db; }
// 기능 사용
public void connect() {
if (db == null) System.out.println("데이터베이스를 선택하세요.");
else {
// 구체적인 DB종류를 입력받지 않아도 기능을 사용할 수 있도록.
db.connectDatabase();
// 이전 코드는 DBTYPE 변수값에 따라 직접 필요한 객체를 생성하는 식의 높은 결합도를 가진 코드
// 이미 만들어진 db객체를 생성자로 주입받는 '낮은 결합도' 코드로 변경
}
}
public void select() {
db.selectData();
}
}
public static void main(String[] args) {
DatabaseUse myDB = new DatabaseUse();
// 특정 DB 선택해서 작업 수행
myDB.setDatabase(new MySQL());
myDB.connect();
myDB.select();
// db connection close 이후
// 다른 DB를 사용하고 싶으면, 동일한 객체에 파라미터만 변경하면 됨
myDB.setDatabase(new Infomix());
myDB.connect();
myDB.select();
// Oracle을 추가하고 싶은 경우 - 아래 코드만 입력하면 실행되도록.
myDB.setDatabase(new Oracle());
myDB.connect();
myDB.select();
}
반응형