-
Spring - 디자인 패턴STUDY/디자인패턴 2021. 5. 10. 12:13
1. 어댑터 패턴(Adapter Pattern)
- 개방 폐쇄 원칙을 활용한 설계 패턴으로, 서로 다른 두 인터페이스 사이에 통신이 가능하게 하는 것이다. 한 클래스의 인터페이스를 클라이언트에서 사용하고자하는 다른 인터페이스로 변환한다. 어댑터를 이용하면 인터페이스 호환성 문제 때문에 같이 쓸 수 없는 클래스들을 연결해서 쓸 수 있다.
public interface ServiceA {
public void startServiceA();
public void stopServiceA();
}
public class ServiceAA implements ServiceA {
@Override
public void startServiceA() {
System.out.println("start ServiceA");
}
@Override
public void stopServiceA() {
System.out.println("stop ServiceA");
}
}public interface ServiceB {
public void startServiceB();
public void stopServiceB();
}
public class ServiceBB implements ServiceB {
@Override
public void startServiceB() {
System.out.println("start ServiceB");
}
@Override
public void stopServiceB() {
System.out.println("stop ServiceB");
}
}public class ServiceBAdapter implements ServiceA {
ServiceB serviceB;
public ServiceBAdapter(ServiceB serviceB) {
this.serviceB= serviceB;
}
@Override
public void startServiceA(){
serviceB.startServiceB();
}
@Override
public void stopServiceA() {
serviceB.stopServiceB();
}
}public class ServiceATestDrive {
public static void main(String[] args) {
ServiceAA serviceA = new ServiceAA();
ServiceBB serviceB = new ServiceBB();
ServiceA serviceBAdapter = new ServiceBAdapter(serviceB);
System.out.println("ServiceB...");
serviceB.startServieB();
serviceB.stopServiceB();
System.out.println("ServiceA...");
testService(serviceA);
System.out.println("ServiceBAdapter...");
testService(serviceBAdapter);
}
public static void testService(ServiceA serviceA){
serviceA.startServiceA();
serviceA.stopServiceA();
}
}[결과]
ServiceB...
start ServiceB
stop ServiceB
ServiceA...
start ServiceA
stop ServiceA
ServiceBAdapter...
start ServiceB
stop ServiceB2. 프록시 패턴(Proxy Pattern)
- 실제 서비스 메소드의 반환값에 가감하는 것을 목적으로 하지 않고 제어의 흐름을 변경하거나 다른 로직을 수행하기 위해 사용하는 것으로, 즉 제어 흐름을 조정하기 위한 목적으로 중간에 대리자를 두는 패턴이다.
- 대리자는 실제 서비스와 같은 이름의 메서드를 구현한다. 이때 인터페이스를 사용한다.
- 대리자는 실제 서비스에 대한 참조 변수를 갖는다(합성).
- 대리자는 실제 서비스의 같은 이름을 가진 메서드를 호출하고 그 값을 클라이언트에게 돌려준다.
- 대리자는 실제 서비스의 메서드 호출 전후에 별도의 로직을 수행할 수도 있다.
public interface IService {
String runSomething();
}
public class Service implements IService {
public String runSomething() {
return "service";
}
}
public class Proxy implements IService {
IService service1;
public String runSomething() {
System.out.println("호출에 대한 흐름 제어가 주목적, 반환 결과를 그대로 전달");
service1 = new Service();
return service1.runSomething();
}
}public class ClientWithProxy {
public static void main(String[] args) {
Iservice proxy = new Proxy();
System.out.println(proxy.runSomething());
}
}[결과]
호출에 대한 흐름 제어가 주목적, 반환 결과를 그대로 전달
service3. 데코레이터 패턴(Decorator Pattern)
- 프록시 패턴과 동일한 구조를 갖는 패턴으로, 프록시 패턴과는 달리 메서드 호출의 반환값에 변화를 주기 위해 중간에 장식자를 두는 패턴이다.
- 장식ㅈ는 실제 서비스와 같은 이름의 메서드를 구현한다. 이때 인터페이스를 사용한다.
- 장식자는 실제 서비스에 대한 참조 변수를 갖는다(합성).
- 장식자는 실제 서비스의 같은 이름을 가진 메서드를 호출하고, 그 반환값에 장식을 더해 클라이언트에게 돌려준다.
- 장식자는 실제 서비스의 메서드 호출 전후에 별도의 로직을 수행할 수도 있다.
public interface IService {
String runSomething();
}
public class Service implements IService {
public String runSomething() {
return "service";
}
}
public class Decorator implements IService {
IService service1;
public String runSomething() {
System.out.println("호출에 대한 장식 주목적, 클라이언트에게 반환 결과에 장식을 더하여 전달");
service1 = new Service();
return "decorator " + service1.runSomething();
}
}public class ClientWithProxy {
public static void main(String[] args) {
Iservice decorator = new Decorator();
System.out.println(decorator.runSomething());
}
}[결과]
호출에 대한 장식 주목적, 클라이언트에게 반환 결과에 장식을 더하여 전달
decorator service4. 싱글턴 패턴(Singleton Pattern)
- 인스턴스를 하나만 만들어서 사용하기 위한 패턴이다.
- 싱글톤 패턴에 필요한 요소
- new를 실행할 수 없도록 생성자에 private 접근 제어자를 지정한다.
- 유일한 단일 객체를 반환할 수 있는 정적 메서드가 필요하다.
- 유일한 단일 객체를 참조할 정적 참조 변수가 필요하다.
- 싱글톤 패턴의 특징
- private 생성자를 갖는다.
- 단일 객체 참조 변수를 정적 속성으로 갖는다.
- 단일 객체 참조 변수가 참조하는 단일 객체를 반환하는 getInstance() 정적 메서드를 갖는다.
- 단일 객체는 쓰기 가능한 속성을 갖지 않는 것이 정석이다.
public class Singleton {
static Singleton singletonObject;
private Singleton() { };
public static Singleton getInstance() {
if(singletonObject == null) {
singletonObject = new Singleton();
}
return singletonObject;
}
}public class ClientWithSingleton{
public static void main(String[] args) {
//private 생성자이기때문에 new를 통해 인스턴스를 생성할 수 없다.
// Singleton s = new Singleton();
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
Singleton s3 = Singleton.getInstance();
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
}
}[결과]
SingletonPattern.Singleton@263c8db9
SingletonPattern.Singleton@263c8db9
SingletonPattern.Singleton@263c8db95. 템플릿 메서드 패턴(Template Method Pattern)
- 상위 클래스의 견본 메서드에서 하위 클래스가 오버라이딩한 메서드를 호출하는 패턴이다.
- 구성요소
- 템플릿 메서드 : 공통 로직을 수행, 로직 중에 하위 클래스에서 오버라이딩한 추상 메서드/훅 메서드를 호출
- 템플릿 메서드에서 호출하는 추상 메서드 : 하위 클래스가 반드시 오버라이딩 해야한다.
- 템플릿 메서드에서 호출하는 훅(Hook, 갈고리) 메서드 : 하위 클래스가 선택적으로 오버라이딩한다.
public abstract class Service{
//템플릿 메서드
public void runService() {
System.out.println("start");
service();
run();
System.out.println("stop");
}
// 추상 메서드
abstract void service();
// Hook 메서드
void run(){
System.out.println("run service");
}
}public class ServiceA extends Service{
@Override
// 추상 메서드 오버라이딩
void service() {
System.out.println("serviceA");
}
@Override
// Hook 메서드 오버라이딩
void run() {
System.out.println("run ServiceA");
}
}
public class ServiceB extends Service{
@Override
// 추상 메서드 오버라이딩
void service() {
System.out.println("serviceB");
}
@Override
// Hook 메서드 오버라이딩
void run() {
System.out.println("run ServiceB");
}
}public class MainService{
public static void main(String[] args){
Service serviceA = new ServiceA();
Service serviceB = new ServiceB();
serviceA.runService();
System.out.println();
serviceB.runService();
}
}[결과]
start
serviceA
run ServiceA
stop
start
serviceB
run ServiceB
stop6. 팩터리 메서드 패턴(Factory Method Pattern)
- 오버라이드된 메서드가 객체를 반환하는 패턴
public abstract class MainService{
// 추상 팩터리 메서드
abstract Service getService();
}
// 팩터리 메서드가 생성할 객체의 상위 클래스
public abstract class Service{
abstract void run();
}public class ServiceA extends MainService{
// 추상 팩터리 메서드 오버라이딩
@Override
Service getService(){
return new ServiceAA();
}
}
// 팩터리 메서드가 생성할 객체
public class ServiceAA extends Service{
public void run() {
System.out.println("run serviceA);
}
}
public class ServiceB extends MainService{
// 추상 팩터리 메서드 오버라이딩
@Override
Service getService(){
return new ServiceBB();
}
}
// 팩터리 메서드가 생성할 객체
public class ServiceBB extends Service{
public void run() {
System.out.println("run serviceB);
}
}public class RealService{
public static void main(String[] args){
//팩터리 메서드를 보유한 객체들 생성
MainService serviceA = new ServiceA();
MainService serviceB = new ServiceB();
//팩터리 메서드가 반환하는 객체들
Service serviceAA = serviceA.getService();
Service serviceBB = serviceB.getService();
//팩터리 메서드가 반환한 객체들을 사용
serviceAA.run();
serviceBB.run();
}
}[결과]
run serviceA
run serviceB7. 전략 패턴(Strategy Pattern)
- 클라이언트가 전략을 생성해 전략을 실행할 컨텍스트에 주입하는 패턴
- 전략 메서드를 가진 전략 객체
- 전략 객체를 사용하는 컨텍스트(전략 객체의 사용자/소비자)
- 전략 객체를 생성해 컨텍스트에 주입하는 클라이언트(제3자, 전략 객체의 공급자)
public interface Strategy{
public abstract void runStrategy();
}
public class StrategyA implements Strategy{
@Override
public void runStrategy(){
System.out.println("strategy A");
}
}
public class StrategyB implements Strategy{
@Override
public void runStrategy(){
System.out.println("strategy B");
}
}
public class StrategyC implements Strategy{
@Override
public void runStrategy(){
System.out.println("strategy C");
}
}public class Context{
void runContext(Strategy strategy){
System.out.println("start");
strategy.runStrategy();
System.out.println("stop);
}
}public class Client{
public static void main(String[] args){
Strategy strategy = null;
Context context = new Context();
strategy = new StrategyA();
context.runContext(strategy);
System.out.println();
strategy = new StrategyB();
context.runContext(strategy);
System.out.println();
strategy = new StrategyC();
context.runContext(strategy);
}
}[결과]
start
strategy A
stop
start
strategy B
stop
start
strategy C
stop8. 템플릿 콜백 패턴(Template Callback Pattern - 견본/회신 패턴)
- 전략을 익명 내부 클래스로 구현한 전략 패턴
- DI(의존성 주입)에서 사용하는 특별한 형태의 전략 패턴이다.
public interface Strategy{
public abstract void runStrategy();
}
public class Context{
void runContext(String strategyElement){
System.out.println("start");
executeStrategy(strategyElement).runStrategy();
System.out.println("stop);
}
}
private Strategy executeStrategy(final String strategyElement) {
return new Strategy(){
@Override
public void runStrategy(){
System.out.println(strategyElement);
}
}
}public class Client{
public static void main(String[] args){
Context context = new Context();
context.runContext("strategy A");
System.out.println();
context.runContext("strategy B");
System.out.println();
context.runContext("strategy C");
}
}[결과]
start
strategy A
stop
start
strategy B
stop
start
strategy C
stop'STUDY > 디자인패턴' 카테고리의 다른 글
Singleton Pattern(싱글턴 패턴) (0) 2024.11.26 Prototype Pattern(프로토타입 패턴) (0) 2024.11.26 Builder Pattern(빌더 패턴) (0) 2024.11.12 Abstract Factory Pattern(추상 팩토리 패턴) (1) 2024.11.12 Factory Method Pattern(팩토리 메서드 패턴) (0) 2024.10.29