SOLID > OCP (개방-폐쇄 원칙)
in etc.
본 글은 로버트 C.마틴 저자(송준이 엮음)의 [클린 아키텍처: 소프트웨어 구조와 설계의 원칙] 도서를 참고하였습니다.
1. 의미
- Open-Closed Principle.
- 소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.
- 확장에 열려 있다
- 모듈의 확장성을 보장함
- 새로운 변경 사항이 발생했을때 유연하게 코드를 추가함으로써 애플리케이션의 기능을 큰 힘을 들이지 않고 확장할 수 있음
- 변경에 닫혀 있다
- 객체를 직접적으로 수정하는 것은 제한해야 함
- 새로운 변경 사항이 발생했을 때 객체를 직접적으로 수정해야 한다면 새로운 변경사항에 대해 유연하게 대응할 수 없는 어플리케이션이라고 함
- 이는 유지보수 비용의 증가로 이어지게 됨
- 따라서 객체를 직접 수정하지 않고도 변경사항을 적용할 수 있도록 설계해야 함
- 확장에 열려 있다
- 따라서 기존 코드를 수정하기 보다는 반드시 새로운 코드를 추가하는 방식으로 시스템의 행위를 변경할 수 있도록 설계해야만 소프트웨어 시스템을 쉽게 변경할 수 있다.
2. 원칙 위반 예제
class Animal {
String type;
Animal(String type) {
this.type = type;
}
}
// 동물 타입을 받아 각 동물에 맞춰 울음소리를 내게 하는 클래스 모듈
class HelloAnimal {
void hello(Animal animal) {
if(animal.type.equals("Cat")) {
System.out.println("냐옹");
} else if(animal.type.equals("Dog")) {
System.out.println("멍멍");
}
}
}
public class Main {
public static void main(String[] args) {
HelloAnimal hello = new HelloAnimal();
Animal cat = new Animal("Cat");
Animal dog = new Animal("Dog");
hello.hello(cat); // 냐옹
hello.hello(dog); // 멍멍
}
}
- 동작 자체는 문제가 없음
- 하지만 ‘고양이’와 ‘개’ 외에 ‘양’이나 ‘사자’를 추가하게 된다면 HelloAnimal 클래스를 수정해주어야 함
- 현재 코드에서는 각 객체의 필드 변수에 맞게 if문을 분기하여 구성해주어야 함
3. 어떻게 OCP대로 추상화 설계를 할 수 있을까?
- 먼저 변경(확장)될 것과 변하지 않을 것을 엄격히 구분
- 이 두 모듈이 만나는 지점에 추상화(추상클래스 or 인터페이스)를 정의함
- 구현체에 의존하기보다 정의한 추상화에 의존하도록 코드를 작성하기
4. 수정한 예제
// 추상화
abstract class Animal {
abstract void speak();
}
class Cat extends Animal { // 상속
void speak() {
System.out.println("냐옹");
}
}
class Dog extends Animal { // 상속
void speak() {
System.out.println("멍멍");
}
}
class HelloAnimal {
void hello(Animal animal) {
animal.speak();
}
}
public class Main {
public static void main(String[] args) {
HelloAnimal hello = new HelloAnimal();
Animal cat = new Cat();
Animal dog = new Dog();
hello.hello(cat); // 냐옹
hello.hello(dog); // 멍멍
}
}
- 위와 같이 구성하게 되면 기능 추가가 됬을때에도 코드 수정 없이 확장이 가능
Reference
- 로버트 C.마틴, 2019, 클린 아키텍처: 소프트웨어 구조와 설계의 원칙
- https://ko.wikipedia.org/wiki/SOLID(객체지향_설계)
- https://inpa.tistory.com/entry/OOP-💠-아주-쉽게-이해하는-OCP-개방-폐쇄-원칙