[Java 객체 지향 디자인 패턴] 3. SOLID 원칙(SRP, OCP, LSP, DIP, ISP)
3.1 SRP - Single Responsibility Principle : 단일 책임 원칙
객체는 단 하나의 책임만 가져야 한다. 책임이란( = 해야하는것, = 할 수 있는 것, = 해야 하는 것을 잘 할 수 있는 것)
핵심적인 책임만 수행하도록 하는 것이 SRP를 따르는 설계이다.
책임의 변경 : 코드는 변경되기 마련이다.
한 클래스의 역할이 많아지게 되면 서로 얽히고 설켜서 일부를 수정하기 위해서 전부를 뜯어고쳐야하는 경우가 발생할 수 있다. 이를 대비하여 책임을 분리시켜주어야 한다.
※ 회귀(regression) 테스트 : 어떤 변화가 있을 때 해당 변화가 시스템의 기능에 영향을 주는지 평가하는 테스트.
산탄총 수술 - AOP
하나의 책임이 여러 클래스에 분산된 경우. 대표적인 예로 로깅, 보안, 트랜잭션과 같은 횡단 관심(cross-cutting concern)으로 분류할 수 있는 기능이 대표적이다. 변경될 곳을 모두 찾아서 수정해야하는 번거로움이 있다. 이를 해결하는 방법으로 관심지향 프로그래밍(Aspect-Oriented Programming, AOP)기법이 있다. ..(뭔지 잘 모르겠다..)
3.2 OCP - Open-Closed Principle : 개방 폐쇄 원치. interface.
-> interface를 많이 활용한다. 큰 단위에서 자주 변경되는 attribute은 interface로, 자주 변경되지 않는 attribute은 클래스를 따로 만들고 interface를 implements해서 사용한다.
기존 코드를 변경하지 않으면서 기능을 추가할 수 있도록 설계가 되어야 한다는 의미이다. 무엇이 변하는 것인지, 무엇이 변하지 않는 것인지를 구분하는 것이 가장 중요하다. 변해야 하는 것은 쉽게 변할 수 있게 하고, 변하지 않아야 할 것은 변하는 것에 영향을 받지 않게 해야 한다.
OCP를 보는 다른 관점은 클래스를 변경하지 않고도 대상 클래스의 환경을 변경할 수 있는 설계가 되어야 한다는 것이다.
*단위테스트 : 빠른테스트가 필요. 작은 기능단위로 테스트.(기억 나는건 JUnit)
*더미 객체 : 테스트하 때 객체만 필요하고 해당 객체의 기능까지는 필요하지 않은 경우에 사용. 더미 객체의 메서드가 호출되는 경우, 정상 동작을 실행하지 않고 예외가 발생한다.
*테스트 스텁(test stub) : 더미 객체에 단순한 기능을 추가한다. 객체의 특정 상태를 가정해서 작성하며 특정한 값을 반환하거나 특정한 메세지를 출력하게 한다.
*테스트 스파이 : 주로 테스트 대상 클래스가 의존하는 클래스로 출력을 검증하는데 사용한다.
*가짜 객체 : 실제 의종 클래스의 기능을 대체해야할 경우에 사용하며 실제 의존 클래스의 기능 중 전체나 일부를 훨씬 단순하게 구성한다.
*목 객체(mock Object) : 미리 정의한 기대 값과 실제 호출을 단언문(assertion)으로 비교해 문제가 있으면 테스트 메서드를 대신해 모의 객체가 테스트를 실패하게 된다.
3.3 리스코프 치환 원칙 - 일반화 관계, 일관성.
부모와 자식 클래스 사이의 행위가 일관성이 있어야 한다는 의미이다.
일반화 관계 = is a kind of 관계. LSP를 만족하려면 부모 클래스의 인스턴스를 자식 클래스의 인스턴스로 대체할 수 있어야 한다. 이는 '피터 코드의 상속 규칙' 중 "서브 클래스가 슈퍼 클래스의 책임을 무시하거나 재정의하지 않고 확장만 수행한다."와 같은 의미이다.
LSP를 만족시키는 간단한 방법은 재정의하지 않는 것이다...(Overriding을 한 기억이 아무 많이 새록새록 떠오른다..+ .ing 처음 프로젝트를 시작할 때 데이터 구조를 잘 정의하면 이런 일이 적게 발생할 것 같다. 안나기는 정말 힘들듯..ㅇㅇ)
3.4 의존 역전 원칙 - DIP
의존 관계를 맺을 때의 가이드라인에 해당한다. DIP는 의존 관계를 맺을 때 변화하기 쉬운 것 또는 자주 변화하는 것보다는 변화하기 어려운 것, 거의 변화가 없는 것에 의존하라는 원칙이다.
추상적인 것은 변하기 어렵고, 그렇지 않은 것은 변하기 쉽다고 보면 된다.
DIP를 만족하려면 어떤 클래스가 도움 받을 때 구체적인 클래스보다 인터페이스나 추상 클래스와 의존 관계를 맺도록 설계해야 한다. 이는 변화에 유연한 시스템이 된다.
의존성 주입 : 클래스 외부에서 의존되는 것을 대상 객체의 인스턴스 변수에 주입하는 기술이다. 아래 코드와 같이 대상 객체를 변경하지 않고도 외부에서 대상 객체의 외부 의존 객체를 바꿀 수 있다.
public class Kid{
private Toy toy;
public void setToy(Toy toy){
this.toy = toy;
}
public void play(){
System.out.println(toy.toString);
}
}
Kid 클래스에서 setToy로 아이가 가지고 노는 장난감을 바꿀 수 있다. 이것이 바로 의존성 주입!?
3.5 인터페이스 분리 원칙 - ISP
인터페이스를 클라이언트에 특화되도록 분리시키는 설계 원칙이다. 책에서 나온 예시로는 복합기. 프린터, 팩스, 복사 기능을 모두 수행할 수 있지만 세 기능을 한꺼번에 사용하지는 않으므로 각각의 기능을 분리시키는게 좋다.
SRP(단일 책임 원칙)를 만족하더라도 ISP를 반드시 만족한다고는 할 수 없다. 책에서는 게시판을 예시로 들었다. 글쓰기, 읽기, 수정, 삭제를 위한 메서드가 제공되지만, 클라이언트에 따라서 일부의 기능만 사용할 수 있다. 관리자만 게시판을 삭제할 수 있는 경우! 이 경우 게시판 클래스는 SRP를 만족한다. 하지만, 이 클래스의 모든 메서드가 들어있는 인터페이스가 클라이언트에 상관없이 사용된다면 ISP에 위반된다.
객체지향 설계 원칙 ~ 끘
거의 한 2주 정도 걸렸네요.. 다 읽는데. ㅜ.ㅜ 천천히 읽어서 ㅋㅋ
다음 chapter부터는 디자인 패턴입니다. 화이링~
JAVA 객체지향 디자인 패턴 - 교보문고
UML과 GoF 디자인 패턴 핵심 10가지로 배우는 | 이 책이 제시하는 핵심 내용객체지향 이론과 UML을 통해 GoF 디자인 패턴의 핵심 10가지를 배운다.이 책의 특징과 장점5단계 학습법으로 디자인 패턴을
www.kyobobook.co.kr