객체 지향의 5대 원칙중 OCP(개방 폐쇄 원칙)가 있습니다. OCP를 Typescript에서 하는 방법을 같이 배워 보겠습니다.
객체 지향의 5가지 원칙은 SOLID라고 부릅니다.
객체의 확장은 개방적으로 객체의 수정은 폐쇄적으로 하여하 한다는 원칙을 OCP라고 부릅니다.
기능의 추가 요청이 오면 확장을 통해서 새로운 기능을 손쉽게 구현하고, 확장에 따라서 수정을 최소화 하여 기존 코드에 영향을 적게 주는것이 목표입니다.
새로운 기능의 추가가 있을때 힘을 들이지 않고 추가하여 애플리케이션의 확정성을 극대화한다.
객체를 직접적으로 수정하는것은 지양해야된다.
새로운 수정사항이 발생하였을 때 직접적으로 수정한다면,
변경된 모든 변경점을 확인해야 하기때문에 유연하지 못한 애플리케이션이라고 할수 있다.
유연하지 못한 어플리케이션은 유지보수 비용의 증가로 이어진다.
차량을 뜻하는 Car 클래스가 있고, Car 클래스를 받아 시작하는 DriveCar 클래스가 있다.
해당 코드가 실행되면 문제 없이 실행되는 모습을 보여준다.
class Car {
type: string;
constructor(type: string) {
this.type = type;
}
}
class DriveCar {
start(car: Car) {
if (car.type === 'BMW') {
console.log('BMW engin start!');
} else if (car.type === 'KIA') {
console.log('KIA engin start!');
}
}
}
const driveCar: DriveCar = new DriveCar();
const bmw: Car = new Car('BMW');
const kia: Car = new Car('KIA');
driveCar.start(bmw);
driveCar.start(kia);
// BMW engin start!
// KIA engin start!
해당 코드의 문제는 없으나, 차량이 추가 될 때 마다 DriveCar 클래스에 무한 조건이 추가 되어야 하는 문제가 있다.
class Car {
type: string;
constructor(type: string) {
this.type = type;
}
}
class DriveCar {
start(car: Car) {
if (car.type === 'BMW') {
console.log('BMW engin start!');
} else if (car.type === 'KIA') {
console.log('KIA engin start!');
} else if (car.type === 'HYUNDAI') {
console.log('HYUNDAI engin start!');
} else if (car.type === 'MC_LAREN') {
console.log('MC_LAREN engin start!');
}
}
}
const driveCar: DriveCar = new DriveCar();
const bmw: Car = new Car('BMW');
const kia: Car = new Car('KIA');
const hyundai: Car = new Car('HYUNDAI');
const mcLaren: Car = new Car('MC_LAREN');
driveCar.start(bmw);
driveCar.start(kia);
driveCar.start(hyundai);
driveCar.start(mcLaren);
// BMW engin start!
// KIA engin start!
// HYUNDAI engin start!
// MC_LAREN engin start!
이는 설계부터 잘못되어서 발생하는 문제이다.
OCP에 따라서 확장에 열려있을 구간과 수정에 닫혀있을 구간을 구분하는 것에서 부터 시작한다.
어는 구간에서 열러 있을지 다른구간에서 닫혀있을지는 OCP 규칙에 따라 이행한다.
abstract class Car {
abstract start();
}
class Bmw extends Car {
start() {
console.log('BMW engin start!');
}
}
class Kia extends Car {
start() {
console.log('KIA engin start!');
}
}
class DriveCar {
start(car: Car) {
car.start();
}
}
const driveCar: DriveCar = new DriveCar();
const bmw: Car = new Bmw();
const kia: Car = new Kia();
driveCar.start(bmw);
driveCar.start(kia);
// BMW engin start!
// KIA engin start!
해당 코드 처럼 구성하게 되면 기능이 추가되었을 때 기존 기능의 수정없이 확장할수 있게된다.
abstract class Car {
abstract start();
}
class Bmw extends Car {
start() {
console.log('BMW engin start!');
}
}
class Kia extends Car {
start() {
console.log('KIA engin start!');
}
}
class Hyundai extends Car {
start() {
console.log('HYUNDAI engin start!');
}
}
class McLaren extends Car {
start() {
console.log('MC_LAREN engin start!');
}
}
class DriveCar {
start(car: Car) {
car.start();
}
}
const driveCar: DriveCar = new DriveCar();
const bmw: Car = new Bmw();
const kia: Car = new Kia();
const hyundai: Car = new Hyundai();
const mcLaren: Car = new McLaren();
driveCar.start(bmw);
driveCar.start(kia);
driveCar.start(hyundai);
driveCar.start(mcLaren);
// BMW engin start!
// KIA engin start!
// HYUNDAI engin start!
// MC_LAREN engin start!
확장에는 잘 열려있고 수정에는 잘 닫혀 있게 구현하기 위해서는 추상화를 잘 설정할 필요가 있다.