좋은 설계자들은 그들의 코드의 대부분을 구체 클래스가 아닌 interface로 작성한다.
구체 클래스 기반의 프로그래밍을 할 경우 어떠한 문제가 생기는지에 대해서 세 가지 이유를 가지고 설명하고자 한다.
1. 유연성을 잃기 쉽다.
구현 상속을 피해야 하는 첫 번째 이유는 구체 클래스의 이름을 명시적으로 사용하게 된다면 특정한 구현에 고정되어서 변경에 용이하지 않다는 것이다.
아래의 코드는 명시적으로 LinkedList를 사용하였다.
f()
{ LinkedList list = new LinkedList();
//...
g( list );
}
g( LinkedList list )
{
list.add( ... );
g2( list )
}
하지만 사용자의 요청으로 더 이상 LinkedList를 사용할 수 없게 되었고 HashSet 컬렉션으로 모두 바꾸어야 하는 상황이 일어났다.
해당 코드 변경 시 우리는 f 함수 내부의 LinkedList와 g 함수 아규먼트도 바꾸어야 한다.
만약 코드가 아래와 같이 작성되었다면 어떨까?
f()
{ Collection list = new LinkedList();
//...
g( list );
}
g( Collection list )
{
list.add( ... );
g2( list )
}
Collections 인터페이스로 컬렉션을 받았기 때문에 단순히 HashSet이라는 컬렉션만 선언해주면 끝이 난다.
2. 결합도
위 보다 더 중요한 문제는 사실 결합도의 문제이다. 결합도는 하나의 문제를 수정하였을 때 또 다른 곳에 영향을 주는 정도라고 정의하겠다.
부가적인 설명을 위해 전역 변수를 예로 들면
특정 전역 변수가 선언되어 있고 모든 함수들은 해당 전역 변수를 참조하고 있다고 가정하자. 사용자의 요구로 부득이하게 전역 변수의 타입을 변경하게 되었다고 하면 해당 전역 변수를 참조하고 있는 모든 함수들을 수정해야 한다.
위와 같은 위험을 방지하고자 설계자들은 결합도를 최소화해야 한다. 최소화한다는 말에 주목하자!
프로그래밍 특성상 결합도는 없앨 수가 없다. 왜냐면 한 클래스에서 다른 클래스의 메서드 호출은 느슨한 결합의 형태이기 때문에 완전히 제거할 수는 없다.
그럼에도 불구하고 우리는 결합도를 최소화해야 한다.
객체의 구현은 그것을 사용하는 객체에서 완전히 숨김으로서 우리는 결합도를 최소화할 수 있다.
- 항상 private 키워드를 사용하자. (protected도 웬만하면 사용하지 말자)
- getter, settter도 사용하지 말자. (pulbic으로 선언한 것과 다를 것이 없기 때문)
3. 깨지기 쉬운 기본 클래스 문제
ing...
References
https://www.javaworld.com/article/2073649/why-extends-is-evil.html
'Java > 객체지향' 카테고리의 다른 글
오브젝트를 읽고 (0) | 2020.05.18 |
---|---|
(OOP) 객체지향에 대해서(3) - 추상화 (0) | 2020.02.21 |
(OOP) 리스코프 치환 원칙 (0) | 2020.02.20 |
(OOP) 객체지향에 대해서(2) - 은유 (0) | 2020.02.20 |
(OOP) 객체지향에 대해서(1) - 객체, 행동, 상태 (0) | 2020.02.19 |