변환기의 역할은 서로 다른 두 인터페이스 사이에 통신이 가능하게 하는 것이다.
어댑터 패턴은 합성, 즉 객체를 속성으로 만들어서 참조하는 디자인 패턴이다.
즉, 어댑터 패턴은 개방 폐쇄 원칙을 활용한 설계 패턴이다.
"호출당하는 쪽의 메서드를 호출하는 쪽의 코드에 대응하도록 중간에 변환기를 통해 호출하는 패턴"
프록시는 대리자, 대변인(다른 누군가를 대신해 그 역할을 수행하는 존재)이라는 뜻을 가진다.
프록시 패턴은 실제 서비스 메서드의 반환값에 가감하는 것을 목적으로 하지 않고 제어의 흐름을 변경하거나 다른 로직을 수행하기 위해 사용한다.
"제어 흐름을 조정하기 위한 목적으로 중간에 대리자를 두는 패턴"
데코레이터 패턴은 클라이언트가 받는 반환값에 장식을 더한다는 점만 빼면 프록시 패턴과 동일하다.
"메서드 호출의 반환값에 변화를 주기 위해 중간에 장식자를 두는 패턴"
싱글턴 패턴은 클래스의 인스턴스, 즉 객체를 하나만 만들어서 사용하는 패턴이다.
// Singleton의 예제
public class Singleton {
static Singleton singletonObject;// 정적 참조 변수
private Singleton() {};// private 생성자
//객체 반환 정적 메서드
public static Singleton getInstance() {
if (singletonObject == null) {
singletonObject = new Singleton();
}
return singletonObject;
}
}
"클래스의 인스턴스, 즉 객체를 하나만 만들어 사용하는 패턴"
템플릿 메서드 패턴은 상위 클래스에 공통 로직을 수행하는 템플릿 메서드와 하위 클래스에 오버라이딩을 강제하는 추상 메서드 또는 선택적으로 오버라이딩할 수 있는 훅(Hook) 메서드를 두는 패턴이다.
템플릿 메서드
템플릿 메서드에서 호출하는 추상 메서드
템플릿 메서드에서 호출하는 훅(Hook, 갈고리) 메서드
"상위 클래스의 템플릿(견본) 메서드에서 하위 클래스가 오버라이딩한 메서드를 호출하는 패턴"
오버라이드된 메서드가 객체를 반환하는 패턴
팩터리 메서드는 객체를 생성 반환하는 메서드를 말한다.
하위 클래스에서 팩터리 메서드를 오버라이딩해서 객체를 반환하게 하는 것이다.
-> 객체를 생성하는 인터페이스는 미리 정의하되, 어떤 클래스의 인스턴스를 생성할 지에 대
한 결정은 서브클래스에서 이루어지도록 하는 패턴이다.
기존 코드(인스턴스를 만드는 과정)를 수정하지 않고 새로운 인스턴스를 다른 방법으로 생성하도록 확장할 수 있다!!
//추상 클래스를 나타내는 Animal.java
package factoryMethodPattern;
public abstract class Animal {
// 추상 팩터리 메서드
abstract AnimalToy getToy();
}
//추상 클래스를 나타내는 AnimalToy.java
// 팩터리 메서드가 생성할 객체의 상위 클래스
public abstract class AnimalToy {
abstract void identify();
}
//Dog.java
package factoryMethodPattern;
public class Dog extends Animal {
// 추상 팩터리 메서드 오버라이딩
@Override
AnimalToy getToy() {
return new DogToy();
}
}
//DogToy.java
//팩터리 메서드가 생성할 객체
public class DogToy extends AnimalToy {
public void identify() {
System.out.println("나는 테니스공! 강아지의 친구!");
}
}
//Cat.java
package factoryMethodPattern;
public class Cat extends Animal {
// 추상 팩터리 메서드 오버라이딩
@Override
AnimalToy getToy() {
return new CatToy();
}
}
//CatToy.java
//팩터리 메서드가 생성할 객체
public class CatToy extends AnimalToy {
@Override
public void identify() {
System.out.println("나는 캣타워! 고양이의 친구!");
}
}
//Driver.java
package factoryMethodPattern;
public class Driver {
public static void main(String[] args) {
// 팩터리 메서드를 보유한 객체들 생성
Animal bolt = new Dog();
Animal kitty = new Cat();
// 팩터리 메서드가 반환하는 객체들
AnimalToy boltBall = bolt.getToy();
AnimalToy kittyTower = kitty.getToy();
// 팩터리 메서드가 반환한 객체들을 사용
boltBall.identify();
kittyTower.identify();
}
}
클라이언트가 전략을 생성해 전략을 실행할 컨텍스트에 주입하는 패턴
<전략 패턴을 구성하는 3가지 요소>
클라이언트는 다양한 전략 중 하나를 선택해 생성한 후 컨텍스트에 주입한다.
ex) 군인
무기 - 전략
군인 - 컨텍스트
보급 장교 - 클라이언트
//전략 인터페이스를 나타내는 Strategy.java
package strategyPattern;
public interface Strategy {
public abstract void runStrategy();
}
//전략 인터페이스를 구현하는 StrategyGun.java
package strategyPattern;
public class StrategyGun implements Strategy {
@Override
public void runStrategy() {
System.out.println("탕, 타탕, 타다당");
}
}
//전략 인터페이스를 구현하는 StrategySword.java
public class StrategySword implements Strategy {
@Override
public void runStrategy() {
System.out.println("챙.. 채쟁챙 챙챙");
}
}
//전략 인터페이스를 구현하는 StrategyBow.java
public class StrategyBow implements Strategy {
@Override
public void runStrategy() {
System.out.println("슝.. 쐐액.. 쉑, 최종 병기");
}
}
//전략을 사용하는 컨텍스트 Soldier.java
package strategyPattern;
public class Soldier {
void runContext(Strategy strategy) {
System.out.println("전투 시작");
strategy.runStrategy();
System.out.println("전투 종료");
}
}
//전략 패턴의 클라이언트 Client.java
package strategyPattern;
public class Client {
public static void main(String[] args) {
Strategy strategy = null;
Soldier rambo = new Soldier();
//총을 람보에게 전달해서 전투를 수행하게 한다.
strategy = new StrategyGun();
rambo.runContext(strategy);
System.out.println();
// 검을 람보에게 전달해서 전투를 수행하게 한다.
strategy = new StrategySword();
rambo.runContext(strategy);
System.out.println();
// 활을 람보에게 전달해서 전투를 수행하게 한다.
strategy = new StrategyBow();
rambo.runContext(strategy);
}
}
전략 패턴의 변형으로, 스프링의 3대 프로그래밍 모델 중 하나인 DI(의존성 주입)에서 사용하는 특별한 형태의 전략 패턴이다.
전략을 익명 내부 클래스로 정의해서 사용한다는 것을 제외하면 전략 특징과 동일하다.
//전략 인터페이스 Strategy.java
package templateCallbackPattern;
public interface Strategy {
public abstract void runStrategy();
}
//전략을 사용하는 컨텍스트 Soldier.java
package templateCallbackPattern;
public class Soldier {
void runContext(Strategy strategy) {
System.out.println("전투 시작");
strategy.runStrategy();
System.out.println("전투 종료");
}
}
//익명 내부 전략을 사용하는 클라이언트 Client.java
package templateCallbackPattern;
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("칼! 카가갈 칼! 칼!");
}
});
System.out.println();
rambo.runContext(new Strategy() {
@Override
public void runStrategy() {
System.out.println("도끼! 독독..도도독 독끼!");
}
});
}
}
각 클라이언트들은 Front Controller에 요청을 보내고,
Front Controller은 각 요청에 맞는 컨트롤러를 찾아서 호출시킨다.
공통 코드에 대해서는 Front Controller에서 처리하고, 서로 다른 코드들만 각 Controller에서 처리할 수 있도록 한다.
도메인(비즈니스 로직) 영역과 UI 영역을 분리시켜 서로 영향을 주지 않고 유지보수가 가능하다.
Model
View
Controller