| 상속 (재사용 + 확장)
- 부모 - 자손의 상속 관점 보다는, 재사용과 확장으로 접근하는 것이 좋다
- 상속은, 상위 클래스의 특성을 하위 클래스에서 재사용하고, 거기에 덧붙여 확장할 수 있는 것을 말한다.
- 관계 : 상위 - 하위 / 슈퍼 - 서브
* 상위로 갈수록 추상화, 일반화되며
* 하위로 갈수록 구체화, 특수화된다.
- 상속을 표현하는 문장
구분 | - | 설명 |
포함 | has a | 클래스 내에서 인스턴스를 형성하여 사용 |
상속 | is a kind of | 클래스를 extends (확장하다) |
구현 | is able to | 인터페이스를 implements (구현하다) |
- 오버라이딩 : 상속 관계에 있는 상위 클래스로부터 물려 받은 메소드를 재정의한 것
| 상속의 장단점
장점 | - 모듈화*를 통한 재사용 - 유지보수가 쉽고, 개발 시간이 단축된다. - 코드가 통일성이 있고 간결해진다. |
단점 | - 상속 시 기능을 추가하고 변경할 때 버그가 발생하면 전반적인 검토가 불가피하다. - 불필요한 기능까지 상속해야하는 경우가 있다. (특히 인터페이스의 경우) - 상위 클래스의 구현이 하위 클래스에게 노출될 경우 캡슐화 원칙을 위반할 수 있다. ==> 강한 결합도 발생 |
* 모듈화 : 소프트웨어를 각 기능별로 나눈 단위. 여기에서는 객체화로 보아도 무방하다.
| 결합도와 응집도
- 상속에 대한 이야기를 할 때 자주 나오는 이야기가 결합도와 응집도인 것 같다.
- 결합도와 응집도란 그럼 뭘까?
결합도 | 응집도 |
서로 다른 모듈 간에 상호 의존하는 정도 또는 연관된 관계 | 한 모듈 내부의 처리 요소들이 서로 연관되어 있는 정도 |
A - B 간에 결합도가 높을 경우, - A를 변경하면, B도 변경해야 한다. - A를 변경한 후, B를 다른 코드에서 재사용하기 어렵다 |
A안에 a1, a2, a3 메소드들이 있다고 할 때, 각 메소드들이 A안에서 책임이 잘 뭉쳐져 있어 A가 독립적인 모듈로써 기능할 때 응집도가 높다고 한다. |
- 상속에서는 여러 개의 하위 모듈이 하나의 상위 객체로부터 공통의 메소드를 사용하거나, 참조하기 때문에 지나치게 결합도가 높은 경우에는 차후에 수정을 할 때에 어려움이 발생할 수 있다.
- 또한 상위 객체에서 접근제어자와 겟터(getter)/셋터(setter) 등으로 정보에 대한 접근을 제한하지 않았다면, 캡슐화(정보은닉)의 원칙도 깨어질 우려가 있다. 잘못하면 상속 후 하위 객체에서 상위 객체의 데이터에 접근을 할 수 있기 때문이다.
- 따라서, 상속 시 사전에 결합도와 응집도를 충분히 고려하는 게 필요하다.
| 상속시 메모리구조
- new 객체명() 를 통해 인스턴스를 생성할 때, 상속을 받은 경우, '나' 뿐만 아니라 '상위' 인스턴스도 함께 힙에 생성된다.
Static : 클래스 정보 | |
Stack : main() -> 하위 생성자 호출 |
Heap : 하위 인스턴스, 상위 인스턴스 |
| UML 표현 (출처 : https://gmlwjd9405.github.io)
(1) Logical
(2) Physical
| 상속을 표현한 코드
동물은 이름(name)과 나이(age)가 있으며, 자신을 소개(introduce)할 수 있다.
'포유류'는 동물이다. (상속)
- Mammal is a kind of Animal.
포유류는 다른 동물처럼 이름과 나이가 있고, 자신을 소개할 수 있다.
포유류의 포유류의 평균 최대 수명(MAX_AGE)을 갖고 있다.
포유류는 자신을 소개할 때, 포유류의 평균 최대 수명을 함께 소개한다.
package inheritance;
// 동물
public class Animal {
String name;
int age;
Animal () {}
Animal (String name, int age) {
this.name = name;
this.age = age;
}
void introduce(){
System.out.println("Hi, my name is " + name + ", and i am " + age + "years old.");
}
}
// 포유류
class Mammal extends Animal{
final int MAX_AGE = 268;
void introduce(){
System.out.println("Hi, my name is " + name + ", and i am " + age + "years old.");
System.out.println("I can only live MAX : " + MAX_AGE);
}
}
// 파충류
class Reptile extends Animal{
final int MAX_AGE = 20;
void introduce(){
System.out.println("Hi, my name is " + name + ", and i am " + age + "years old.");
System.out.println("I can only live MAX : " + MAX_AGE);
}
}
| 또다른 예시 코드
package inheritance;
class Vehicle {
String name;
double maxSpeed;
int maxCapacity;
public Vehicle() {}
public Vehicle(double maxSpeed, int maxCapacity) {
super();
this.maxSpeed = maxSpeed;
this.maxCapacity = maxCapacity;
}
public void info() {
System.out.println("== vehicle info ==");
System.out.println("name : " + name);
System.out.println("maxSpeed : " + maxSpeed);
System.out.println("maxCapacity : " + maxCapacity);
}
}
class Car extends Vehicle{
final String name = "car";
int gasDisplacement; // 배기량
public Car() {}
public Car(int gasDisplacement) {
super(430,100);
this.gasDisplacement = gasDisplacement;
}
public void info() {
System.out.println("== Car info ==");
System.out.println("name : " + name);
System.out.println("maxSpeed : " + maxSpeed);
System.out.println("maxCapacity : " + maxCapacity);
System.out.println("gasDisplacement : " + gasDisplacement);
}
}
class Train extends Vehicle{
final String name = "train";
final static String[] ALL_LINES = {"경부선", "호남선", "전라선",
"중앙선", "경의선", "경의선"}; // 나머지 생략
String line; // 노선
public Train() {}
public Train(String line) {
super(330, 1000);
this.line = line;
}
public void info() {
System.out.println("== Train info ==");
System.out.println("name : " + name);
System.out.println("maxSpeed : " + maxSpeed);
System.out.println("maxCapacity : " + maxCapacity);
System.out.println("line : " + line);
}
}
class Airplane extends Vehicle{
final String name = "airplane";
String departure;
String arrival;
public Airplane() {}
public Airplane(String departure, String arrival) {
super(1000, 200);
this.departure = departure;
this.arrival = arrival;
}
public void info() {
System.out.println("== vehicle info ==");
System.out.println("name : " + name);
System.out.println("maxSpeed : " + maxSpeed);
System.out.println("maxCapacity : " + maxCapacity);
System.out.println("departure : " + departure);
System.out.println("arrival : " + arrival);
}
}
-- 테스트 코드
package inheritance;
public class Test {
public static void main(String[] args) {
Car car = new Car(1000);
car.info();
System.out.println();
Train train = new Train(Train.ALL_LINES[1]);
train.info();
System.out.println();
Airplane air = new Airplane("Seoul", "Reykjavik");
air.info();
System.out.println();
}
}
== Car info ==
name : car
maxSpeed : 430.0
maxCapacity : 100
gasDisplacement : 1000
== Train info ==
name : train
maxSpeed : 330.0
maxCapacity : 1000
line : 호남선
== vehicle info ==
name : airplane
maxSpeed : 1000.0
maxCapacity : 200
departure : Seoul
arrival : Reykjavik
[참조]
스프링 입문을 위한 자바 객체 지향의 원리와 이해
https://madplay.github.io/post/coupling-and-cohesion-in-software-engineering
https://gmlwjd9405.github.io/2018/07/04/class-diagram.html
'Language > Java' 카테고리의 다른 글
객체지향 언어의 특징 4_캡슐화 (정보 은닉) (0) | 2022.07.22 |
---|---|
객체지향 언어의 특징 3_다형성 (사용 편의성) (0) | 2022.07.22 |
객체지향 언어의 특징 1_추상화 (모델링) (0) | 2022.07.20 |
객체지향 프로그래밍이란? (0) | 2022.07.18 |
자바 설치부터 제어문까지 기본 핵심 복습 (0) | 2022.07.05 |