본문 바로가기
책 내용 정리/[책] 개발자가 반드시 정복해야 할 객체지향과 디자인 패턴

[4] 코드 재사용은 상속보다는 조립

by 문자메일 2023. 3. 1.

https://link.coupang.com/a/QoNwV

 

개발자가 반드시 정복해야 할 객체 지향과 디자인 패턴

COUPANG

www.coupang.com

 

본문의 내용은 위 책에서 정리한 내용 일부이며, 자세히 알고 싶은 분들은 위 책을 구매해서 보시는 것을 추천드립니다.

씹고 뜯고 맛보고 즐겨도 내용이 지루하지 않고, 정말 돈이 아깝지 않은 책!

 

 

상속

상속을 사용하면 쉽게 다른 클래스의 기능을 재사용하면서 추가 기능을 확장할 수 있기 때문에, 상속은 기능을 재사용하는 매력적인 방법이다.

하지만 상속은 변경의 유연함이라는 부분에서 치명적인 단점이 있다.

 

상속을 통한 재사용의 단점

1. 상위 클래스 변경이 어려움

상위 계층의 클래스인 경우, 해당 클래스를 상속받은 하위 클래스가 많으면, 그 하위 클래스들이 상위 클래스를 의존하기 때문에 상위 클래스의 내용을 변경하기 어려워지는 문제가 발생한다.

 

2. 클래스의 불필요한 증가

상속을 통해 기능 재사용을 목적으로 기능을 확장 할 경우, 유사한 기능을 확장하는 과정에서 클래스의 개수가 불필요하게 증가할 수 있다.

 

3. 상속을 오용할 수 있다.

 

조립을 이용한 재사용

객체 조립(composition)은 여러 객체를 묶어서 더 복잡한 기능을 제공하는 객체를 만들어내는 것이다.

이전 예시에서 '파일 읽기', '암호화', '파일쓰기', '흐름제어'라는 네 개의 객체를 모아서 '파일 암호화'라는 더 복잡한 기능을 완성하였다.

 

객체 지향 언어에서 객체 조립은 일반적으로 필드에서 다른 객체를 참조하는 방식으로 구현된다.

아래 예시에서 FlowController 클래스는 Encryptor 타입의 객체를 필드에서 참조하는 방식으로 조립하여 사용한다.

package chapter3;

public class FlowController5 {
	
	private Encryptor encryptor = new Encryptor(); // 필드로 조립
	
	public void process() {
		///
		byte[] encryptedData = encrytpor.encrypt(data);
		///
	}

}

 

한 객체가 다른 객체를 조립해서 필드로 갖는다는 것은 다른 객체의 기능을 사용한다는 의미를 내포한다.

 

조립의 장점 1. 조립을 통한 재사용은 상속을 통한 재사용에서 발생했던 문제들을 해소해 준다.( 기능 확장 과정에서 클래스 증식 문제 )

 

압축 기능과 캐시 기능 추가가 요구된다면, 조립 방식에서는 상속과 달리 신규 클래스 생성이 불필요하다.

 

아래 예시 코드와 같이 압축기능과 캐시기능을 제공하는 클래스를 조립해서 사용하면 된다.

 

package chapter3;

public class FlowController5 {
	
	private Encryptor encryptor = new Encryptor(); // 필드로 조립
	private Compressor compressor = new Compressor(); // 필드로 조립
	private CacheEngine cacheEngine = new CacheEngine(); // 필드로 조립
	
	public void process() {
		///
		byte[] encryptedData = encrytpor.encrypt(data);
		///
	}

}

 

조립의 장점 2. 상속 방식과는 다르게 런타임에 조립 대상 객체를 교체할 수 있다. ( 상속을 통해 기능 확장된 클래스는 컴파일 단계에서 필드에 할당되는 것이 고정되어 버리기 때문이다.) 

 

 

조립의 단점 1. 상속 방식의 기능 확장에 비해 런타임 구조가 복잡해진다.

 

조립의 단점 2. 상속방식보다 구현하는 난이도가 더 어렵다.

 

정리

재사용을 위한 목적으로는 상속 방식 보다는, 객체 조립 방식이 장점이 더 크기 때문에 우선 고려해 보자.

 

2.1 위임

위임(delegation)은 내가 할 일을 다른 객체에게 넘긴다는 의미를 담고 있으며, 보통 조립 방식을 이용해서 위임을 구현한다.  (객체지향에서 다른 객체에게 역할을 위임 하기 위하여 조립 하는 것이 필요한 것!, 위임이 목적, 조립은 수단)

 

2.2 상속은 언제 사용해야 할까?

  1. 상속을 사용할 때에는, 재사용이라는 관점이 아닌 기능의 확장이라는 관점에서 상속을 적용해야 한다.
    1. 어떤 클래스 만들 때 클래스의 생성 목적이, 부모 클래스의 메서드 구현 로직을 단순히 재사용 하여 기능을 만드는 목적으로는 상속을 사용하면 안 된다는 것으로 이해가 된다. ( 이렇게 생성된 클래스 경우 부모자식간 IS-A관계가 성립되지 않을 확률이 높을 것으로 생각이 된다. 단순히 부모 클래스 로직 재사용만 했으니 )
    2. 그리하여 상속을 사용할 때는 부모클래스의 코드를 '재사용' 하는 목적이 아닌, 부모클래스의 기능을 물려 받고 그 '기능을 확장'하는 목적으로 자식 클래스에서 상속을 사용해야 하는 것으로 이해가 된다.
  2. 그리고 명확한 IS-A 관계가 성립해야 한다.

 

댓글