개발/Java

[객체지향] SOLID 원칙 (객체지향 설계 5원칙)

뚜키 💻 2022. 3. 7. 00:45
반응형

 

 

[객체지향] SOLID 원칙 (객체지향 설계 5원칙)

 

 

* 설계원칙 SOLID

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

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

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

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

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

 


 

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

클래스는 단 한개의 책임을 가져야 한다

 

왜?

  클래스가 여러 책임을 갖게되면 그 클래스는 각 책임마다 변경되는 이유가 발생하기 때문

 

어려움

  한 개의 책임에 대한 정의가 명확하지 않고, 책임을 도출하기위해서는 많은 경험이 필요

 

어기면?

  재사용을 어렵게 함

 

 

 

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

확장에는 열려있어야 하고, 변경에는 닫혀있어야 한다.

= 기능을 변경하거나 확장 할 수 있으면서 그 기능을 사용하는 코드는 수정하지 않는다

(ex. 추상화, 다형성(상속..)을 이용해서 개방 폐쇄 원칙 구현)

 

 

개방 폐쇄 원칙을 어기는 코드의 전형적인 특징?

  - 다운 캐스팅을 한다

  - 비슷한 if-else 블록이 존재한다

 

 

개발 폐쇄 원칙은 변경의 유연함과 관련된 원칙

  만약 기존 기능을 확장하기위해 기존 코드를 수정해주어야한다면 새로운 기능을 추가하는 것이 점점 힘들어짐

 

개방 폐쇄 원칙은 변화가 예상되는 것을 추상화해서 변경의 유연함을 얻도록 함

  변화되는 부분을 추상화하지 못하면(안하면) 개방 폐쇄 원칙을 지킬 수 없게 되어 시간이 흐를수록 기능 변경이나 확장을 어렵게 만듦

 

 

 

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

상위 타입의 객체를 하위 타입의 객체로 치환해도 상위 타입을 사용하는 프로그램은 정상적으로 동작해야한다

 

 

상위타입 (SuperClass), 하위타입 (SubClass)가 있다고 생각해보자

public void someMethod (SuperClass sc) {
	sc.someMethod();
}

someMethod()는 상위 타입인 SuperClass타입의 객체를 사용하고 있는데, 이 메서드에 다음과 같이 하위 타입의 객체를 전달해도 someMethod()가 정상적으로 동작해야 한다는 것이 리스코프 치환 원칙

someMethod(new SubClass());

 

* 리스코프 치환 원칙이 제대로 지켜지지 않으면 다형성에 기반한 OCP(개방 폐쇄 원칙)도 지켜지지 않기 때문에 잘 지키는게 중요

 

리스코프 치환 원칙은 계약과 확장에 의한 것

* 위반 사례

- 명시된 명세에서 벗어난 값을 리턴한다.

- 명시된 명세에서 벗어난 익셉션을 발생한다.

- 명시된 명세에서 벗어난 기능을 수행한다.

 

=> 비정상적으로 동작할 수 있기때문에, 하위 타입은 상위 타입에서 정의한 명세를 벗어나지 않는 범위에서 구현해야 한다.

 

 

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

인터페이스는 그 인터페이스를 사용하는 클라이언트를 기준으로 분리해야한다

 

 

* 인터페이스 분리 원칙은 자신이 사용하는 메서드에만 의존해야 한다는 원칙

 

 

 

5. DIP (Dependency Inversion Principle) - 의존 역전 원칙

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

 

고수준 모듈?

  어떤 의미있는 단일 기능을 제공하는 모듈

 

저수준 모듈?

  고수준 모듈의 기능을 구현하기 위해 필요한 하위 기능의 실제 구현

 

ex)

고수준 모듈

  - 바이트 데이터를 읽어와 암호화하고 결과 바이트 데이터를 쓴다

저수준 모듈

  - 파일에서 바이트 데이터를 읽어온다

  - AES 알고리즘으로 암호화한다

  - 파일에 바이트 데이터를 쓴다

 

저수준 모듈의 변경이 고수준 모듈의 변경을 초래하게되면 프로그램의 변경을 어렵게 만든다

 

고수준 모듈 -> 저수준 모듈 사용 = 의존한다 => 추상화로 저수준 모듈이 고수준 모듈을 의존하게 변경

 

* 소스코드상에서의 의존은 역전되었지만 런타임에서의 의존은 고->저

* 의존 역전 원칙은 변경의 유연함을 확보할 수 있도록 만들어주는 원칙

* 의존 역전 원칙은 타입의 소유도 역전시킨다

=> 타입의 소유 역전은 각 패키지를 독립적으로 배포할 수 있도록 만들어준다 (jar, ddl등..)

 

 

 


SOLID 정리

변화에 유연하게 대처할 수 있는 설계 원칙

 

SRP 단일 책임 원칙

OCP 개방 폐쇄 원칙

LSP 리스코프 치환 원칙

ISP 인터페이스 분리 원칙

DIP 의존 역전 원칙

 

SRPISP는 객체가 커지지 않도록 막아줌

  객체가 많은 기능을 가지면, 객체가 가진 기능의 변경 여파가 그 객체의 다른 기능에까지 번지게되고 다른 기능을 사용하는 클라이언트에게까지 영향을 준다.

  객체가 단일 책임을 갖게하고 클라이언트마다 다른 인터페이스를 사용하게 함으로써 한 기능의 변경이 다른 곳에까지 미치는 영향을 최소화하고, 기능 변경을 더 쉽게한다

 

LSPDIPOCP를 지원함

  OCP는 변화되는 부분을 추상화하고 다형성을 이용함으로써 기능 확장을 하면서도 기존 코드를 수정하지 않도록 만들어준다.

  여기서 변화되는 부분을 추상화 할 수 있도록 도와주는 원칙이 DIP, 다형성을 도와주는 원칙이 LSP

 

SOLID 원칙은 사용자입장에서의 기능 사용을 중시

  ISP는 클라이언트 입장에서 인터페이스를 분리하고

  DIP는 저수준 모듈을 사용하는 고수준 모듈 입장에서 추상화 타입 도출을 유도하고

  LSP는 사용자에게 기능 명세를 제공하고, 그에 따라 기능 구현할 것을 약속한다.

  이처럼 SOLID 원칙은 사용자 관점에서의 설계를 지향한다

 

 

 

 

 

 

 

Reference

책 객체지향과 디자인 패턴 (최범균)

 

 

 

 

반응형