재우니의 블로그

 

Open/Closed Principle (OCP)

 

 

Open/Closed Principle (OCP)을 준수하는 실행 가능한 예제 코드입니다. 추가적인 기능이나 모듈을 확장할 수 있도록 설계되어 있습니다.

 

다시말해, 소프트웨어 엔터티(클래스, 모듈, 함수)가 확장에는 열려 있어야 하지만 수정에는 닫혀 있어야 한다는 원칙입니다. 이것을 간단하게 설명해보겠습니다.

 

1. 확장에는 열려 있어야 함 (Open for Extension): 기존의 코드를 변경하지 않고도 새로운 기능이나 동작을 추가할 수 있어야 합니다. 이는 새로운 요구사항이나 기능이 추가되더라도 기존 코드를 수정하지 않아도 되게 하는 것을 의미합니다.


2. 수정에는 닫혀 있어야 함 (Closed for Modification): 이미 동작하는 코드를 수정하지 않아야 합니다. 기존의 코드는 안전하게 동작하고 있는 상태를 유지하며, 새로운 기능이나 변경이 필요한 경우에는 해당 부분만을 수정하고 나머지 코드에는 영향을 주지 않아야 합니다.

 

 

이 코드에서는 Shape 클래스를 확장하여 새로운 기능을 추가할 수 있도록 설계되었습니다. Triangle 클래스가 추가되었으며, Shape를 상속하고 CalculateArea 메서드를 구현하여 새로운 도형의 면적을 계산합니다. 이렇게 함으로써 기존의 코드를 변경하지 않고도 새로운 도형을 추가할 수 있습니다. 이는 Open/Closed Principle을 따르는 설계의 한 예입니다.

 

using System;

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

public class Rectangle : Shape
{
    public double Width { get; set; }
    public double Height { get; set; }

    public override double CalculateArea()
    {
        return Width * Height;
    }
}

public class Circle : Shape
{
    public double Radius { get; set; }

    public override double CalculateArea()
    {
        return Math.PI * Radius * Radius;
    }
}

// 추가 기능을 위한 새로운 도형 (Triangle) 클래스
public class Triangle : Shape
{
    public double BaseLength { get; set; }
    public double Height { get; set; }

    public override double CalculateArea()
    {
        return 0.5 * BaseLength * Height;
    }
}

class Program
{
    static void Main()
    {
        // 기존의 Rectangle 및 Circle 클래스 사용
        var rectangle = new Rectangle { Width = 5, Height = 10 };
        var circle = new Circle { Radius = 7 };

        // 새로 추가된 Triangle 클래스 사용
        var triangle = new Triangle { BaseLength = 4, Height = 8 };

        // 각 도형의 면적 계산 및 출력
        Console.WriteLine($"Rectangle Area: {rectangle.CalculateArea()}");
        Console.WriteLine($"Circle Area: {circle.CalculateArea()}");
        Console.WriteLine($"Triangle Area: {triangle.CalculateArea()}");
    }
}

 

 

OCP 위반된 코드

 

 

기존의 AreaCalculator 클래스를 변경하여 새로운 기능을 추가하고자 하는 시나리오를 나타냅니다. 이 코드에서는 AreaCalculator 클래스를 변경하여 Triangle 도형을 추가하려고 시도하였습니다. 이는 OCP를 위반하는 것이며, 기존의 코드를 수정하고 새로운 기능을 추가할 때마다 코드를 변경해야 합니다. OCP를 따르지 않으면 새로운 기능을 추가할 때마다 기존 코드를 수정해야 하는 불편함이 발생하게 됩니다.

 

 

 

public class AreaCalculator
{
    public double CalculateArea(object[] shapes)
    {
        double totalArea = 0;
        foreach (var shape in shapes)
        {
            if (shape is Rectangle)
            {
                var rectangle = (Rectangle)shape;
                totalArea += rectangle.Width * rectangle.Height;
            }
            else if (shape is Circle)
            {
                var circle = (Circle)shape;
                totalArea += Math.PI * circle.Radius * circle.Radius;
            }
            // 새로운 기능 추가를 위해 코드 수정 (OCP 위반)
            else if (shape is Triangle)
            {
                var triangle = (Triangle)shape;
                totalArea += 0.5 * triangle.BaseLength * triangle.Height;
            }
            // 새로운 도형이 추가될 때마다 코드 수정이 필요 (OCP 위반)
        }
        return totalArea;
    }
}

class Program
{
    static void Main()
    {
        // 기존의 Rectangle 및 Circle 인스턴스 생성
        var rectangle = new Rectangle { Width = 5, Height = 10 };
        var circle = new Circle { Radius = 7 };

        // 새로 추가된 Triangle 인스턴스 생성
        var triangle = new Triangle { BaseLength = 4, Height = 8 };

        // AreaCalculator 인스턴스 생성 및 기존 도형들을 사용하여 면적 계산
        var areaCalculator = new AreaCalculator();
        var totalArea = areaCalculator.CalculateArea(new object[] { rectangle, circle, triangle });

        // 결과 출력
        Console.WriteLine($"Total Area: {totalArea}");
    }
}

 

 

AreaCalculator 클래스의 CalculateArea 메서드를 호출할 때, 새로운 도형인 Triangle이 추가되었기 때문에 코드를 수정해야 합니다. 이는 OCP를 위반하고 있으며, 새로운 도형이 추가될 때마다 코드를 변경해야 하는 불편함이 발생합니다. OCP를 지키지 않은 코드는 유연성과 확장성이 떨어지게 됩니다.