공부/SPRING

SOLID 란?

junani0v0 2024. 4. 10. 16:39

SOLID는 좋은 객체 지향 설계의 5가지 원칙을 말한다

 

• SRP: 단일 책임 원칙(single responsibility principle)

• OCP: 개방-폐쇄 원칙 (Open/closed principle)
• LSP: 리스코프 치환 원칙 (Liskov substitution principle)
• ISP: 인터페이스 분리 원칙 (Interface segregation principle)
• DIP: 의존관계 역전 원칙 (Dependency inversion principle)

 

이렇게 5가지이며 이 5가지를 하나씩 알아보자

 

1. SRP 단일 책임 원칙

한 클래스는 하나의 책임만을 가져야 한다

쉽게말해 변경을 했을때 파급이 적게하는게 단일 책임 원칙을 다른것

극단적인 예로 UI하나의 변경을 하는데 SQL,애플리케이션 등 여러가지를 변경해야한다면 단일 책임 원칙을 잘 따르지 못한 잘못된 설계라 할 수 있으며 객체의 생성과 사용을 분리하는게 좋으며

변경 범위가 있을때 하나의 클래스만 변경할 수 있게 설계할 수 있으면 단일 책임 원칙을 지켰다 할 수 있다

 

2. OCP 개방-폐쇄 원칙

소프트웨어 요소는 확장에는 열려있고, 변경에는 닫혀있어야 한다

자바의 다형성을 활용하면 이 개방-폐쇄 원칙은 잘 지킬 수 있다

ex)사용자가 노트북을 lg그램을 사용하다 hp,dell등의 다른회사 제품으로 변경을해도 잘 사용할 수 있는것과 같다 

사용법은 같기에 기종을 바꾸더라도 사용하는데 문제가 없다

 

OCP 개방-폐쇄 원칙 문제점

구현 객체를 변경하려면 클라이언트 코드를 변경해야한다

분명 다형성을 사용했지만 OCP원칙을 지킬 수 없다

 

이러한 문제점을 해결하기 위해서는 객체을 생성하고, 연관관계를 맺어주는 별도의 조립, 설정자가 필요

 

3. LSP 리스코프 치환 원칙

프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다

다형성에서 하위 클래스는 인터페이스 규약을 다 지켜야 한다는 것, 다형성을 지원하기 위한 원칙, 인터페이스를 구현한 구현체는 믿고 사용하려면, 이 원칙이 필요

ex) 자동차 인터페이스에서 엑셀은 앞으로 가능 기능, 뒤로 가게 구현하면 컴파일에서는 성공하지만 LSP는 위반한 것, 속도가 느리더라도 앞으로 간다면 LSP를 잘 지킨 것이다.

 

4. ISP 인터페이스 분리 원칙

특정 클라이언트를 위한 인터페이스 여러개가 범용 인터페이스 하나보다 낫다

ex) 자동차 인터페이스 - > 운전 인터페이스, 정비 인터페이스로 분리

      사용자 클라이언트 - > 운전자 클라이언트, 정비사 클라이언트로 분리

즉, 기능이 너무 많으면 복잡하니 기능을 알맞게 쪼개서 개별관리하는 것

이렇게하면 인터페이스가 명확해지고, 대체 가능성이 높아진다

ex) 전기차라면 정비 인터페이스만 바꾸면 되기에 운전자쪽은 아무 영향도 주지 않을 수 있다

 

5. DIP 의존관계 역전 원칙

프로그래머는 "추상화에 의존해야지, 구체화에 의존하면 안된다." 의존성 주입은 이 원칙을 따르는 방법 중 하나이다.

즉, 클라이언트 코드가 구현 클래스에 의존하지 말고, 인터페이스에 의존하라는 뜻

ex)MemberService가 MemberRepository의 인터페이스만 바라보고 MeoryMemberRepository나JdbcMemberRepository에 대해선 몰라야한다

역활(Role)에 의존하게 해야한다. 객체 세상도 클라이언트가 인터페이스에 의존해야 유연하게 구현체를 변경할 수 있다. 구현체에 의존하게 되면 변경이 아주 어려워진다

 

 

< 정리 >

-모든 설계는 역활과 구현을 분리.

-애플리케이션 설계도 공연을 설계 하듯이 배역만 만들어두고, 배우는 언제든지 유연하게 변경할 수 있도록 만드는게 좋은 객체 지향 설계(이렇게 하기위해 스프링 컨테이너 사용)

-이상적으로는 모든 설계에 인터페이스를 부여

  장점 : 하부 구현부의 선택을 미루고 개발이 가능 나중에 확정이되면 그부분만 기능 확장

  단점 : 추상화라는 비용 발생 

  그래서 기능을 확장할 가능성이 없다면, 구체 클래스를 직접 사용, 향후 꼭 필요할 때 리팩터링해서 인터페이스를 도입