일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- linux
- TypeScript
- Scheduling
- OOAD
- algorithm
- React
- css
- Kotlin
- DATABASE
- Android
- mysql
- AWS
- postman
- sequelize
- typeorm
- S3
- ubuntu
- OS
- HTML
- Express
- Crawling
- wireshark
- Util
- Network
- python
- mongoose
- macos
- node.js
- docker
- MongoDB
- Today
- Total
Seongwon Lim
[OOP] 객체지향 설계 원칙 SOLID - OCP(개방 폐쇄 원칙) 이란? 본문
서론
이번 글에서는 객체지향 설계의 5가지 기본 원칙 중에서 O에 해당하는 개방 폐쇄 원칙(OCP)에 대한 개념 및 예제를 다루고자 한다.
단일 책임 원칙(SRP)에 대한 개념은 이전 글에서 다루었으므로 해당 원칙에 대한 개념 이해가 필요한 분들은 아래 글을 참고하면 좋을 것 같다.
개방 폐쇄 원칙 - OCP(Open Closed Principle)
개방 폐쇄 원칙이란 소프트웨어 개체(클래스, 모듈, 함수, 컴포넌트 등)는 확장에 대해서는 열려있어야 하고, 수정에 대해서는 닫혀 있어야 한다는 원칙을 의미한다. 해당 원칙에서 언급된 확장에 대해 열려있어야 하고 수정에 대해서는 닫혀 있어야 한다는 의미는 무엇일까?
- 확장에 대해서 열려있다 : 모듈(또는 함수)의 기능을 확장할 수 있다는 의미로, 요구사항이 변경됨에 따라 요구에 맞게 모듈에 새로운 기능을 추가하거나 기능을 변경하는 것을 의미한다. 다시 말하면, 모듈이 하는 일을 변경할 수 있어야 한다는 뜻이다.
- 수정에 대해서 닫혀있다 : 기존에 구성된 요소들을 수정하지 않고도 모듈의 기능 추가 및 변경이 일어나야 한다는 의미이다.
즉, 변경하는 모듈을 호출하는 상위 모듈 쪽에서는 변경이 발생하지 말아야 한다는 것이다.
개방 폐쇄 원칙이 제대로 이루어지지 않으면 어떠한 단점이 존재할까?
예를 들어 수많은 모듈 중에서 하나의 모듈을 수정한다고 할 때, 해당 모듈과 연결된 다른 모듈들을 수정해야 한다면 시스템을 수정하는 과정에서 높은 유지보수 비용이 발생할 수 있다.
개방 폐쇄 원칙의 설명을 돕고자 예제를 통해 OCP를 이해해보자.
개방 폐쇄 원칙(OCP) 예제
public class Truck {
// 수동 기어 변경
public void changeGear() {System.out.println("수동 기어 변경");}
}
예를 들어, 어떤 운전자는 수동으로 기어를 변경해야 하는 트럭을 가지고 있다고 가정해보자.
public class Driver {
Truck truck;
public Driver(...) {...} // truck 인스턴스 생성했다고 가정
public void change() {truck.changeGear();}
}
운전자 클래스에서는 위와 같이 트럭 인스턴스를 통해 기어를 변경하는 로직을 수행할 수 있을 것이다.
그러나, 나중에 트럭을 운전해야 할 필요가 없어져서 운전자는 트럭을 처분하고 SUV를 구매하기로 한다.
해당 SUV는 자동 기어 변경 기능을 가지고 있다고 가정하면, 다음과 같이 SUV 클래스를 구성할 수 있다.
public class SUV {
// 자동 기어 변경
public void changeGear() {System.out.println("자동 기어 변경");}
}
그러면 Driver 클래스 또한 SUV에 대한 인스턴스를 새롭게 생성해야 하며 이 과정에서 코드의 수정이 일어난다.
이 때 우리는 개방 폐쇄 원칙(OCP)를 위배하게 된다. 수정하는 모듈(Truck, SUV)을 참조하는 상위 모듈(Driver 클래스)의 수정이 일어났기 때문이다.
그러면 Driver 클래스의 수정 없이 새로운 모듈(SUV)를 추가하여 기능을 확장하기 위해서는 어떻게 해야할까?
위 그림처럼 자동차라는 상위 클래스(혹은 인터페이스)를 정의함으로써 운전자는 자동차 클래스만 참조하면 된다.
이렇게 되면 새로운 차가 추가되더라도 운전자는 자동차 클래스만 참조하면 되기 때문에 기존 모듈의 수정에 대해서는 닫혀있는 상태가 되고, 확장에 대해서는 열려있는 상태가 될 수 있다.
OCP 원칙을 적용하여 수정한 코드를 확인해보자.
OCP 원칙을 적용한 코드
public class Car {
public void changeGear();
}
public class Truck exntends Car {
public void changeGear() {수동 기어 변동 로직}
}
public class SUV exntends Car {
public void changeGear() {자동 기어 변동 로직}
}
public class Driver {
Car car;
public Driver(...) {...} // car 인스턴스 생성했다고 가정
public void change() {car.changeGear();}
}
개방 폐쇄 원칙을 준수하여 작성한 코드는 위와 같다. 위처럼 코드를 인터페이스 또는 클래스를 통해 추상화 시키면 다양한 차종이 들어와도 해당 차는 Car 클래스를 참조시킴으로써 유연하게 모듈의 추가(기능 확장)를 할 수 있다. 뿐만 아니라, 수많은 차 종류가 추가되어도 운전자는 Car 클래스만을 참조하면 되기 때문에 기존 코드의 수정을 막을 수 있다.
'OOAD' 카테고리의 다른 글
[UML] 유스케이스 다이어그램(Usecase Diagram) 완벽 정리 (1) | 2022.09.15 |
---|---|
[OOP] 객체지향 설계 원칙 SOLID - SRP(단일 책임 원칙) 이란? (0) | 2022.09.02 |
[OOAD] 결합도(Coupling) & 응집도(Cohesion) (0) | 2022.07.03 |
[Design Pattern] GoF 디자인 패턴이란? (0) | 2022.06.05 |
[OOAD] GRASP Pattern이란? (0) | 2022.05.24 |