티스토리 뷰

1. 객체지향 프로그래밍의 5가지 설계 원칙, SOLID

SOLID란 객체 지향 프로그래밍을 하면서 지켜야하는 5대 원칙으로

각각 SRP(단일 책임 원칙), OCP(개방-폐쇄 원칙), LSP(리스코프 치환 원칙), DIP(의존 역전 원칙), ISP(인터페이스 분리 원칙)

SOLID 원칙을 철저히 지키면 시간이 지나도 변경이 용이하고, 유지보수와 확장이 쉬운 소프트웨어를 개발하는데 도움이 되는 것으로 알려져 있다.

[단일 책임의 원칙(SRP, Single Responsibility Principle)]

 • 모듈이 변경되는 이유가 한가지여야 한다.

→ 해당 모듈이 여러 대상 또는 액터들에 대해 책임을 가져서는 안되고, 오직 하나의 액터에 대해서만 책임을 져야 한다.

 • 단일 책임 원칙을 제대로 지키면 변경이 필요할 때 수정할 대상이 명확해진다.

 • SRP를 올바르게 판단하기 위해서는 유스케이스와 요구 사항등을 고려해야 함.

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

- 확장에 대해 열려있고 수정에 대해서는 닫혀있어야 한다는 원칙

 • 확장에 대해 열려 있다 : 요구사항이 변경될 때 새로운 동작을 추가하여 애플리케이션의 기능을 확장할 수 있다.

 • 수정에 대해 닫혀 있다 : 기존의 코드를 수정하지 않고 애플리케이션의 동작을 추가하거나 변경할 수 있다.

→ 개방 폐쇄 원칙을 지키기 위해서는 추상화에 의존해야 함.

✓ 추상화 : 핵심적인 부분만 남기고, 불필요한 부분은 제거함으로써 복잡한 것을 간단히 하는 것

 

기존에 userService에 암호화방식을 

private final SHA256PasswordEncoder passwordEncoder; 방식으로 사용하고 있었다고 하자.

이때 암호화 방식을 변경하라는 요구가 들어왔을 때, userService의 passwordEncoder의 클래스를 직접적으로 수정해주어야하는 문제가 발생한다. (OCP 위반)

이를 해결하기 위해서는 추상화를 통해 UserService가 구체적인 암호화 클래스에 의존하지 않고 PasswordEncoder라는 인터페이스에 의존하도록 추상화하면 OCP를 충족하는 코드를 작성할 수 있다.

→ private final PasswordEncoder passwordEncoder;

[인터페이스 분리 원칙(Interface segregation principle, ISP)]

- 목적과 관심이 각기 다른 클라이언트가 있다면 인터페이스를 통해 적절하게 분리해줄 필요가 있다.

- 즉, 인터페이스 분리 원칙이란 클라이언트의 목적과 용도에 적합한 인터페이스만을 제공하는 것이다.

- 인터페이스 분리 원칙을 준수함으로써 모든 클라이언트가 자신의 관심에 맞는 public interface만을 접근하여 불필요한 간섭을 최소화 할 수 있다. → 기존 클라이언트에 영향을 주지 않은 채로 유연하게 객체의 기능을 확장하거나 수정할 수 있다.

- 어떤 구현체에 부가 기능이 필요하다면 이 인터페이스를 구현하는 다른 인터페이스를 만들어서 해결할 수 있다.

예를 들어 비밀번호 암호화, 비밀번호일치확인 기능을 갖는 구현 클래스가 있는데, 어떤 클라이언트는 비밀번호 일치확인만을 필요로 한다면, 별도의 비밀번호 일치확인 인터페이스를 만들어 제공해준다. 이를 통해서 불필요한 내용을 알게하는 일이 없도록 할 수 있다.

 

[리스코프 치환 원칙(Liskov Substitution Principle, LSP)]

- 하위 타입은 상위 타입을 대체할 수 있어야 한다. (부모 클래스에 대한 클라이언트의 가정을 준수해야 한다)

- 즉, 해당 객체를 사용하는 클라이언트는 상위 타입이 하위 타입으로 변경되어도, 차이점을 인식하지 못한 채 상위 타입의 public interface를 통해 서브 클래스를 사용할 수 있어야 한다.

+ 위반사례

• 하위 클래스가 상위 클래스에서 선언한 기능을 위반하는 경우

• 하위 클래스가 입력, 출력 및 예외에 대한 상위 클래스의 계약을 위반하는 경우

• 하위 클래스가 상위 클래스의 주석에 나열된 특별 지침을 위반하는 경우

예를 들어 rectangle을 상속한 square이 있다고 하자.

여기서 square은 정사각형을 나타낸다. 

만약,

Rectangle rectangle = new Square();

resize(rectangle, 100, 150);

이와같이, resize의 파라미터로 square이 전달된다면, setWidth, setHeight에서 

@override한 square의 방식대로 작동할 것이다.

이는 원래 resize의 의도에 어긋나게되며, 따라서 이는 하위타입이 상위타입을 대체할 수 없음을 뜻한다.

[의존 역전 원칙(Dependency Inversion Princple, DIP)]

고수준 모듈은 저수준 모듈의 구현에 의존해서는 안되며, 저수준 모듈이 고수준 모듈에서 정의한 추상타입에 의존해야 한다는 것이다.

• 고수준 모듈 : 입력과 출력으로부터 먼(비즈니스와 관련된) 추상화된 모듈

• 저수준 모듈 : 입력과 출력으로부터 가까운(HTTP, 데이터베이스, 캐시등과 관련된) 구현 모듈

 

결국, 비즈니스와 관련된 부분이 세부 사항에는 의존하지 않는 설계 원칙을 의미

쉽게 말하면, 의존관계를 맺을 때 변화하기 쉬운 것, 또는 자주 변화하는 것에 의존하기 보다는, 변화하기 어려운 것, 거의 변화가 없는 것에 의존하라는 원칙이다.

 

저수준 클래스는 빈번하게 변경되고, 새로운 것이 추가될 때마다 고수준 클래스가 영향을 받기 쉬우므로 의존관계를 역전시켜야 한다.

 

예를들어, UserService를 SimplePasswordEncoder에 직접 의존하도록 하면, DIP가 위배된다.

그러므로 UserService가 변하지 않는 추상화에 의존하도록 변경이 필요하다.

이는 PasswordEncoder 인터페이스를 만들어 이에 의존하도록 변경하는 것이다.

DIP를 만족하면, 의존성 주입(DI)라는 기술로 변화를 쉽게 수용할 수 있는 코드를 작성할 수 있다.

 

 

결국 SOLID의 핵심은 추상화와 다형성이다.

구체 클래스에 의존하지 않고, 추상 클래스나 인터페이스에 의존함으로써

유연하고 확장가능한 애플리케이션을 만들 수 있다.

'Web > BackEnd' 카테고리의 다른 글

네트워크 기본 - IP란?, IP주소, PORT, DNS, URL, URI  (0) 2024.03.12
객체지향 프로그래밍 - OOP  (0) 2024.03.10
JPA란? Spring Data JPA란? Hibernate란?  (1) 2024.01.02
Mybatis란?  (0) 2024.01.02
SQL Mapper와 ORM  (1) 2024.01.02
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/12   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함