Spring에서 객체지향 원리를 이해하 보자
들어가며
스프링은 자바 기반의 프레임워크로, 자바는 객체지향적인 프로그래밍을 중요시합니다. 이에 따라 스프링을 사용하면 객체지향적인 개발을 할 수 있습니다. 스프링이 객체지향적인 개발을 지원하는 방법을 이해하는 것은 매우 중요합니다. 따라서 이번 시간에는 스프링이 추구하는 객체지향적인 원리를 이해하는 시간을 갖도록 하겠습니다.
객체지향이란 무엇인가?
객체지향 프로그래밍은 절차지향적인 방법과는 달리 하나의 모델을 가지고 그 모델과 관련된 기능을 세분화하여 객체처럼 사용할 수 있게 하는 프로그래밍 방식입니다.
그림으로 간단하게 설명하겠습니다.
Car car =new Car()라는 생성자를 통해 자동차 모델을 만듭니다.
car.Go();
car.Back();
과 같이 객체를 하나씩 가져와 사용할 수 있는걸 객체지향이라고 부릅니다.
SOLID란
SOLID란?
위에서 설명한 것처럼, JAVA의 객체지향적인 프로그래밍 관점을 기반으로 만들어진 스프링은 SOLID 설계 원칙을 적용하여 개발된 프레임워크로 볼 수 있습니다
SOLID는 객체지향 프로그래밍 및 설계의 다섯 가지 기본 원칙을 요약한 것입니다. 이 개념은 로버트 C. 마틴이 2000년대 초반에 제시했으며, 마이클 페더스가 이를 두 글자로 약어 화한 것입니다. SOLID는 다음과 같은 다섯 가지 원칙으로 구성됩니다.
- S - Single Responsibility Principle (단일 책임 원칙): 클래스는 하나의 책임만 가져야 하며, 그 책임을 완전히 캡슐화해야 합니다.
- O - Open/Closed Principle (개방 폐쇄 원칙): 클래스는 확장에 대해 열려 있어야 하지만, 수정에 대해서는 닫혀 있어야 합니다. 즉, 기존의 코드를 변경하지 않고도 새로운 기능을 추가할 수 있어야 합니다.
- L - Liskov Substitution Principle (리스코프 치환 원칙): 서브 타입은 언제나 기반 타입으로 교체할 수 있어야 합니다. 이는 상속을 사용할 때 하위 클래스가 상위 클래스의 기능을 완전히 대체할 수 있어야 함을 의미합니다.
- I - Interface Segregation Principle (인터페이스 분리 원칙): 클라이언트는 자신이 사용하지 않는 메서드에 의존하지 않아야 합니다. 큰 인터페이스보다는 작은 여러 개의 인터페이스가 더 좋습니다.
- D - Dependency Inversion Principle (의존성 역전 원칙): 고수준 모듈은 저수준 모듈에 의존하면 안 되며, 둘 모두 추상화에 의존해야 합니다. 이는 추상화된 인터페이스를 통해 의존성을 주입하는 방식으로 구현됩니다.
스프링에서의 객체지향적용
웹사이트에서 아이디 비밀번호 찾기 시에 사용될 로직이 버전 1과 버전 2가 있다고 가정하고 설명하도록 하겠습니다.
다음과 같이 EmailService로 구현한 로직에는 비밀번호 찾기 이메일 로직과 비밀번호 찾기 버전2 로직이 들어있습니다. 만약 버전1을 사용하기 위해서 한다면 다음과같이 작성할 것입니다.
private final FindPwdEmail findPwdEmail;
하지만 이렇게 사용한다면 EamilService에도 의존하고 findPwdEmail에도 의존하는 상태가 됩니다. 이러면 DIP을 위배하는 코드가 됩니다. 다음과 같은 상태가 됩니다. 반대로 비밀번호 찾기 버전 2를 했을 때도 DIP를 위배하는 상태가 됩니다.
그래서 SOLID 원칙처럼 구체클래스의 의존하면 안 되고 인터페이스의 의존하는 코드로 작성해야 합니다.
private final EmailService에 의존하는 코드로 작성해야 합니다.
그러면 인터페이스에 의존하고 있는데 어떻게 비밀번호 찾기? 와 아이디 찾기? 구현체를 사용할 수 있게 해 줄까?라는 생각이 들 수 있습니다. 그래서 스프링은 동적으로 구체클래스를 주입해 주는 DI(의존성 주입)을 통해서 가능하게 해 줍니다.
스프링에서는 @Configuration 어노테이션이 붙은 설정 파일을 통해 @Bean 어노테이션이 붙은 메서드를 정의할 수 있습니다. 이 메서드들은 스프링 컨테이너에 빈으로 등록되며, 이때 해당 빈은 인터페이스를 구현한 클래스의 객체일 수 있습니다. 따라서 런타임 시에 스프링은 이러한 빈을 필요한 곳에 주입하여 동적으로 구현 클래스를 교체할 수 있게 됩니다. 이를 통해 코드의 변경 없이도 구현 클래스를 변경하거나 확장할 수 있습니다.
@Configuration
public class Config {
@Bean
public FindInfoService findInfoService() {
return new FindInfoServiceImpl(findPwdEmailService());
}
@Bean
public EmailService emailService() {
return new FindPwdEmailService();
}
}
만약 이메일 버전 2를 사용하고 싶다면 new FindPwdv2 Email을 사용하면 됩니다.
위 그림과 같이 런타임 시에 Config 설정파일이 주입해 주는 다이어그램입니다. findPwdV2 Email을 사용한다면 Config는 findPwdV2Email을 생성해 줍니다.
'Spring > spring' 카테고리의 다른 글
[Spring] 스프링 컨테이너와 싱글톤 컨테이너 (0) | 2024.02.29 |
---|---|
[Spring] "객체지향 디자인 패턴 이해하기: 템플릿 메서드, 전략, 콜백" (1) | 2024.02.07 |
[Spring] 스프링에서의 필터(filter)와 인터셉터(Interceptor) (1) | 2024.02.06 |
[스프링] AOP(Aspect-Oriented-Programming)이해 (0) | 2023.11.22 |
[스프링] 트랜잭션(Transaction)이란 (0) | 2023.11.22 |