개요
오늘은 객체 지향 프로그래밍(OOP)의 핵심 개념인 상속(Inheritance)과 복합(Composition)에 대해 설명해드리겠습니다. 이 두 개념은 코드 재사용과 유지보수성을 높이는 중요한 설계 방식입니다. 예제와 함께 특징을 살펴보며 공부해도록 하겠습니다.
상속
상속은 OOP에서 가장 기본개념중에 하나입니다. 부모 - 자식 클래스로 정의하여 자식클래스에서 부모 클래스의 메소드를 override, 재사용 할 수 있다는 특징이 있습니다.
@AllArgsConstructor
public class Car {
private final String brand;
private final String model;
private final int year;
public void start() {
System.out.println("차량이 시동됩니다.");
}
public void stop() {
System.out.println("차량이 정지합니다.");
}
}
public class ElectricCar extends Car {
private int batteryCapacity;
private int batteryLevel;
public ElectricCar(String brand, String model, int year, int batteryCapacity) {
super(brand, model, year);
this.batteryCapacity = batteryCapacity;
this.batteryLevel = 100;
}
@Override
public void start() {
System.out.println("전기차가 조용히 시동됩니다.");
}
public void charge() {
System.out.println("배터리를 충전합니다.");
this.batteryLevel = 100;
}
}
ElectricCar 클래스는 Car 클래스를 상속받고있습니다. 따라서 Car와 ElectricCar는 부모-자식 관계입니다.
ElectricCar는 Car의 기능을 재사용하거나 새로운 기능을 손쉽게 추가할 수 있고, 때에 따라서 Override 할 수 있습니다. 그리고 Car 에서 변경된 사항은 ElectricCar에도 그대로 반영됩니다.
복합
@AllArgsConstructor
public class Engine {
private final String type;
private final int hp;
public void start() {
System.out.println(type + " 엔진이 가동됩니다.");
}
}
@AllArgsConstructor
public class GasCar {
private final Car car; // 복합관계
private final Engine engine; // 복합관계
public void start() {
car.start();
engine.start();
}
}
Engine 클래스와 GasCar 클래스를 구현했습니다. GasCar는 Car와 Engine을 필드에서 참조하고있습니다.
이처럼 GasCar가 Car를 필드로 가지는 것이 복합관계라고합니다. GasCar를 통해 Car 메소드를 호출하는 방식이죠.
상속의 장단점
장점
- 코드 재사용성
- 부모 클래스의 기능을 그대로 물려받아 사용할 수 있어 코드 중복을 줄일 수 있습니다.
- 공통 기능을 부모 클래스에 구현하면 모든 자식 클래스가 활용할 수 있습니다.
- 간단한 확장성
- 기존 클래스를 수정하지 않고도 새로운 기능을 추가할 수 있습니다.
- 다형성 구현
- 부모 타입으로 자식 객체를 참조할 수 있어 유연한 프로그래밍이 가능합니다.
Car car = new ElectricCar("Tesla", "Model 3", 2024, 75);
단점
- 강한 결합도
- 부모 클래스의 변경이 모든 자식 클래스에 영향을 미칩니다.
- 부모 클래스의 내부 구현을 자식 클래스가 알아야 할 수 있습니다.
- 취약한 기반 클래스 문제
- 부모 클래스의 변경이 예상치 못한 자식 클래스의 동작 변경을 일으킬 수 있습니다.
- 단일 상속 제한
- Java는 다중 상속을 지원하지 않아 한 클래스만 상속할 수 있습니다.
복합의 장단점
장점
- 유연한 설계
- 런타임에 구성요소를 변경할 수 있습니다.
- 다중 복합이 가능합니다.
- 캡슐화 향상
- 내부 구성요소의 구현을 완전히 숨길 수 있습니다.
- 인터페이스를 통한 통신이 가능합니다.
- 느슨한 결합도
- 각 클래스가 독립적으로 동작하여 유지보수가 용이합니다.
// Engine을 쉽게 교체할 수 있음
public void updateEngine(Engine newEngine) {
this.engine = newEngine;
}
단점
- 코드 가독성
- 복잡한 구성의 경우 코드 추적이 어려울 수 있습니다.
- 구현의 복잡성
- 여러 클래스를 조합하여 사용하므로 초기 설계가 더 복잡할 수 있습니다.
// 복합 관계에서는 위임 메서드를 많이 작성해야 할 수 있음
public class GasCar {
private Car car;
private Engine engine;
public void start() { car.start(); }
public void stop() { car.stop(); }
public void accelerate() { engine.accelerate(); }
// ... 더 많은 위임 메서드들
}
결론
상속과 복합에 대한 글을 읽다보면 'IS-A' 일때는 상속, 'HAS-A' 일때는 복합을 사용하라는 글이 많습니다.
'전기차는 차다' -> 상속,
'차는 엔진을 갖고있다' -> 복합,
이렇게 이해하면 조금더 와닿을것 같습니다.
최근의 객체지향 설계에서는 "상속보다는 복합을 사용하라"는 원칙이 널리 받아들여지고 있습니다. 복합이 더 유연하고 안전한 설계를 제공하기 때문입니다. 하지만 각각의 상황에 맞는 적절한 선택이 중요합니다.
마지막으로 위의 예제를 상속과 복합관계를 이용하여 CasCar를 조금 더 깔끔하게 바꿔보면서 글을 마치겠습니다.
@AllArgsConstructor
public class Car {
private final String brand;
private final String model;
private final int year;
private final Engine engine;
public void start() {
System.out.println("차량이 시동됩니다.");
engine.start();
}
public void stop() {
System.out.println("차량이 정지합니다.");
}
}
public class GasCar extends Car {
private final int fuelCapacity;
private double currentFuel;
public GasCar(String brand, String model, int year, Engine engine, int fuelCapacity) {
super(brand, model, year, engine);
this.fuelCapacity = fuelCapacity;
this.currentFuel = fuelCapacity;
}
public void refuel(double amount) {
currentFuel = Math.min(currentFuel + amount, fuelCapacity);
}
}
차는 엔진을 가지고있다 -> private final Engine engine
가솔린차는 차이다 -> GasCar extends Vehicle
'Language > JAVA' 카테고리의 다른 글
[JAVA] StringTokenizer 에 대해서 (0) | 2024.11.14 |
---|---|
[JAVA] Record와 Sealed (0) | 2024.11.13 |
[JAVA] String + 연산을 왜 쓰지말아야할까 (0) | 2024.09.24 |
[JAVA] for문과 향상된 for문은 어떤 차이가 있을까? (0) | 2024.09.24 |
[JAVA] If-else 와 switch 중에 어느게 더 빠를까? (0) | 2024.09.24 |