객체지향의 5대 원칙 (SOLID)
모듈 규모의 소프트웨어 구조가 유지보수성, 가독성, 낮은 결합도, 높은 응집도를 만족하도록 하는 것 을 말한다.
SRP(Single Responsibility Principle) 단일 책임의 원칙
하나의 모듈은 하나의 액터(변경을 요청하는 사용자, use case에 요청을 하는 사람 혹은 사물, *domain은 책임의 범위다.)에 대해서만 책임져야 한다. (단일 태스크 X)
예를 들어 학생 class에 식사, 공부, 놀기 등의 3가지 메소드가 있다고 가정해 보자
class 학생 {
식사()
공부()
놀기()
}
식사 메소드는 학생이 편식하지 않고 밥을 잘 먹었는지 확인 하기 위해 급식 영양 관리소에서 요청을 한다.
공부 메소드는 학생이 공부를 하였는지 확인하기 위해 성적 관리소에서 요청을 한다.
놀기 메소드는 학생이 선호하는 놀이를 확인하기 위해 여과시간 관리소에서 요청을 한다.
이렇게 하나의 학생 class에 3가지 엑터가 존재하게 된다.
이경우 식사를 관리하는 영양관리소에서 학생이 좋아하는 음식을 위주로 제공하게 되면
학생은 과식을 하게 되여 수업시간에 졸아 성적 관리소에 영향을 주게 된다.
이런식으로 여러 액터가 하나의 모듈에 존재하게 되면 액터간의 의존성에 의해 문제가 발생하는 경우가 존재하게 된다.
그럼으로 하나의 모듈은 하나의 액터에 대해서만 책임 져야 된다.
하지만 이경우 사용자의 사용성을 떨어뜨릴 수 있는데 이를 해결하기 위해서는 (특정 행위를 하는 모듈을 액터 별로 나눔으로) 유사한 액터들을 묶어 사용하여 사용성을 높이는 것을 퍼사드(Facade) 패턴을 통해 해결가능하다.
유사한 액터들을 묶는다는 의미는
식사, 공부, 놀기등의 일부를 퍼사드로 묶어 사용하는 것을 말한다.
이때 퍼사드에는 코드가 거의 존재 하지 않고 원하는 메소드등을 가지는 객체들을 엮어 식사, 공부와 같이 학교에서 이루어지는 메소드들을 가지고 있는 객체를 엮는 것을 말한다.
class 학생 퍼사드 {
식사()
공부()
}
OCP(Open-Closed Principle) 개방-폐쇄 원칙
객체는 확장에는 개방되어 있어야 하고 수정에는 폐쇄적이여야 한다는 이야기이다.
여기서 개방의 의미는 새로운 데이터나 함수등을 추가하는 것이 가능해야함을 의미하고
폐쇄의 의미는 내부 데이터를 수정해도 다른 부분에 영향을 미치지 않아야 한다는 의미이다.
클래스 단위에서 개방 폐쇄
모든 멤버변수는 private와 protected여야 한다.
내부 변수의 변화가 사용자에게 의도하지 않게 피해를 줄 수 있기 때문이다.
그럼으로 글로벌 변수등은 지양해야 한다.
이러한 문제를 예방하기 위해 추상클래스를 많이 이용하는데
추상클래스를 이용하여 사용자에게 메소드와 같은 필요한 부분만 개방하고 수정시 문제를 일으킬 수 있는 변수를 폐쇄하기 편하기 때문이다.
모듈단위에서 폐쇄
의존 관계를 설정하여 같은 관계에 존재하지만 직접 import하는 것이 아닌 해당 모듈을 import하는 모듈을 import하면 높은 클래스 수준의 모듈이 하위 모듈로 부터 보호가 되게 된다.
LSP(Liskov Substitution Principle) 라스코프 치환의 원칙
상위 타입의 컴포넌트를 하위 타입의 컴포넌트로 치환하여도 상위 타입 사용이 가능한 것을 말한다.
Repository와 datasource간의 관계 및 자바에서 흔히 사용하는 부모 자식간의(업캐스팅) 부모와 자식들 간의 다형성등이 라스코프 치환의 예이다.
ISP(Liskov Substitution Principle) 인터페이스 분리 원칙
각각의 모듈은 자신이 사용하지 않는 모듈에 대해 의존하지 말아야 된다는 원칙이다.
여러 기능을 가진 인터페이스가 있다면 이를 다시 작게 나누어 사용하는 것을 말한다.
예를 들어 인터페이스 A에 기능 1, 2, 3이 있다고 가정하고 사용자 a, b, c가 각각 기능 1, 2, 3 하나씩만을 이용할 경우
인터페이스 a`, b`, c`를 만들고 각각의 인터페이스 마다 기능 1, 2, 3 하나씩만 가지고 있어 사용자 a는 a`인터페이스를 b는 b`인터페이스를 구현하는 식으로 인터페이스 분리하는 것을 말한다.
Interface A {
fun 1()
fun 2()
fun 3()
}
class a : A {
override fun 1() {..}
override fun 2() {..} //사용 안함
override fun 3() {..} //사용 안함
}
Interface a` {
fun 1()
}
class a : a` {
override fun 1() {..}
}
DIP(Dependency Inversion Principle) 의존성 역전 원칙
추상성과 안정성이 높은 고수준의 코드 에서는 낮은 수준에서의 세부사항 구현에 의존해서는 안된다는 원칙이다.
일반적으로 인터페이스를 사용하는 것을 말하는데 인터페이스를 구현하는 저수준의 클래스에서는 인터페이스(고수준)만 바라보게 되어 저수준에서는 인터페이스의 메소드를 원하는대로 구현이 가능하고 인터페이스(고수준)에서는 저수준(인터페이스를 implement하는 클래스)에 영향을 받지 않는다.
'객체지향' 카테고리의 다른 글
솔리드 5대원칙 개념 정리 및 코틀린 예제 (0) | 2025.01.16 |
---|