카테고리 없음

[김영한_자바기본][12. 다형성과 설계] 다형성 사용 전, 후 예제를 통한 이해 (p.1-20)

줌인. 2024. 2. 14. 16:39

 

OCP(Open-Closed principle) 원칙 = 전략 패턴
- Open for extension : interface(전략 정의)를 통한 구현 확장이 가능해야 한다.
- closed for modification : 클라이언트 부분의 코드가 수정이 불가능해야한다.
단, 메인과 같이 새로운 객체를 생성하고 클라이언트에게 전달하는 부분은 수정이 발생한다.

 

 

 

 

1. 역할과 구현을 분리하지 않았을 때

[p.12 / Driver_멤버변수 발췌] K3Car 타입의 변수를 선언할 수 있는 것이지, 데이터를 들고오는 것은 아니다.

private K3Car k3Car;

- 이 코드는 `K3Car` 클래스의 인스턴스를 참조하기 위한 멤버 변수를 선언한다.

- 이것을 통해 `Driver` 클래스 내에서 `K3Car` 객체에 접근할 수 있다. 

- `k3Car` 변수를 사용하여 객체에 접근할 때는 해당 객체의 메서드나 속성에 접근할 수 있지만,

   변수 자체가 객체를 담는 것이 아니므로 객체 자체를 불러오는 것이 아니라 해당 객체의 위치를 가리키는 것이다.

 

[p.12 / Driver] k3Car 멤버변수는 해당 객체의 위치를 저장한다.

public class Driver {
    private K3Car k3Car; //K3car class 호출 -> type화 : 멤버변수 선언

    public void setK3Car(K3Car k3Car) { //외부에서 K3Car 참조값 받아서
        this.k3Car = k3Car; //참조값에 설계도 k3변수 값을 다시 담아주는 것
    }

    public void drive() {
        System.out.println("자동차를 운전합니다.");
        k3Car.startEngine(); //k3Car를 호출할 수 있는 것은 멤버변수로 선언했기 때문
        k3Car.pressAccelerator();
        k3Car.offEngine();
    }
}

- `K3Car` 클래스의 인스턴스를 `Driver` 클래스 내에서 `k3Car`라는 이름의 멤버 변수로 선언했다.

   이것은 `Driver` 클래스가 `K3Car` 객체를 사용할 수 있도록 한다.

- `k3Car.startEngine()`, `k3Car.pressAccelerator()`, `k3Car.offEngine()`는 `k3Car` 객체의 메서드를 호출한다.

    이것은 `Driver` 클래스가 `K3Car` 객체를 사용하여 실제로 자동차를 운전하는 것을 나타낸다.

 

↓ 세부 설명 ↓

 

[p.13 / Driver] 내부 로직 이해하기

private K3Car k3Car; //k3Car 변수는 K3Car 클래스의 인스턴스를 가리키는 참조값을 담는 변수이다.

//`k3Car` 변수는 `K3Car` 클래스의 인스턴스를 가리키는 참조값을 담는 변수이다.
//그러나 처음에는 어떤 값도 가리키지 않으므로 초기값으로 `null`이 할당된다.

public void setK3Car(K3Car k3Car) { //해당 코드는 외부의 K3Car타입 변수를 의미한다.
    //예를 들면 외부의 K3Car타입 변수는 x005이다.
    this.k3Car = k3Car; //즉 null에 x005를 대입한다.
    //이제 private K3car k3car에는 외부에서 받은 x005가 차지한다.
    //이 말은 즉 k3설계도 위치가 아니라 메인에서 사용한 k3설계도 위치가 들어간다.
}

public void drive() {
    System.out.println("자동차를 운전합니다.");
    k3Car.startEngine();
    k3Car.pressAccelerator();
    k3Car.offEngine();
    //해당설계도 위치(x005)에 있는 각 메서드를 호출해서 실행한다.
}

 

 

[p.13 / CarMain0] Main logic 그려보기 

public static void main(String[] args) {
    Driver driver = new Driver(); //driver 객체 생성
    K3Car k3Car = new K3Car(); //k3Car 객체 생성

    driver.setK3Car(k3Car); //driver 내부 setK3Car 메서드 접근
    // 내부에 선언된 k3객체에 접근
    driver.drive(); //driver내부 drive 메서드 접근
}

 

 

2. 1번 코드의 문제 : 새로운 차량 추가시, Driver 코드 변경  

① Model3Car 차량 추가 

public class Model3Car

 

② Driver 기능 변경 : 두 차 모두 소유하고 운전할 수 있지만, 동시에 동시간대 운전할 수 있는 것은 아니다.

[p.15 / Driver]

private K3Car k3Car;
private Model3Car model3Car; //추가

public void setK3Car(K3Car k3Car) {
    this.k3Car = k3Car;
}

public void setModel3Car(Model3Car model3Car) { //코드 추가
    this.model3Car = model3Car;
}

public void drive() { //코드 변경 - model3 추가
    System.out.println("자동차를 운전합니다.");
    if (k3Car != null) { //k3Car에 데이터가 있다면
        k3Car.startEngine();
        k3Car.pressAccelerator();
        k3Car.offEngine();
    } else if(model3Car != null) { //model3에 데이터가 있다면
        model3Car.startEngine();
        model3Car.pressAccelerator();
        model3Car.offEngine();

    }
}

- `k3Car` 또는 `model3Car`가 `null`이 아니라면 해당 객체가 있음을 나타낸다.

 

[p.15 / main]

public static void main(String[] args) {
    DriverRef driver = new DriverRef ();
    K3Car k3Car = new K3Car();

    driver.setK3Car(k3Car);
    driver.drive();

    Model3Car model3Car = new Model3Car();
    driver.setK3Car(null); //현재 k3car에 값이 들어있기 때문에 null을 넣어야 model3을 넣을 수 있다.
    driver.setModel3Car(model3Car);
    driver.drive();
}

- null값을 넣지 않으면 drive를 출력했을 때 동일하게 k3를 넣었을때 값이 출력됨

 

3. 다형성을 활용하여 역할과 구현 분리 - 클라이언트(Drive) 코드 변경 없이 구현 객체 변경

    > 운전자(Drive) : 클라이언트는 자동차(Car)의 역할에만 의존한다.

[p.18 / Car] 인터페이스 Car

public interface Car {
    void startEngine();
    void offEngine();
    void pressAccelerator();
}

 

[p.19 / K3Car & Model3Car] 메서드 Overriding

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 pressAccelerator() {
        System.out.println("K3Car.pressAccelerator");
    }
}

 

[p.19 / Driver] Car라는 interface 이용

public class Driver {

    private Car car;

    public void setCar(Car car) {
        System.out.println("자동차를 설정합니다." + car); //참조값
        this.car = car; //참조값을 받아서 나에게
    }

    public void drive() {
        System.out.println("자동차를 운전합니다.");
        car.startEngine();
        car.pressAccelerator();
        car.offEngine();
    }
}

- 프로세스 로직 그려보기

 

[p.20 / CarMain1]

public class CarMain {

    public static void main(String[] args) {
        Driver driver = new Driver();
        Car k3Car = new K3Car();

        driver.setCar(k3Car);
        driver.drive();

        Car model3Car = new Model3Car();
        driver.setCar(model3Car);
        driver.drive();
    }
}

 

 

728x90