Java나 Java의 스펙(사양)에 정의된 것 이외에는 다른 기술이나 규약에 얽매이지 않아야 함
: 특정 프레임 워크에서 지원하는 클래스 사용 시 규약에 얽매이게 됨.
: 다른 기술을 사용하는 상태에서 요구사항이 변경 될 경우에는 다시 전부 일일이 제거하거나 수정해야하는 일이 발생
특정 환경에 종속적이지 않아야 함
애플리케이션 프로그래밍 코드를 작성할 때 항상 작성한 코드가 객체지향스러운가에 대해 고민 하는 습관을 가지는 것
※ main() 메서드처럼 애플리케이션이 시작되는 지점을 엔트리 포인트(Entry point)
1. 의존성 주입이 아닌 일반 의존성 관계
public class MenuController { public static void main(String[] args) { MenuService menuService = new MenuServie(); // MenuService 클래스의 객체를 생성 List<Menu> menuList = menuService.getMenuList(); // MenuService 기능 사용 } } public class MenuService { public List<Menu> getMenuList() { return null; } }
2. 의존성 주입
public class CafeClient { public static void main(String[] args) { // menuService 인스턴스를 생성 MenuService menuService = new MenuService(); // menuController 인스턴스 생성 시에 앞서 생성한 munuService 인스턴스를 인자값으로 전달함. // 외부에서 객체를 주입한다, 즉 의존성 주입에 해당됨 MenuController controller = new MenuController(menuService); List<Menu> menulist = controller.getMenus(); } } public class MenuController { private MenuService menuService; public MenuController(MenuService menuService) { this.menuService = menuService; } public List<Menu> getMenus() { return menuService.getMenuList(); } } public class MenuService { public List<Menu> getMenuList() { return null; } }
3. 의존성 주입은 왜 필요할까요? Why
3-1. new 키워드를 사용할 경우 문제 발생 예시
public class CafeClient { public static void main(String[] args) { MenuServiceStub menuService = new MenuServiceStub(); // 변경 필요 MenuController controller = new MenuController(menuService); List<Menu> menulist = controller.getMenus(); } } public class MenuController { private MenuServiceStub menuService; // 변경 필요 public MenuController(MenuServiceSutb menuService) { // 변경 필요 this.menuService = menuService; } public List<Menu> getMenus() { return menuService.getMenuList(); } } public class MenuServiceStub { // 변경 될 경우 public List<Menu> getMenuList() { return List.of( new Menu(1, "아메리카노", 2500), new Menu(2, "바닐라 라떼", 3500) ); } }
3-2 느슨한 의존성 주입은 어떻게 할까요? How
public class CafeClient { public static void main(String[] args) { MenuService menuService = new MenuServiceStub(); // 변경 필요 (업 캐스팅) MenuController controller = new MenuController(menuService); List<Menu> menulist = controller.getMenus(); } } public class MenuController { private MenuService menuService; // 기존 MenuService public MenuController(MenuService menuService) { // 기존 MenuService this.menuService = menuService; } public List<Menu> getMenus() { return menuService.getMenuList(); } } public Interface MenuService { // MenuService 를 인터페이스로 설정 List<Menu> getMenuList(); } public class MenuServiceStub implements MenuService { // Stub을 MenuServce 인터페이스로 구현 public List<Menu> getMenuList() { return List.of( new Menu(1, "아메리카노", 2500), new Menu(2, "바닐라 라떼", 3500) ); } }
애플리케이션의 핵심 업무 로직에서 로깅이나 보안, 트랜잭션 같은 공통 기능 로직들을 분리하는 것
핵심 관심 사항(Core concern)
: 비즈니스 로직 즉, 애플리케이션의 주목적을 달성하기 위한 핵심 로직에 대한 관심사
공통 관심 사항(Cross-cutting concern)
: 애플리케이션 전반에 걸쳐 공통적으로 사용되는 기능들에 대한 관심사
애플리케이션을 제작하면서 항상 기본적으로 가져야 하는 사고
- ‘어떻게 하면 이 코드를 깔끔하게 유지할 수 있을까?’
- ‘어떻게하면 여기 저기 중복되는 코드들을 재사용할 수 있을까?’
추상화(Abstraction) : 객체지향 프로그래밍 세계에서 어떤 클래스의 본질적인 특성만을 추출해서 일반화 하는 것
PSA가 필요한 이유
어떤 서비스를 이용하기 위한 접근 방식을 일관된 방식으로 유지함으로써 애플리케이션에서 사용하는 기술이 변경되더라도 최소한의 변경만으로 변경된 요구 사항을 반영하기 위함
애플리케이션의 요구 사항 변경에 유연하게 대처
Spring은 상황에 따라 기술이 바뀌더라도 변경된 기술에 일관된 방식으로 접근할 수 있는 PSA를 적극적으로 지원함
이미지 출처
: https://velog.velcdn.com/images/bimilless/post/8d4bd476-1c5c-43e2-9152-b5d053fae2b0/image.png