•
객체지향적으로 설계를 할때, 지켜주면 유지보수하기에 좋은 원칙이다.
•
왜 유지보수를 할까? ⇒ ‘소프트’웨어다. 하드웨어와 달리 처음 그 설계를 유지하지 않고 변경될 가능성이 있다.
객체에게 데이터를 요구(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, 즉 수행에 초점을 맞춰서 이해해야 한다!!
•
예시를 하나 들어보자.
◦
직사각형을 상속한 정사각형이 있다. 이 직사각형은 setHeight과 setWidth 메소드가 있다.
◦
정사각형은 직사각형과 달리 높이와 밑변이 같아야한다.
◦
만약 setHeight을 통해서 정사각형의 높이를 변경해버린다면? 정사각형이 아니게 되어버릴 것이다.
◦
직사각형의 메소드인 setHeight, setWidth 메소드를 없애버린다면? 불변해지므로 정사각형 클래스가 직사각형 클래스의 메소드들을 정상적으로 수행해낼 수 있다.
•
리스코프 치환 원칙을 지키려면 다음과 같은 항목들을 강제해야한다.
◦
하위형에서 메서드 인수의 반공변성
◦
하위형에서 반환형의 공변성
◦
하위형에서 메소드는 상위형 메소드에서 지정한 예외 이외의 다른 예외를 던질 수 없다.
◦
하위형에서 선행조건은 강화될 수 없다.
◦
하위형에서 후행조건은 약화될 수 없다.
◦
하위형에서 상위형의 불변조건은 반드시 유지되어야 한다.
인터페이스 분리 원칙 (Interface Segragation Principle)
•
클래스는 자신의 책임이 아닌 것에 영향을 받으면 안 된다.
•
범용 인터페이스 하나보다는 특정 클라이언트를 위한 여러 개의 인터페이스 분리가 더 좋다는 뜻이다. 어렵다.
•
지나치게 많은 책임을 가지고 있는 인터페이스는 결합도를 높인다.
•
인터페이스를 응집도를 높이고 결합도를 낮추기 위해 사용했지만 적절히 사용하지 못했을 경우, 되려 역효과가 날 수 있다는 뜻이다.
•
인터페이스를 추상적으로 정의하고 추상화 수준을 점차 낮춰가면서 클래스나 인터페이스를 설계하자. 추상화 수준이 높을수록 수행할 수 있는 역할은 제한적이어야 한다.
의존성 역전 원칙 (Dependency Inversion Principle)
•
고수준 모듈은 저수준 모듈의 구현에 의존해서는 안 된다. 저수준 모듈이 고수준 모듈에서 정의한 추상 타입에 의존해야 한다.
•
즉 추상적인 것이 구체적인 것에 의존해서는 안 된다는 뜻이다.
•
그렇다면 고수준 모듈에서 사용하는 저수준 모듈을 추상화해야할 것이다. 이때 인터페이스를 사용할 수 있다.
◦
자동차라는 고수준 모듈에서 겨울철 타이어라는 저수준 모듈을 의존하는 상황에서 이런 의존성을 역전시키고 싶다.
◦
타이어라는 추상 타입을 인터페이스로 만들어서 자동차는 타이어를 의존하게 하는 것이다.
◦
겨울철 타이어, 여름철 타이어 등은 타이어를 의존하게 되면서 의존성이 역전된다.