-
스프링과 디자인 패턴공부방 2023. 8. 27. 20:26
디자인 패턴
소프트웨어 디자인 패턴(software design pattern)은 소프트웨어 공학의 소프트웨어 디자인에서 특정 문맥에서 공통적으로 발생하는 문제에 대해 재사용 가능한 해결책이다.
디자인 패턴은 시스템을 디자인 할 때 공통된 문제들을 해결하는데에 쓰이는 형식화 된 관행이라고 볼 수 있다.
'스프링 입문을 위한 자바 객체 지향의 원리와 이해' 라는 책에서 소개된 디자인 패턴중 일부를 살펴 보고 이 패턴들이 스프링에서 어떤식으로 사용 되는지 살펴보자
어댑터 패턴
먼저 어댑터 패턴이 적용되지 않은 두 클래스를 보자
public class ServiceA{ void runServiceA(){ System.out.println("ServiceA"); } } public class ServiceB{ void runServiceB(){ System.out.println("ServiceB"); } }
이 두 클래스를 사용하는 곳에서는 runServiceA 와 runServiceB라는 서로 다른 함수를 호출 해야 한다. 위 코드를 어댑터 패턴을 적용해 개선을 해보면
public class AdapterServiceA{ ServiceA sa = new ServiceA(); void runService(){ sa.runServiceA(); } } public class AdapterServiceB{ ServiceB sb = new ServiceB(); void runService(){ sb.runServiceB(); } }
이런식으로 어댑터 클래스를 새로 두어 실제 사용할때는 같은 이름의 함수를 호출하면 된다. 이처럼, 어댑터 패턴은
"호출당하는 쪽의 메서드를 호출하는 쪽의 코드에 대응하도록 중간에 변환기를 통해 호출하는 패턴" 이라 할 수 있다.
스프링에서 어댑터 패턴이 사용되는곳은 대표적으로 HandlerAdapter 가 있다.
HanderAdapter 중 하나인 SimpleControllerHandlerAdapter를 예시로 보자. handle 이라는 method가 있는데 DispatcerServelet에서는 이 method를 호출하여 handler를 작동시킨다. 이 HandlerAdapter를 구현한 다른 클래스들도 각자에 맞게 handle 함수를 구현하고 호출하는곳에서는 동일하게 handle 을 호출하는 형식이다.
프록시 패턴
먼저 프록시 패턴을 적용하지 않은 코드를 보자
public class Service { public String runSomething(){ return "Hello"; } }
위 클래스를 사용하는곳에서는 Service의 인스턴스를 만들고 runSomething 메소드를 호출할 것이다. 이를 프록시 패턴을 적용하여 수정해 보자.
public interface IService{ String runSomething(); } public class Service implements IService{ public STring runSomething(){ return "Hello"; } } public class Proxy implements IService{ IService service; public String runSomething() { serive = new Service(); return service.runSomething(); } }
위처럼 수정된 코드에서는 Service 의 인스턴스를 생성하는것이 아닌 Proxy의 인스턴스를 생성하고 runSomething 메소드를 호출하면 Service의 runSomething 결과를 마찬가지로 받을 수 있다.
이게 무슨 차이가 있나 싶겠지만, 이런식으로 Proxy를 통해 대신 호출하게 되면 Proxy의 runSomething에 별도의 제어 흐름을 추가할 수 있다. Service 의 runSomething 전후에 자신이 원하는 로직을 넣을 수 있게되었다.
프록시 패턴을 정리하면 "제어 흐름을 조정하기 위한 목적으로 중간에 대리자를 두는 패턴" 이라 할 수 있다.
스프링에서 프록시 패턴이 적용된 대표적인 부분은 스프링의 AOP 기능이다.
스프링 AOP란, Aspect Oriented Programming의 약자이다. 위 그림처럼 여러 클래스에 흩어져있는 관점들을 하나로 모아 처리하는 것이다.
대표적인 예로, 스프링에서 @Transactional 는 AOP 방식으로 처리된다. 실제 비즈니스 로직 외에 트랜잭션 시작 등의 전처리와 커밋, 롤백등의 후처리등을 프록시 패턴으로 처리한다.
싱글톤 패턴
싱글톤 패턴은 클래스의 인스턴스를 하나만 만들어 사용하는 패턴이다.
public class Singleton { static Singleton singletonObject; private Singleton(){}; public static Singleton getInstance(){ if(singletonObject == null){ singletonObject = new Singleton(); } return singletonObject; } }
위는 싱글톤 패턴의 예시이다. 물론 아주 좋은 싱글톤 생성 방식은 아니다. 자세한 싱글톤에 대한 설명은 다음을 참조한다.
2023.08.27 - [JAVA] - Singleton 구현 기법
이처럼, 싱글톤 패턴을 사용하면 항상 하나의 인스턴스만 생성하여 사용된다.
스프링에서의 싱글톤 패턴으로는 다음과 같은 부분을 볼 수 있다.
DefaultBootstrapContext의 getInstance 함수이다. 현재 Scope 이 싱글톤이면 this.instances에 인스턴스를 하나 할당하고 계속 같은 인스턴스를 반환하는것을 볼 수 있다.
코드로 찾아본 예시는 위와 같지만, 스프링에서 제일 유명한 싱글톤 패턴은 싱글톤 컨테이너이다. 스프링에서는 생성된 Bean을 싱글톤 패턴으로 관리하여 단 하나의 인스턴스만 갖고있는다. 이를 컨테이너가 필요한 곳에 주입하는 방식으로 사용된다.
'공부방' 카테고리의 다른 글
HTTPS 통신 과정 (0) 2023.11.15 OSI 7계층과 TCP/IP 4계층 (0) 2023.11.07 Session과 Token (0) 2023.10.20 부동소수점 표현 방식 [IEEE 754] (0) 2023.08.31 CAP Theorem (0) 2023.08.06