Search
Duplicate
🌉

SOLID

객체지향적으로 설계를 할때, 지켜주면 유지보수하기에 좋은 원칙이다.
왜 유지보수를 할까? ⇒ ‘소프트’웨어다. 하드웨어와 달리 처음 그 설계를 유지하지 않고 변경될 가능성이 있다.
객체에게 데이터를 요구(ask)하지 말고 직접 하게 만들어라.
데이터는 가급적 캡슐화하는 것이 좋다. 즉 정보를 제한시켜 결합도를 낮추는 것이 유지보수에 도움이 된다.

단일 책임의 원칙 (Single Responsiblity Principle)

하나의 클래스는 하나의 책임을 가지는 것이 좋다.
there should never be more than one reason for a class to change again. 또는 A class should have one, and only one, reason to change.
책임이란 기준이 추상적이기 때문에 로버트 마틴은 변경의 이유를 책임의 기준으로 삼으면 설계에 용이할 수 있다고 했다.
구체적인 단일 기능에 대해서 책임을 부여하자.
동일한 이유로 변경되는 것들은 모아두고 다른 이유로 변경되는 것은 분리시킨다. 즉, 하나의 클래스에는 하나의 기능만 넣어라는 뜻이다.
그렇다면 하나의 관심사를 하나의 클래스만 담당해야하는 이유는 무엇일까? 이것은 유지보수성을 향상시켜주기 때문이다.
하나의 클래스에서 다양한 관심사를 관장하게될 경우, 지속적인 변경이 발생하고 이는 자칫 버그를 발생시킬 위험을 높이게 된다. 다양한 변경 이유가 있는 클래스는 불안정하다.
하나의 클래스가 충분히 커졌다면 분리를 고민해보자. 각 메소드들의 연관 관계를 이해해보고 동떨어진 친구가 있다면 그 친구는 다른 수행자 만들어 그에게 보내주자.
이렇게 나눠진 클래스들을 잘 조합해서 사용한다면 유지보수가 어렵지 않은 클래스를 설계할 수 있을 것이다.

개방 폐쇄의 원칙 (Open Closed Principle)

높은 응집도와 낮은 결합도를 유지하라는 뜻이다.
You should be able to extend a classes behavior, without modifying it.
확장에 열려있고 변경에 닫혀있다. 이게 무슨 말일까?
software entities, which basically means classes or modules or methods software entities should be open for extension but closed for modification.
확장에 열려있다는 말은 새로운 변경사항이 발생했을 때 유연하게 코드를 추가, 수정할 수 있어야 한다는 것이다.
변경에 닫혀있다는 말은 확장 시 기존 코드를 수정하지 않고도 변경사항을 적용할 수 있어야 한다는 것이다.
확장될 가능성이 있는 메소드나 클래스는 추상화하여 구현한다. 새로운 기능이 추가되는 경우, 해당 인터페이스를 주입한다면 기존 다른 코드들은 수정하지 않아도 된다.
상속을 예시로 들면 좋을 것 같다.
Crystal Ball은 없다.
미래의 요구사항을 예측할 수 없기 때문에 경험에서 비롯한 예측을 통해서 OCP를 지켜보자.

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

B가 A를 상속받는다면 B는 A의 역할을 그대로 수행할 수 있어야 한다.
하위 타입이 상위 타입의 역할을 수행하는 것이 불가하다면 하위 타입을 사용하는 클래스에서의 버그 가능성을 의심해보아야 한다.
Behavior, 즉 수행에 초점을 맞춰서 이해해야 한다!!
예시를 하나 들어보자.
직사각형을 상속한 정사각형이 있다. 이 직사각형은 setHeightsetWidth 메소드가 있다.
정사각형은 직사각형과 달리 높이와 밑변이 같아야한다.
만약 setHeight을 통해서 정사각형의 높이를 변경해버린다면? 정사각형이 아니게 되어버릴 것이다.
직사각형의 메소드인 setHeight, setWidth 메소드를 없애버린다면? 불변해지므로 정사각형 클래스가 직사각형 클래스의 메소드들을 정상적으로 수행해낼 수 있다.
리스코프 치환 원칙을 지키려면 다음과 같은 항목들을 강제해야한다.
하위형에서 메서드 인수의 반공변성
하위형에서 반환형의 공변성
하위형에서 메소드는 상위형 메소드에서 지정한 예외 이외의 다른 예외를 던질 수 없다.
하위형에서 선행조건은 강화될 수 없다.
하위형에서 후행조건은 약화될 수 없다.
하위형에서 상위형의 불변조건은 반드시 유지되어야 한다.

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

클래스는 자신의 책임이 아닌 것에 영향을 받으면 안 된다.
범용 인터페이스 하나보다는 특정 클라이언트를 위한 여러 개의 인터페이스 분리가 더 좋다는 뜻이다. 어렵다.
지나치게 많은 책임을 가지고 있는 인터페이스는 결합도를 높인다.
인터페이스를 응집도를 높이고 결합도를 낮추기 위해 사용했지만 적절히 사용하지 못했을 경우, 되려 역효과가 날 수 있다는 뜻이다.
인터페이스를 추상적으로 정의하고 추상화 수준을 점차 낮춰가면서 클래스나 인터페이스를 설계하자. 추상화 수준이 높을수록 수행할 수 있는 역할은 제한적이어야 한다.

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

고수준 모듈은 저수준 모듈의 구현에 의존해서는 안 된다. 저수준 모듈이 고수준 모듈에서 정의한 추상 타입에 의존해야 한다.
즉 추상적인 것이 구체적인 것에 의존해서는 안 된다는 뜻이다.
그렇다면 고수준 모듈에서 사용하는 저수준 모듈을 추상화해야할 것이다. 이때 인터페이스를 사용할 수 있다.
자동차라는 고수준 모듈에서 겨울철 타이어라는 저수준 모듈을 의존하는 상황에서 이런 의존성을 역전시키고 싶다.
타이어라는 추상 타입을 인터페이스로 만들어서 자동차는 타이어를 의존하게 하는 것이다.
겨울철 타이어, 여름철 타이어 등은 타이어를 의존하게 되면서 의존성이 역전된다.