OOP의 SOLID 알아보기

프로그래밍/자바2021. 4. 30. 11:22

OOP에서 SOLID는 객체지향에서 어떻게 개발하면 좋다에 대한 5가지 원칙에서 앞 글자를 따온 이름입니다.

 

Single Responsibility Principle

Open-closed Principle

Liskov Substitution Principle

Interface Segregation Principle

Dependency Inversion Principle

 

인터넷에 검색해보면 이에 대한 내용이 좀 있으나 이해가 잘 되는 글이 없어서 직접 정리해보려고 합니다.

 

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

클래스를 설계할 때 각 클래스는 하나의 일만(only one job) 하도록 설계하자는 원칙입니다. 하나의 일을 어떻게 봐야하나 좀 애매하지만 대충 느낌은 옵니다. 하나의 함수를 의미하는 것이 아니라 하나의 주제?에 맞는 일을 해야합니다. 하나의 클래스에서 여러 일을 한다면 클래스를 쪼개서 하나의 일만 하도록 수정해야 합니다.

이는 Highly Cohesive와도 관련있는 내용 같습니다.

 

 

2. Open-closed Principle

클래스는 확장에는 열려있고 수정에는 닫혀있어야 한다는 원칙입니다. 이 말만 들으면 사실 이해가 잘 안됩니다. 

확장은 새 기능을 추가하는 것을 의미하고, 수정은 말 그대로 기존 클래스의 코드를 수정하는 것을 의미합니다.

이 말을 좀 더 쉽게하면 기존 코드를 수정하지 않고 새 기능 추가가 가능해야한다는 말입니다.

 

저는 처음에 그냥 클래스에 새 함수를 추가하면 되는 것이 아닌가 했는데 항상 그렇게 되는 것 같지 않습니다. 

경우에 따라서는 기존 함수에 새 기능과 관련된 코드를 추가해야 하는 경우도 있을 것입니다. 그런데 이렇게 되면 Open-closed principle을 위배하게 됩니다. 동작이 잘 되는 기존 코드를 수정한다는 것은 상당한 리스크가 있습니다.

 

여기서 중요한 것은 java의 interface입니다. 애초에 설계를 잘 해서 새 기능을 추가할 때 기존 함수를 수정하는 것이 아니라 interface에 기능 추가와 관련된 추상 함수를 추가하고 이를 구현(implements)하는 함수에서 그 클래스를 정의하도록 하면 됩니다.

 

3. Liskov Substitution Principle

리스코프의 치환 법칙은 자식 클래스가 부모 클래스를 치환할 수 있어야 한다는 법칙입니다.

부모 클래스를 A, 이를 상속받는 클래스를 B라고 했을 때, 클래스 A를 인자로 받는 함수에 클래스 B를 넘겨도 문제없이 잘 동작해야한다는 이야기입니다.

 

이는 클래스의 상속에 의해 자연스럽게 만족될까요?. 자식 클래스는 부모 클래스의 기능을 확장하고 줄이지는 않으니까요. 그런데 어떤 경우는 자식 클래스에서 @Override를 통해 재 정의한 함수로 인해 리스코프의 치환법칙을 위배하게 되는 경우도 있습니다.

 

하단 참고 부분의 영어 강좌들을 보면 이 예제에 대한 긴 설명이 있습니다.

 

reflectoring.io/lsp-explained/

왜 이 법칙이 필요한지에 대한 설명을 찾아봤는데 위 링크에 그 내용이 좀 있는 것 같습니다.

리스코프의 치환 법칙을 위배한다면.. 부모 클래스 A를 인자로 하는 함수에선 동작이 잘 되도록 instanceof 체크 구문을 넣어야하는데 유지측면에서 좋지 않은 방법입니다. 기존에 잘 작성하던 함수를 수정해야하는 것이니까요.

 

 

4. Interface Segregation Principle

인터페이스 분리 법칙은 말 그대로 인터페이스를 분리하는 것을 의미합니다.

1개의 범용적으로 쓰이는 인터페이스보단 필요?에 따라 여러 인터페이스를 갖는 것이 더 좋습니다.

범용적인 인터페이스로 인해 이를 구현하는 어떤 클래스는 자신에게 필요없는 함수까지 구현해야할 수 있습니다.

 

5. Dependency Inversion Principle

DDD에서도 배운 내용입니다.

상위 모듈에서 하위 모듈을 사용하는데, 그냥 일반적으로 설계를 하면 상위 모듈이 하위 모듈에 의존하게 됩니다. 하위 모듈이 바뀌기라도 한다면 상위 모듈도 따라 변경될 수 있어 올바르지 않습니다.

 

그래서 이런 경우에 상위 모듈에서 사용하는 하위 모듈의 특정 함수들에 대해 인터페이스로 정의합니다.

상위 모듈에선 하위 모듈을 바로 사용하는게 아니라 이 인터페이스의 함수들을 접근합니다.

그리고 하위 모듈은 이 인터페이스를 구현해서 상위 모듈이 문제없이 동작되도록 하면됩니다.

하위 모듈이 변경되는 경우를 생각해보면, 변경된 하위 모듈만 인터페이스를 잘 구현하도록 하면 됩니다.

 

 

참고

www.freecodecamp.org/news/solid-principles-explained-in-plain-english/

www.digitalocean.com/community/conceptual_articles/s-o-l-i-d-the-first-five-principles-of-object-oriented-design

 

작성자

Posted by 드리머즈

관련 글

댓글 영역