이 글은 객체지향 5대 원칙, SOLID principle 중 O인 Open Closed Principle에 대해 알아본다.
정의
class, function, module 등 프로그램의 구성 요소는 확장에는 열려 있고 수정에는 닫혀 있어야 한다는 원칙이다. 조금 풀어 설명하면 코드를 변경하지 않으면서 기능 변경 또는 확장할 수 있도록 설계되어야 한다는 것이다.
Open Closed Principle가 준수되지 않은 경우 요구사항이 변화하거나 새로운 요구사항이 생길 때 기존 코드를 수정해야 한다. 반면 완벽하게 준수되었다면 요구사항의 변화 또는 확장 시 기존 코드를 수정할 필요 없이 새로운 코드만 추가하면 된다. 따라서 이 원칙은 프로그램의 유지보수성을 높여주며 코드의 확장성을 높이는 데 크게 기여한다.
언제 사용해야 할까?
분기문으로 구현된 로직
위에서 사용한 예시이다. 이렇게 구현된 경우 아래와 같이 분기문으로 코드를 작성해야 한다.
public class Human {
public void ride(){
if (type.equals("Hyundai")) {
Hyundai hyundai = new Hyundai();
hyundai.run();
} else if (type.equals("Porsche")) {
Porsche porsche = new Porsche();
porsche.run();
}
}
}
Human Class가 자동차를 사용하는 상황이다. 그러나 이렇게 구현해 버리면 Hyundai Car와 Porsche Car의 겹치는 부분이 많아질 것이다. 또한 Hyundai와 Porsche에서 수정사항이 발생하면 Human class 또한 수정해야 할 것이다.
어떻게 사용해야 할까?
interface를 이용한 abstraction과 polymorphism을 이용해 쉽게 구현할 수 있다.
바로 위 단락에서 문제 상황을 살펴보았다. 이러한 문제를 해결하기 위해 interface를 이용한 abstraction과 polymorphism을 사용한다.
Porsche와 Hyundai를 Car interface로 묶는다. Human class는 Car interface에 있는 method만 사용하면 된다. 만약 Porsche나 Hyundai의 기능이 바뀌더라도 Human class에는 영향을 주지 않는다. 즉 수정에 닫혀있게 된다.
interface Car{
// ...
abstract void run();
}
class Hyundai implements Car{
@Override
public void run() {
System.out.println("Hyundai car run");
}
}
class Porsche implements Car{
@Override
public void run() {
System.out.println("Porsche car run");
}
}
public class Human {
private Car car;
public void ride(Car car) {
car.run();
}
}
위와 같이 변화가 예상되는 것을 abstraction해서 interface를 만들고, 그것을 사용하는 object가 변하지 않는 abstraction에 의존하게 코드를 작성한다.
이점
유지보수성과 확장성 증가
Open Closed Principle을 준수했다면 기존 코드를 수정하지 않기 때문에 의도하지 않은 동작이 발생할 확률이 줄어든다. 또한 새로운 코드를 쉽게 확장할 수 있기 때문에 확장성과 유지보수성이 증가한다.
변경의 유연성 증가
변화가 예상되는 것을 interface로 abstraction해서 만약 기능이 추가되더라도그것을 사용하는 object의 코드는 바뀌지 않는다. 따라서 코드 변경의 유연함을 얻게 된다. 다만 interface가 변한다면 그것을 사용하는 object의 코드 또한 바뀌어야 할 것이다.
유의점
Open Closed Principle은 프로그램을 쉽게 확장하고, 확장 시 변경으로 인한 영향을 최소화하는 데 의의가 있다. 이를 위해서는 component를 잘 분할하고 각 component의 변경이 다른 component에게 영향이 가지 않게 hierarchy를 잘 만들어야 한다.
- 보통 low-level component가 자주 수정되며 low-level component의 변경이 high-level component에 영향을 주지 않게 만들어야 한다는 것이다. (물론 그 역도 중요하다)
따라서 component hierarchy를 설계할 때 abstraction을 적절히 사용해야 한다.이를 위해 변하는 것과 변하지 않는 것을 잘 구분해서 코드를 작성해야 한다.
'CS > OOP' 카테고리의 다른 글
[OOP] SOLID - Dependency Inversion Principle (0) | 2023.03.12 |
---|---|
[OOP] SOLID - Interface Segregation Principle (0) | 2023.03.11 |
[OOP] SOLID - Liskov Substitution Principle (0) | 2023.03.09 |
[OOP] SOLID - Single Responsibility Principle (0) | 2023.03.06 |
[OOP] 객체지향 프로그래밍 Object-Oriented Programming (0) | 2023.02.17 |