[객체 지향 프로그래밍 입문] 상속보단 조립

kshired·2021년 8월 20일
0

상속과 재사용

  • 상속은 상위 클래스의 기능을 재사용, 확장하는 방법으로 사용이 가능하지만..

상속을 통한 기능 재사용시 발생할 수 있는 단점

  • 상위 클래스 변경 어려움

상위 클래스가 조금만 잘못 변경되어도 다른 하위 클래스가 잘못 동작하게 될 수 있음

  • 클래스 증가

위와 같이 상속을 사용하면서 하위 클래스가 증가하게 되어, 복잡도가 증가하게 됨

  • 상속을 오용하게 될 수 있음
    public class Container extends ArrayList<Luggage> {
    	private int maxSize;
    	private int currentSize;

    	public Container(int maxSize){
    		this.maxSize = maxSize;
    	}

    	public void put(Luggate lug) throws NotEnoughSpaceException {
    		if(!canContain(lug)) throw new NotEnoughSpaceException();
    		super.add(lug);
    		currentSize += lug.size();
    	}
    	
    	public void extract(Luggage lug){
    		super.remove(lug);
    		this.currentSize -= lug.size();
    	}
    	
    	public boolean canContain(Luggage lug){
    		return maxSize >= currentSize + lug.size();
    	}
    }

Container 클래스는 ArrayList를 상속받아서 구현하고 있다.

Container 클래스는 putextract를 상위 클래스인 ArrayListaddremove를 이용하여 구현하고 있다.

올바른 사용법은 위 그림에 나타나 있는데, IDE는 상속받은 상위 클래스의 메소드도 제안으로 보여주기 때문에 원치 않는 동작을 개발자가 오용하여 사용하게 될 수 있다.

이것은 잘못 사용한 개발자의 문제일까?

Nope. 오용할 가능성이 높은 클래스를 만든 사람의 문제

상속의 단점 해결 방법 → 조립

  • 조립 ( Composition )
    • 여러 객체를 묶어서 더 복잡한 기능을 제공
    • 보통 필드로 다른 객체를 참조하는 방식으로 조립
    • 객체를 필요 시점에서 생성하거나 구하게 됨
public class FlowController {
	private Encryptor encryptor = new Encryptor(); // 필드로 객체를 생성하여 조립
	
	public void process() {
		//...
		byte[] encrytepdData = encryptor.encrypt(data);
		//...
	}
}

조립을 통한 기능 재사용

Storage 클래스를 상속하지 않고, 필드로 객체를 사용.

상속의 오용 문제 해결

public class Container {
	private int maxSize;
	private int currentSize;
	private List<Luggage> luggages = new ArrayList<>(); // 필드로 사용

	public Container(int maxSize){
		this.maxSize = maxSize;
	}

	public void put(Luggate lug) throws NotEnoughSpaceException {
		if(!canContain(lug)) throw new NotEnoughSpaceException();
		luggages.add(lug);
		currentSize += lug.size();
	}
	
	public void extract(Luggage lug){
		luggages.remove(lug);
		this.currentSize -= lug.size();
	}
	
	public boolean canContain(Luggage lug){
		return maxSize >= currentSize + lug.size();
	}
}

위와 같이 ArrayList를 상속받지 않고, 필드를 이용해 구현하면 오용의 가능성이 사라지게 된다.

상속보다는 조립 ( Composition over Inheritance )

  • 상속하기에 앞서 조립으로 풀 수 없는지 검토
  • 진짜 하위 타입인 경우에만 상속을 사용
profile
글 쓰는 개발자

0개의 댓글