250x250
Notice
Recent Posts
Recent Comments
관리 메뉴

탁월함은 어떻게 나오는가?

IS-A(Inheritance, 상속) vs HAS-A(Composition, 포함) 관계 정리 본문

[Snow-ball]server/객체지향

IS-A(Inheritance, 상속) vs HAS-A(Composition, 포함) 관계 정리

Snow-ball 2023. 6. 5. 17:35
반응형

객체 지향 프로그래밍(Object-Oriented programming) 언어는 코드 재사용에 대한 이점이 있다.

코드 재사용 방법에는 상속 구현(inheritance, IS-A 관계) 또는 개체 구성(composition, HAS-A 관계) 두가지가 있다.

그러나 상속을 사용할 때는 컴파일러와 Java virtual machin(JVM)이 많은 일을 하지만, composition을 사용할 때는 상속의 기능을 사용할 수 있다.

 

 

 

IS-A Relationship

객체 지향 프로그래밍의 컨셉은 전부 IS-A을 기반으로 한 상속이며, 상속은 Class 상속과 Interface 상속 2가지 타입이 있다. 상속은 "A 타입은 B 타입의 것이다." 라고 하는 것이다. 예를들어 [ 사과는 과일이다. ] or [ 차는 차량이다. ] 과 같다. 그렇기 때문에 상속은 단방향이다. 예를 들자면 사과는 과일에 속하지만, 과일은 사과에 속하지 않기 때문이다.

 

이 부분에서 중요한 점은 우리는 아주 쉽게 IS-A relationship을 구별할 수 있다. 어디에서나 클래스 안에 extends 또는 implements 가 선언되어있고, 가지고 있다면 IS-A relationship이다.

 

 

 

HAS-A Relationship

Composition(HAS-A)는 개체 오브젝트를 인스턴스 변수로 참조하는 것을 의미한다.

예를들어 [ 마루티는 엔진을 가진다. ] or [ 집은 욕실을 가진다. ] 와 같다.

 

Car class 로 컨셉을 이해할 수 있다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Car {
  private color: string;
  private maxSpeed: number;
 
  public carInfo(): void {
    console.log(`Car Color= ${this.color} Max Speed= ${this.maxSpeed}`);
  }
 
  public setColor(color: string): void {
    this.color = color;
  }
 
  public setMaxSpeed(maxSpeed: number): void {
    this.maxSpeed = maxSpeed;
  }
}
cs

Car class 를 살펴보면, Car clas안에는 2개의 인스턴스 변수와 3개의 메소드가 존재한다.

마루티는 Car와 IS-A relationship 을 의미하는 Car class 로 확장하는 특정 유형의 자동차 타입니다.

 

1
2
3
4
5
6
7
8
class Maruti extends Car {
  // 마루티 클래스는 extends Car 를 하면 Car class 로부터 모든 메소드를 상속받을 수 있다. (final 및 static 제외)
  // 마루티는 또한 모든 특정 기능을 정의할 수 있다.
  public MarutiStartDemo(): void {
    const MarutiEngine = new Engine();
    MarutiEngine.start();
  }
}
cs

마루티 클래스는 composition을 통해 엔진 클래스의 start() 메소드를 사용할 수 있다.

마루티 클래스와 엔진 클래스는 HAS-A relationship 이다.

 

1
2
3
4
5
6
7
8
9
class Engine {
  public start(): void {
    console.log("Engine Started:");
  }
 
  public stop(): void {
    console.log("Engine Stopped:");
  }
}
cs

 

RelationsDemo class 는 Maruti class 개체를 만들고 초기화시킨다.

Maruti class 안에 setColor(), setMaxSpeed() 그리고 carInfo() 메소드를 가지고 있지 않지만 Maruti class는 Car class 와 IS-A relationship관계이기 때문에 사용할 수 있다.

1
2
3
4
5
6
7
8
9
class RelationsDemo {
  public Demo(): void {
    const myMaruti = new Maruti();
    myMaruti.setColor("RED");
    myMaruti.setMaxSpeed(180);
    myMaruti.carInfo();
    myMaruti.MarutiStartDemo();
  }
}
cs

 

 

아래는 출력 결과이다.

 

 

 


 

 

 

Composition(구성) 과 Inheritance(상속) 비교

- 클래스 composition 구성을 변경하는 것이 Inheritance 보다 쉽다. 그리고 슈퍼클래스의 변경은 하위 클래스에 대한 상속 계층에 영향을 준다.

 

- 상위 클래스에서 상속된 메서드와 메소드 이름은 같지만 반환 유형은 다른 메서드를 하위 클래스에 추가할 수 없다. Composition을 사용하면 백엔드 클래스에 영향없이 프론트엔드 클래스의 인터페이스를 변경할 수 있다.

 

- Composition은 동적 바인딩(run0time binding)이고 Inheritance는 정적 바인딩(compile time binding) 이다.

 

- 상속에는 다형성이 존재하기 때문에 새로운 프론트엔드 클래스(composition)을 추가하는 것보다 새로운 하위 클래스(inheritance)를 추가하는 것이 더 쉽다. 슈퍼클래스 인터페이스만 의존하는 코드가 있다면 해당 코드는 변경 없이 새로운 서브클래스와 함께 작동할 수 있다. 이것은 인터페이스와 함께 구성을 사용하지 않는 한 Composition에는 해당되지 않는다. Composition과 Interface를 함께 사용하면 매우 강력한 설계 도구가 된다.

 

- composition 과 inheritance 둘다 모든 클래스의 구현(인터페이스가 아니다)을 변경하는 것은 쉽다. 구현 변경의 파급 효과는 동일한 클래스 내에 남아 있다.

1. 코드 재사용을 위해서 inheritance를 사용하지 말아라!!

    IS-A relationship 관계가 필요없으면서 코드만을 재사용하기 원한다면 composition 을 사용하라.

2. 다형성을 얻기 위해 상속을 사용하지 말아라!!

    정말 원하는 것이 다형성이지만, 자연스러운 IS-A relationship이 없다면 interface를 사용하여 composition을 하라.

 

 

 

 

참조

* Inheritance (IS-A) vs, Composition(HAS-A) Relationship, w3resouce

 

 

반응형
Comments