OCP (Open-Closed Principle): 변화에 강하고 확장에 유연한 소프트웨어 설계 원칙

  •  

OCP (Open-Closed Principle): 변화에 강하고 확장에 유연한 소프트웨어 설계 원칙

 

OCP는 객체지향 설계의 중요한 원칙 중 하나로, 소프트웨어 모듈이 확장에는 열려 있고, 수정에는 닫혀 있어야 한다는 원칙입니다. 이는 새로운 기능이나 요구사항이 추가될 때 기존 코드를 수정하지 않고도 시스템을 확장할 수 있도록 해줍니다. OCP를 통해 시스템의 유지보수성과 확장성을 크게 향상시킬 수 있습니다.

 

🎯 OCP의 핵심 개념

 

1. 개방 (Open):

모듈은 확장에 대해 열려 있어야 합니다. 새로운 요구사항이나 기능을 추가할 때 기존 코드를 수정하지 않고도 새로운 코드를 추가할 수 있어야 합니다.

예시: UserDao 클래스는 DB 연결 기능을 확장할 수 있도록 ConnectionMaker 인터페이스를 사용합니다. 이로 인해 UserDao는 다양한 DB 연결 기능을 추가할 수 있는 확장 포인트를 제공합니다.

2. 폐쇄 (Closed):

모듈은 수정에 대해 닫혀 있어야 합니다. 즉, 기존 코드를 변경하지 않고도 시스템의 기능을 확장할 수 있어야 합니다.

예시: UserDao 클래스의 핵심 로직은 변경 없이 그대로 유지됩니다. 새로운 DB 연결 기능이 추가되더라도 UserDao의 기존 코드는 수정되지 않습니다.

 

🛠 OCP를 구현하는 방법

 

추상화 (Abstraction):

코드를 인터페이스나 추상 클래스로 분리하여 변경에 대해 폐쇄적이고, 기능 확장에 대해 개방적이도록 설계합니다.

예시: Shape 추상 클래스는 다양한 도형의 공통 인터페이스를 제공합니다. 이를 상속받은 CircleRectangle 클래스는 도형별로 고유한 넓이 계산 로직을 구현합니다.

다형성 (Polymorphism):

인터페이스나 추상 클래스를 사용하여 다양한 구현체를 수용할 수 있습니다. 다형성을 통해 기능을 확장하면서도 기존 코드를 수정하지 않고 확장이 가능합니다.

예시: AreaCalculator 클래스는 Shape 인터페이스를 받아서 넓이를 계산합니다. 새로운 도형 클래스를 추가해도 기존 코드를 수정할 필요가 없습니다.

상속 (Inheritance):

부모 클래스를 확장하여 새로운 클래스를 생성함으로써 기능을 확장합니다. 이때 부모 클래스의 코드는 변경되지 않으므로 OCP를 만족합니다.

 

📌 OCP 적용 전후의 코드 비교

 

OCP 적용 전

class Rectangle {
    //...
}

class Circle {
    //...
}

class AreaCalculator {
    public double calculateTotalArea(Object[] shapes) {
        double totalArea = 0;
        for (Object shape : shapes) {
            if (shape instanceof Rectangle) {
                Rectangle rectangle = (Rectangle) shape;
                totalArea += rectangle.getArea();
            } else if (shape instanceof Circle) {
                Circle circle = (Circle) shape;
                totalArea += circle.getArea();
            }
            // 새로운 도형이 추가될 때마다 이곳에 조건을 추가해야 합니다.
        }
        return totalArea;
    }
}

 

OCP 적용 후

abstract class Shape {
  public abstract double area();
}

class Circle extends Shape {
  private double radius;
  //...
}

class Rectangle extends Shape {
  private double width;
  private double height;
  //...
}

class AreaCalculator {
  public double calculateArea(Shape shape) {
    return shape.area();
  }
}

 

💡 OCP의 장점

 

유지보수 용이성: 새로운 기능을 추가할 때 기존 코드를 수정하지 않아도 되므로, 코드의 안정성이 높아지고 유지보수가 쉬워집니다. 🛠

유연한 설계: 코드의 확장 가능성이 높아져 새로운 요구사항을 쉽게 반영할 수 있습니다. 🔄

테스트 용이성: 코드 변경이 적어 테스트해야 할 범위가 줄어들고, 테스트가 더 쉬워집니다. 🧪

 

OCP를 잘 적용한 설계는 변화에 강하고 확장에 유연한 시스템을 구축하는 데 매우 중요합니다. 이 원칙을 통해 더 나은 소프트웨어를 만들 수 있습니다. 🚀

 

위 이미지는 OCP를 가장 잘 보여주는 그림입니다.

UserDao의 ConnectionMaker 인터페이스를 통해 제공되는 확장 포인트는 확장을 위해 Open 되어 있지만, 이러한 확장을 위해 UserDao 자신의 변화가 불필요하게 일어나지 않도록 Close되어 있습니다.

 

이러한 OCP를 지키기 위해 다양한 디자인 패턴이 존재하며, 상속, 추상화, 인터페이스 등의 개념을 활용하여 객체 간의 결합도를 낮추고, 유연하고 확장 가능한 설계를 만들어냅니다. OCP는 소프트웨어 개발에서 중요한 원칙 중 하나이며, 유지보수와 확장성을 고려한 잘 설계된 소프트웨어를 만드는 데에 큰 역할을 합니다.

  • 추상화: 추상화를 사용하여 코드의 일부를 인터페이스나 추상 클래스로 분리하고, 이를 기존 코드와 분리합니다. 이렇게 분리된 코드는 변경에 대해 폐쇄적이며, 기능을 추가할 때는 새로운 클래스를 만들어서 이를 구현하면 됩니다.
  • 다형성: 다형성을 사용하여, 인터페이스나 추상 클래스에 대한 구현 클래스를 다양하게 만들 수 있습니다. 이렇게 구현된 클래스는 기존 코드에 영향을 주지 않으면서 기능을 확장할 수 있습니다.
  • 상속: 상속을 사용하여, 부모 클래스를 확장하여 새로운 클래스를 만들 수 있습니다. 이렇게 만들어진 새로운 클래스는 기존 코드와는 독립적으로 동작하므로, 기능을 확장할 때 영향을 주지 않습니다.

 

  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유