[Spring] 01. 객체 지향 설계와 스프링

김동현·2024년 3월 28일
0

스프링이란?

Spring은 무엇인가?

  • Java 기반의 애플리케이션 프레임워크
  • 스프링 프레임워크
    • 핵심 기술 : 스프링 DI 컨테이너, AOP, 이벤트, 기타
    • 웹 기술 : 스프링 MVC, 스프링 WebFlux
    • 데이터 접근 기술 : 트랜잭션, JDBC, ORM, XML
    • 기술 통합 : 캐시, 이메일, 원격접근, 스케줄링
    • 테스트 : 스프링 기반 테스트
  • 스프링 부트
    • 스프링을 편리하게 사용할 수 있도록 지원
    • 단독으로 실행할 수 있는 스프링 애플리케이션을 쉽게 생성 가능
    • 웹 서버를 내장하고 있음
    • 손쉬운 빌드 구성을 위한 starter 종속성
    • 스프링과 외부 라이브러리 자동 구성
    • 메트릭, 상태 확인, 외부 구성과 같은 프로덕션 준비 기능
  • 스프링을 사용하는 이유?
    • 자바 언어 기반의 프레임 워크로 객체 지향 언어의 장점을 잘 살려낸다.
    • 스프링을 통해 좋은 객체 지향 애플리케이션을 개발할 수 있도록 해준다.

좋은 객체 지향 프로그래밍

스프링은 통해 좋은 객체 지향 애플리케이션을 개발한다는데, 그렇다면 좋은 객체 지향 프로그래밍이란 무엇인가?

  • 컴퓨터 프로그램을 객체라는 여러개의 독립된 단위들의 모임으로 생각할 수 있고, 각 객체는 메시지를 서로 주고 받으며 데이터를 처리함.
  • 객체 지향 프로그래밍은 유연하고 변경에 용이하기 때문에 대규모 소프트웨어 개발에 사용됨
    • 객체를 쉽게 갈아 끼울 수 있음
    • 다형성을 통해 역할과 구현을 분리하여, 역할에만 의존하도록 하여 구현 부분을 자유롭게 갈아끼울 수 있음
    • 클라이언트를 변경하지 않고, 서버의 구현 기능을 유연하게 변경할 수 있음
public class UserService {
	private UserRepository userRepository = new MemoryUserRepository;
    private UserRepository userRepository = new JpaUserReposiotory;
}

유저 서비스는 유저 레포지토리의 구현에 의존하지 않고, 역할만에 의존함.
즉, 구현한 클래스가 아닌 역할을 지정한 인터페이스 만으로 서비스를 할 수 있음.

public interface UserRepository {
	void save();
    User findById(Long id);
}
public class MemoryUserRepository implement UserRepository {
	@Override
    void save() {
    	...
    }
    
	@Override
    User findById(Long id) {
    	...
    }
}
public class JpaUserRepository implement UserRepository {
	...
}

구현 클래스는 명세된 역할을 구현하기만 하면 되며, 자유롭게 바꾸어 낄 수 있음.

  • 역할과 구현을 분리하여 다형성을 가능하게 하였고, 이는 스프링에서 IoC(제어의 역전), DI(의존관계 주입)을 편리하게 사용할 수 있도록 지원함

SOLID 원칙

  • 좋은 객체 지향 설계의 5가지 원칙

SRP(Single Responsibility Principle) - 단일 책임 원칙

  • 하나의 클래스는 하나의 책임만 가져야 한다. 하나의 클래스는 하나의 기능만을 담당하여 하나의 책임을 수행하는 데에 집중해야 함.
  • 책임의 크기는 어떻게 정하는가? 정하기 애매하다...
  • 변경을 기준으로 책임을 부여하면 효과적임. 변경이 있을 때 파급 효과가 적다면 SRP를 잘 따랐다고 할 수 있다.
  • 장점
    • 한 책임의 변경으로부터 다른 책임의 변경으로의 연쇄작용에서 자유로울 수 있음
    • 코드의 가독성 향상
    • 유지보수 용이
  • 어떻게 지킬 수 있는가?
    • 클래스명에 책임을 분명하게 나타낼 수 있도록 작성한다.
    • 책임을 분리할 때, 결합도와 응집도를 고려하여 분리한다. 응집도는 높게, 결합도는 낮게 설계한다.

OCP(Open Closed Principle) - 개방 폐쇄 원칙

  • 소프트웨어 요소는 "확장"에는 열려 있으나, "변경"에는 닫혀 있어야 함
  • 다형성을 활용하여 기능과 구현을 분리하였지만, 구현을 바꾸기 위해서는 클라이언트의 코드를 변경해야 함. 즉, 확장을 하기 위해서 클라이언트 코드를 변경해야 해 OCP 원칙을 위반하는 경우가 발생한다.
  • 이는 객체를 생성하고, 연관관계를 맺어주는 별도의 설정자가 필요하게 됨. 스프링의 컴포넌트 스캔과 Autowired가 이를 해결해 줌.(Dependency Injection)

LSP(Liskov Substitution Principle) - 리스코프 치환 원칙

  • 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 함.
  • 구현 클래스는 기능 인터페이스에서 정한 규칙을 모두 지켜야 함.

ISP(Interface Segregation Principle) - 인터페이스 분리 원칙

  • 인터페이스를 명확하게 분리해야지, 특정 인터페이스를 변경해도 다른 인터페이스에 영향을 주지 않음
  • 보다 더 쉽게 대체할 수 있게 됨.

DIP(Dependency Inversion Principle) - 의존관계 역전 원칙

  • 프로그램을 작성할 때, 구체화가 아닌 추상화에 의존하도록 함. 즉, 구현 클래스가 아닌 인터페이스에 의존하도록 하지만, 실제로는 구현 클래스를 선언해주어야 함.
  • 이러한 문제를 해결해주기 위해서 의존관계 주입을 해주는 컨테이너를 통해 구현 클래스에 의존하지 않는 클래스를 만들 수 있도록 함.
profile
I'm Donggle

0개의 댓글