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();
}
}