객체지향 특징 : 추상화, 캡술화, 상속, 다형성
객체지향 설계 원칙 : SOLID(SRP, OCP, LSP, ISP, DIP)
- OCP: 개방-폐쇄 원칙 (Open/closed principle)
- 소프트웨어 요소는 확장에서는 열려 있으나 변경에는 닫혀 있어야 한다
- 인터페이스를 구현한 새로운 클래스를 하나 만들어서 새로운 기능을 구현
- 확장 - new를 없애는 행위. 뭐가 들어와도 상관없는 상태가 됨
- 변화 - 개발자가 수정코딩하는 행위는 최대한 줄여야 함
- DIP: 의존관계 역전 원칙 (Dependency inversion principle)
- 프로그래머는 “추상화에 의존해야지, 구체화에 의존하면 안된다.”
- 의존성 주입은 이 원칙을 따르는 방법 중 하나
- 구현 클래스에 의존하지 말고, 인터페이스에 의존하라
- 역할(Interface)에 의존해야 구현의 변경에 유연해질 수 있다
스프링은 DI(Dependency Injection, 의존관계, 의존성 주입)과 DI 컨테이너로 다형성 + OCP, DIP를 가능하게 지원
IoC(Inversion of Control) /DI(Dependency Injection)
- IoC : 프로그램 제어권을 역전시키는 개념
- 애플리케이션 흐름의 주도권을 Spring이 갖는다
- 프레임워크가 필요한 시점에 가져다가 프로그램을 구동
- 프로그램의 진행 흐름과 구체적인 구현을 분리시킬 수 있다.
- 개발자는 비즈니스 로직에 집중할 수 있다.
- 구현체 사이의 변경이 용이하고 객체간 의존성이 낮아진다.
- DI : IoC라는 개념을 구현하기 위해 사용하는 디자인 패턴 중 하나
- 생성자를 통해서 어떤 클래스의 객체를 전달받는 것(외부에서 객체를 주입한다)
- 즉 객체를 직접 생성하는게 아니라 외부에서 생성한 후 주입
- 모듈간의 결합도가 낮아지고 유연성이 높아진다.
spring에서는 일반적으로 다음과 같이 db통신을 하게되는데, 서블릿(모델 → 서비스 → 레파지토리(db와 직접통신)) → db 통신
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository = new MemoryMemberRepositoryImpl();
//....생략
}
service -> repository 구조를 갖기 때문에 repository 객체를 선언하여 의존관계를 갖는다.
이때 new가 다른 구현체로 교체되어야 한다면, 항상 new 를 코드 수정하고 컴파일하여 재배포해야 되는 문제가 발생한다. → 객체지향적이지 않음(객체지향 OCP 원칙 위배)
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository;
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
따라서, 생성자가 외부에서 구현체를 전달받는 식으로 객체 간 결합성을 낮추고(Spring Dependency Injection)
객체 생성은 다른 곳에서 처리하도록 한다.
@Configuration
public class AppConfig {
@Bean
public MemberService memberService(){
return new MemberServiceImpl(memberRepository());
}
@Bean
private MemberRepository memberRepository(){
return new MemoryMemberRepositoryImpl();
}
}
이렇게 객체 생성이 필요한 부분들을 모아서 AppConfig 파일을 만들게 되는데
이때 annotation을 통해 Spring에게 객체를 관리하는 역할을 위임하게 된다.(Spring Inversion of Control)
@Configuration
@Bean
→ 스프링에서 자동으로 bean들을 관리해주는 application context에 신뢰할 수 있는 위임을 했다는 뜻
// main에서는 ..
//step1.
MemberService memberService = new MemberServiceImpl();
//step2
AppConfig appConfig = new AppConfig();
MemberService memberService = appConfig.memberService();
//step3.
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = applicationContext.getBean("memberSerivce",MemberService.class);
step1. 개발자가 직접 new를 했다면,
step2. appConfig 파일에서 전체 객체 생성에 대해 관리해봤고,
step3. 마지막으로 스프링이 관리하도록 넘겨서 객체를 직접 new 하지 않음
2,3 에서 new를 동일하게 하더라도
개발자가 만든 appConfig 와스프링에서만든 context를 new하는 것은 다름.
복잡해지더라도 appcontext(스프링에서 관리되는 것으로 승격시킴)에 다 위임시켜버림(app, db컨피그 등등)
⇒ 비지니스 로직에는 new가 없어짐
결국, 프레임워크는 객체지향적으로 코딩할 수 있도록 도와줌 ⇒ 결합도를 낮춰준다!!!
서비스 → repo로 흐르는 구조는 변할 수 없지만(MVC구조), new를 씀으로 인해 결합도가 생김.
객체지향 : 연관성을 아예없앨 순 없지만 최대한 결합도를 낮춰야 함 ⇒ new 연산자를 최대한 덜나오게 해야함
어디선가는 나와야 하는데 내 코드에서는 안보이게 함(추상화를 통해)
'Coding > Back - Spring Framework' 카테고리의 다른 글
Spring MVC (0) | 2023.08.21 |
---|---|
Spring Servlet Filter, Interceptor, AOP #Day3 (0) | 2023.08.18 |
Spring Framework 패키지 생성 #Day2 (0) | 2023.08.17 |
Spring Framework 기초 #Day1 (0) | 2023.08.17 |
Spring Framework 스터디 시작 (0) | 2023.08.17 |