[김영한_자바기본][12. 다형성과 설계] (보충) 예제를 통한 이해 (p.13-
▶ 다형성 사용 전, 후 : 예제를 통한 이해
https://zoooom-in.tistory.com/63
[김영한_자바기본][12. 다형성과 설계] 다형성 사용 전, 후 예제를 통한 이해 (p.1-20)
OCP(Open-Closed principle) 원칙 = 전략 패턴 - Open for extension : interface(전략 정의)를 통한 구현 확장이 가능해야 한다. - closed for modification : 클라이언트 부분의 코드가 수정이 불가능해야한다. 단, 메인
zoooom-in.tistory.com
[p.13 / Driver] `drive()` 메서드는 `k3Car` 변수가 가리키는 실제 객체(원본 `k3Car`의 참조값)의 메서드를 호출
public class Driver {
K3Car k3Car; //null -> 불러온거긴 함 : 내부 객첸 없음
public void setK3Car(K3Car k3Car) {
this.k3Car = k3Car; //내부 객체를 전달받고
}
public void drive() {
System.out.println("차량을 운전합니다.");
k3Car.startEngine(); //Driver 안의 k3Car를 작동한다는 의미지만
k3Car.pressAccelerate(); //k3Car에는 원본 k3Car의 참조값이 존재함
k3Car.offEngine(); // 즉 실제로는 참조값의 기능에 접근하는걸로 봐야함
}
}
- 각각의 자동차 객체를 필드로 직접 참조
- `Driver` 클래스의 `k3Car` 필드는 `K3Car` 객체에 대한 참조를 저장한다.
> `setK3Car()` 메서드는 외부에서 `K3Car` 객체를 전달받아 `k3Car` 필드에 할당한다.
- `k3Car.startEngine()` 호출은 원본 `k3Car` 객체의 `startEngine()` 메서드를 호출하는 것이다.
*Drive 참조값 이해 도식화
[p.13 / K3Car]
public class K3Car {
public void startEngine() {
System.out.println("엔진을 켭니다.");
}
public void offEngine() {
System.out.println("엔진을 끕니다.");
}
public void pressAccelerate() {
System.out.println("악셀을 밟으세요");
}
}
[p.13 / CarMain0] 다형성, 역할 / 구현 분리하지 않은 상태
public static void main(String[] args) {
Driver driver = new Driver();
K3Car k3Car = new K3Car();
driver.setK3Car(k3Car);
driver.drive();
}
[p.18 / Driver] 객체 직접 참조가 아닌, 다형성을 이용하여 인터페이스를 통해 자동차를 참조
public class Driver {
Car car;
public void setCar(Car car) {
System.out.println("자동차를 설정합니다.");
this.car = car;
}
public void drive() {
System.out.println("자동차를 운전합니다.");
car.startEngine(); //car자체에 기능은 있다. -> 구현은 그 하위 속성에서
car.pressAccelerate();
car.offEngine();
}
}
- 첫번째 코드는 각각의 자동차 객체를 필드로 직접 참조하고 있지만,
두 번째 코드에서는 다형성을 이용하여 인터페이스를 통해 자동차를 참조하고 있다.
첫번째 코드 | 두번째 코드(다형성) | |
장점 | 명시적으로 어떤 종류의 자동차를 다루는지 알 수 있음 - `k3Car`와 `model3Car`를 직접 참조 |
유연성과 확장성이 높음 - 객체를 손쉽게 교체 가능 하며, 추가도 자유롭다. |
단점 | 각각의 자동차 객체에 특화된 동작을 수행 - 'k3Car`에만 있는 특정한 메서드를 호출 가능 |
코드 의존성 감소 - 인터페이스에 의존 |
- 타입의 자동차 객체만 다루고, 그 기능이 변경될 가능성이 적다면 첫 번째 방법이 적합
- 다양한 종류의 자동차를 다루고자 하거나, 앞으로 자동차의 종류가 늘어날 가능성이 있다면 두 번째 방법이 더 적절
[p.18 / Car] 인터페이스 생성
public interface Car {
void startEngine();
void offEngine();
void pressAccelerate();
}
[p.18 / K3Car] Car : 인터페이스 값 전달 받음
public class K3Car implements Car{
@Override
public void startEngine() {
System.out.println("K3Car.startEngine");
}
@Override
public void offEngine() {
System.out.println("K3Car.offEngine");
}
@Override
public void pressAccelerate() {
System.out.println("K3Car.pressAccelerate");
}
}
[p.19 / CarMain1]
public static void main(String[] args) {
Driver driver = new Driver();
K3Car k3Car = new K3Car();
driver.setCar(k3Car);
driver.drive();
Model3Car model3Car = new Model3Car();
driver.setCar(model3Car);
driver.drive();
}