변환기의 역할 : 서로 다른 두 인터페이스 사이에 통신이 가능케 하는 것.
ex : 실생활에서 충전기가 휴대폰과 콘센트를 연결해주는 것.
JDBC / ODBC가 다양한 DB시스템을 단일한 인터페이스로 조작할 수 있게 해준다.
OCP
를 활용한 패턴.
OCP
, DIP
를 활용한 패턴.
그냥 캡슐화를 잘 지키는 패턴인 것 같다.
프록시 패턴과 구현방법이 같지만, 리턴값에 장식을 더한다.
리턴값을 포장한다고 해서, 데코레이터 패턴.
인스턴스를 하나만 만들어 사용하기 위한 패턴.
💡 왜 인스턴스를 하나만 만들지 ? → 인스턴스를 여러개 만들게 되면 불필요한 자원(메모리 등)을 사용하게 되고, 프로그램이 예상치 못한 결과(이건 뭘까)를 낳을 수 있기 때문.인스턴스를 하나만 만들기 위해, 생성자를 private으로 지정한 이후(외부에서 생성자 호출 불가능.),
단일객체를 반환하기 위한 정적 메서드(getter)와 해당 단일객체를 참조하는 정적 참조변수가 필요하다.
이때 getter에서는 해당 단일객체가 생성되어있지 않으면 생성 후 반환하고, 이미 생성되어 있으면 바로 해당 단일객체를 반환한다.
공유되는 정적 변수는 속성을 갖지 않게 하는 것이 정석 → 동시에 해당 변수(객체)에 접근해서 속성값을 변경할 경우, 경쟁상태에 진입할 수 있기 때문.
노션에서 쓰는 템플릿처럼, 공통되게 사용되는 메서드를 미리 정의해 두고, 상속받는 클래스에서 구현을 강제하도록 추상 메서드를 두거나 선택적으로 오버라이딩(훅 메서드) 하는 패턴.
객체를 생성하는 팩터리 클래스의 메소드를, 하위 클래스에서 해당 팩터리 메서드를 오버라이딩 하여 객체를 반환하게 하는 패턴.
예제에서 설명한 것은 추상 팩터리 메서드 패턴으로써, 하나의 객체를 구성하는 것들을 같은 분류로 보아, 하나의 클래스 안에서 구성요소들을 생성하는 메소드를 오버라이딩한다.
DIP
를 활용한다.
위 세개의 구성요소가 정말 중요하다고 한다.
클라이언트가 컨트롤러의 역할을 하는 듯 보인다.
군인의 예제에서,
보급장교 : 클라이언트
군인 : 컨텍스트
무기 : 전략이 된다.
전략을 인터페이스로 정의하고, 해당 전략을 무기로써 구현체로 구현한다.
이 때, 컨텍스트가 될 군인에게 무기인 전략을 주입해 준다.
템플릿 메서드 패턴과 유사한데, 템플릿 메서드는 상속(추상 메서드 & 오버라이딩)을 이용하는 반면, 전략 패턴은 인터페이스를 이용하기 때문에 구현의 강제성이 부여된다는 점이 차이점으로 보인다.
다만 자바는 단일 상속만이 가능하므로, 다양한 메서드를 구현하기 위해 템플릿 메서드 패턴보다는 전략 패턴을 더 활용한다고 한다.(이 때, 최대한 ISP를 활용해 인터페이스를 쪼개서 구현할 듯 싶다.)
OCP
, DIP
를 활용한다.
DI에서 활용하는, 특별한 형태의 전략 패턴.
전략을 익명 내부 클래스로 정의해서 사용한다.
package java.templateCallbackPractice;
public interface Strategy {
void runStrategy();
}
package java.templateCallbackPractice;
// Context
public class Soldier {
void runContext(Strategy strategy) {
System.out.println("전투 시작");
strategy.runStrategy();
System.out.println("전투 종료");
}
}
package java.templateCallbackPractice;
public class Client {
public static void main(String[] args) {
Soldier rambo = new Soldier();
rambo.runContext(new Strategy() {
@Override
public void runStrategy() {
System.out.println("총총ㅊ오옻오");
}
});
System.out.println();
rambo.runContext(new Strategy() {
@Override
public void runStrategy() {
System.out.println("카카카ㅏ카랔라");
}
});
}
}
클라이언트 코드를 보면, 익명 클래스 사용으로 (같은 메서드를 오버라이딩 하는 과정에서) 중복 코드가 너무 많이 발생한다.
package java.templateCallbackPractice;
// Context
public class Soldier {
void runContext(String weaponSound) {
System.out.println("전투 시작");
executeWeapon(weaponSound).runStrategy();
System.out.println("전투 종료");
}
private Strategy executeWeapon(final String weaponSound) {
return new Strategy() {
@Override
public void runStrategy() {
System.out.println(weaponSound);
}
};
}
}
package java.templateCallbackPractice;
public class Client {
public static void main(String[] args) {
Soldier rambo = new Soldier();
rambo.runContext("총..촘초초총");
System.out.println();
rambo.runContext("카캌...카카카카ㅏㄹ!");
}
}
리팩토링 이후 클라이언트 코드가 많이 깔끔해졌다. (중복코드를 컨텍스트로 옮겼으므로)
이런식으로 최대한 클라이언트 코드를 짧게 유지하는 듯 하다.
전략 패턴의 일종이므로 역시나 OCP
와 DIP
를 활용한다.