Wanna be Brilliant Full-Stack Developer

Java 객체지향프로그래밍의 이해 상속과 콤포지션 본문

Some Memos/Java

Java 객체지향프로그래밍의 이해 상속과 콤포지션

Flashpacker 2023. 2. 10. 18:50


자바에는 상속이라는것이 있다.
엄밀히 말하면 Extend라고 해서 확장하다라고 정의하는것이 낫다. 

 

내가 만약 자동차 하나를 만들고 싶다. 
자동차를 만들기 위해서 필요한 부품들이 있다. 첫번쨰로는 바퀴, 엔진, 차 외관(프레임) , 기어와 같은것들이 필요하다.

내가 만약 자동차를 만들건데 자동차를 만들려고 했더니 이미 잘 만들어진 엔진이라는 라이브러리가 존재한다.

그래서 이 라이브러리를 사용하면 되는데?

어떻게 사용해야하는가! 내가 자동차를 만들거니까 이 엔진을 가져와서 사용하면 된다. 

그러면 이 자동차를 만들떄 이 엔진을 가져와서 사용하는거니까 라이브러리를 import를 해야한다.

이걸 상속이라고 하지는 않는다.

 

어떤 필요한것을 가져오는것을 상속이라고 하지는 않는다.


그러면 상속이라는것은 무엇인가?  

가장 중요한것이 상속은 두가지 일을 해준다.
첫번째는 추상화를 해준다.

두번째는 어떤 상태나 행위를 물려받을 수 있다. 

 

이 물려 받는 개념에서 상속이라고 하는데?

우리가 라이브러리를 땡겨서 쓸떄도 필요한걸 가져와서 쓸때도
이 엔진이 들고 있는 상태나 행위를 임포트 해서 가져와서 쓸수 있는것처럼 똑같다.

이것은 상태와 행위를 물려 받는 개념이라는것 보다는 가져와서 쓰는것이다. 

 

근데 상속은 상태와 행위를 물려 받는다의 개념이다! 그리고 추상화가 된다는 개념이 조금 다르다. 

 

예를 들어 엔진이 있고 자동차가 있다. 햄버거가 있고 치즈 햄버거가 있다.
이때 내가 자동차를 만들떄 엔진을 상속할 수 는 없다.
왜? 애는 개념이 애를 가져와서 사용해야 한다. 애를 라이브러리 느낌으로 가져와서 사용

 

자동차를 엔진이라고 부를 수 없기 떄문이다.
너 자동차야 엔진이니? 자동차는 나는 엔진이 아닌데? 
라고 그 두가지는 타입의 일치가 될 수 없다.
이것은 굉장히 중요한 개념이다. 

 

이것은 햄버거와 치즈 햄버거가 있는데 만약에 내가 치즈 햄버거를 만들고 싶으면 그러면 기존에 잘 만들어진 햄버거를 가져와서 사용하는것이 아니라 화살표가 반대가 되어서 상속할 수 있다.
이것은 왜 가능한가? 타입 일치가 가능하다.
타입일치가 가능하다는것은 애가 추상화된 존재라는것이다. 
누구에게 추상화된 존재라는것인가? 치즈 햄버거에게는 햄버거는 추상적인 존재이다.
왜그러는가? 치킨 햄버거가 만약에 있다고 생각해보자.
치킨 햄버거는 이 햄버거를 상속할 수 있다.
햄버거는 이미 만들어져있는데
치킨 햄버거는 햄버거에다가 치킨만 넣으면 되니까
그대로 물려받으니까 상속으로 접근할 수 있다.
치킨 햄버거에게는 햄버거라고 물어보면 햄버거라고 말할 수 있으니 타입 일치가 된다. 
햄버거를 봤을떄 치킨 햄버거에게 추상적인 개념이다. 

햄버거는 치즈 햄버거와 치킨 햄버거에게 추상적인 존재이다. 
치즈 햄버거와 치킨 햄버거는 햄버거라는 추상적인 존재를 부를 수 있다.

하지만 엔진과 자동차는 타입 일치가 안되기 떄문에 안된다. 

 

오토바이를 만들고 싶은데 엔진을 상속할 수 있을까?오토바이에게 엔진이니? 이렇게 물어보는것이 말이 안되니 이것도 가져와서 사용한다.

엔진이 추상화된 존재인가? 자동차와 오토바이를 하나로 부를 수 있는것인가?
아니다 추상화된 존재가 아니다.  꼭 기억해야한다.

상속은 추상화가 꼭 가능해야한다!!( 상태, 행위 물려 받아야한다) 즉 타입의 일치가 가능해야한다!


그러면 간단하게 코드를 짜보자 

package ch05;

class Engine {
	int power = 2000;
}

class Car {
	
}

public class OOPEx02 {

	public static void main(String[] args) {

	}

}

이 엔진을 Car가 임포트할 필요가 없다. 같은 패키지 안에 있으니까! 

상속을 하는게 아니라 생성자를 하나 만든다.

그런데 오류가 난다.

여기서 c1으로 Car을 찾아가서 e를 찾아서 e는 무엇인가?
Engine이다. Engine이 들고 있는 Static이 아닌 모든 상태를 가지고 있을것이다. 

 

이렇게 잘만들어진것을 내가 가져와서 사용할때 이렇게 사용하는 방식을 콤포지션(결합) 한다고 한다.

왜 상속 할 수 없느냐? 자동차는 엔진이 아니기 떄문이다. 


그러면 이번에 상속을 해보려고 하는데? 

이번에는 콤포지션 결합할 필요가 없다. 왜냐하면 치즈 햄버거는 햄버거라 부를 수 있기 떄문이다. 

 

Extends라는것은 Hamburger가 들고 있는 햄버거 내부에 있는게 치즈 햄버거에 들어왔다고 넣지 않았어도 사용해도 된다고 보면된다. 

여기서 중요한것은 상속은 상태와 행위를 물려받을 수 있지만 꼭 타입이 일치될 수 있어야한다.

package ch05;

class Engine {
	int power = 2000;
}

class Car { // 자동차는 엔진이 아니기 떄문에 상속할 수 없다.
	 
	//컴포지션!! 결합한다고 한다.
	Engine e; 
	
	public Car(Engine e) {
		this.e = e;
	}
}

class Hamburger {
	String name = "기본햄버거";
}

class CheesseHamburger extends Hamburger{ // 치즈 햄버거 = 햄버거이다.
	
}


public class OOPEx02 {

	public static void main(String[] args) {
		Engine e1 = new Engine();
		Car c1 = new Car(e1);
		System.out.println("자동차의 엔진 마력 : " + c1.e.power);
		
		CheesseHamburger ch1 = new CheesseHamburger();
		System.out.println(ch1.name);
	}

}

 

여기 보면 치즈 햄버거는 name이라는 상태를 가지고 있지 않지만 이재 물려 받았기 떄문에 사용이 가능하다.

여러가지를 추가해서 해보려고한다!

결과가 잘나온다! 치즈 햄버거의 이름은 기본햄버거를 하기 좀그래서 

이렇게 햄버거와 치즈 햄버거에 둘다 name이라는 변수를 두었을떄 어떤 결과가 나올까? 

이름이 겹치면 자기것을 사용한다! 

겹치지 않는것만 물려 받는다!

겹치지 않는 상태(필드) 만 불려 받는다!
겹치면 물려 받을 필요가 없다 내가 들고 있으니까? 

근데 이렇게 할필요 없이 이렇게 할 수도 있다. 

치킨 햄버거는 햄버거와 타입이 일치가 되니 상속을 해도 되지만 

생성자를 만들고 결합을 해보자 콤포지션을 했다. 

꼭 상속하지않아도 된다. 이렇게 사용해도 상관없다! 

결합을 해도 되고 상속을 해도 사용해도 된다.

지금 배우지 않은것은 추상화에 대해서 배우지 않았다. 

어떻게 하면 추상화를 잘하는것인지 다음에 배우려고 한다! 

 

컴포지션을 해도되고 상속해도 된다면 도대체 왜 상속을 사용하는것인가도 궁금하다.

package ch05;

class Engine {
	int power = 2000;
}

class Car { // 자동차는 엔진이 아니기 떄문에 상속할 수 없다.
	 
	//컴포지션!! 결합한다고 한다.
	Engine e; 
	
	public Car(Engine e) {
		this.e = e;
	}
}

class Hamburger {
	String name = "기본햄버거";
	String 재료1 = "양상추";
	String 재료2 = "패티";
}

class CheesseHamburger extends Hamburger{ // 치즈 햄버거 = 햄버거이다.
	String name = "치즈햄버거";
}

class ChickenHamburger {
	String name = "치킨햄버거";
	Hamburger h;
	
	public ChickenHamburger(Hamburger h) {
		this.h = h;
	}
}

public class OOPEx02 {

	public static void main(String[] args) {
		Engine e1 = new Engine();
		Car c1 = new Car(e1);
		System.out.println("자동차의 엔진 마력 : " + c1.e.power);
		
		CheesseHamburger ch1 = new CheesseHamburger();
		System.out.println( "햄버거의 이름은 : "+ ch1.name);
		System.out.println("재료 : " +ch1.재료1);
		System.out.println("재료 : " +ch1.재료2);
		
		Hamburger h1 = new Hamburger();
		ChickenHamburger ckh1 = new ChickenHamburger(h1);
		System.out.println(ckh1.name);
		System.out.println(ckh1.h.재료1);
		System.out.println(ckh1.h.재료2);
	}

}

꼭 상속하지 않아도 다른 클래스를 만든것을 재사용하는것이 가능하다.

꼭 상속만으로 재사용할 필요가 없다.

언제 상속을 해야하는지 배워보자!!