SOLID 원칙은 소프트웨어 개발에서 디자인 원칙을 제시하는 가이드라인으로, 이를 따르면 유지 보수 가능하고 확장성이 좋은 소프트웨어를 개발할 수 있습니다.
SOLID는 다음의 다섯 가지 원칙을 나타냅니다.
- SRP (Single Responsibility Principle - 단일 책임 원칙):
클래스는 단 하나의 책임만 가져야 합니다. 어떤 클래스도 변경되는 이유는 단 하나여야 하며, 이를 통해 클래스의 재사용성, 유지 보수성, 테스트 용이성이 증가합니다.
- OCP (Open-Closed Principle - 개방-폐쇄 원칙):
소프트웨어 개체(클래스, 모듈, 함수 등)는 확장에는 열려 있어야 하고, 수정에는 닫혀 있어야 합니다. 즉, 기존의 코드를 변경하지 않고도 새로운 동작을 추가하거나 기존 동작을 변경할 수 있어야 합니다.
- LSP (Liskov Substitution Principle - 리스코프 치환 원칙):
부모 클래스는 언제나 자식 클래스로 대체될 수 있어야 합니다. 이를 위해 자식 클래스는 부모 클래스의 기능을 완전히 지원하고, 부모 클래스가 정의한 규약을 준수해야 합니다.
- ISP (Interface Segregation Principle - 인터페이스 분리 원칙):
클라이언트는 자신이 사용하지 않는 인터페이스에 의존해서는 안 됩니다. 인터페이스는 클라이언트의 요구에 따라 작게 분리되어야 하며, 이를 통해 클라이언트는 필요한 인터페이스에만 의존할 수 있습니다.
- DIP (Dependency Inversion Principle - 의존성 역전 원칙):
의존성은 추상화에 의존해야 하며, 구체화에 의존해서는 안 됩니다. 즉, 코드는 인터페이스나 추상 클래스와 같은 추상화에 의존해야 하고, 구체적인 구현에는 의존하지 않아야 합니다.
이러한 SOLID 원칙들은 소프트웨어의 유연성, 확장성, 재사용성, 유지 보수성을 높이기 위한 지침으로, 객체지향 프로그래밍과 관련하여 많이 언급됩니다. 이러한 원칙들을 준수하면 변경에 유연하고 모듈화된 소프트웨어를 개발할 수 있습니다.
"개방-폐쇄 원칙(Open-Closed Principle, OCP)"은 소프트웨어의 확장성과 유지보수성을 높이기 위한 원칙
소프트웨어 엔티티(클래스, 모듈, 함수 등)는 확장에 대해 개방적이어야 하지만 수정에 대해서는 폐쇄적이어야 합니다.
즉, 새로운 기능을 추가하거나 기존의 기능을 확장하기 위해서는 코드를 변경하지 않고 확장 포인트를 제공해야 합니다.
OCP를 준수하면 소프트웨어 시스템이 미래의 요구사항에 대해 보다 유연하고 확장 가능하게 됩니다.
새로운 기능을 추가하거나 변경할 때, 기존 코드를 수정하지 않고도 쉽게 대응할 수 있으며,
이는 소프트웨어의 유지보수성과 재사용성을 향상시킵니다.
"개방" (Open) - 새로운 기능 추가: OCP는 소프트웨어 컴포넌트가 새로운 기능이나 요구사항을 수용하기 위해 개방적이어야 함을 의미합니다.
이것은 시스템이 변하는 환경에 더 잘 적응할 수 있게 하며, 새로운 요구사항이 나타났을 때 기존 코드를 변경하지 않고도 이를 수용할 수 있어야 합니다.
"폐쇄" (Closed) - 기존 코드 수정 방지: OCP는 기존의 코드나 컴포넌트를 수정하지 않도록 하고자 합니다.
이미 동작 중인 기능이나 클래스를 수정할 때는 버그를 수정하는 것과 같은 예외적인 상황을 제외하고 피해야 합니다.
- 추상화와 인터페이스 사용: 소프트웨어 컴포넌트를 추상 클래스나 인터페이스로 정의하면,
새로운 기능을 추가하려면 해당 인터페이스를 구현하거나 새로운 추상 클래스를 작성할 수 있습니다.
이렇게 함으로써 새로운 동작을 추가하고 기존 코드를 수정하지 않을 수 있습니다.
- 다형성 활용: 다형성을 통해 상속과 오버라이딩을 활용하여 새로운 동작을 추가하거나 기존 동작을 확장할 수 있습니다.
새로운 하위 클래스를 만들어서 새로운 기능을 추가할 수 있습니다.
- 디자인 패턴 사용: OCP를 준수하는 데 도움이 되는 다양한 디자인 패턴이 있습니다.
예를 들어, 전략 패턴은 알고리즘을 컴포넌트로 분리하여 쉽게 대체하거나 확장할 수 있게 합니다.
- 모듈화: 코드를 모듈로 나누고 모듈 간의 의존성을 최소화하여, 새로운 요구사항을 수용하기 위해 하나의 모듈을 수정하더라도 다른 모듈에 영향을 미치지 않도록 합니다.
Java를 사용하여 도형 그리기 애플리케이션의 예시를 만들기
=====================================================================
// OCP를 준수한 예시 코드
// 추상 클래스 Shape 정의
abstract class Shape {
abstract void draw();
}
// 원 클래스
class Circle extends Shape {
void draw() {
System.out.println("원을 그립니다.");
}
}
// 사각형 클래스
class Rectangle extends Shape {
void draw() {
System.out.println("사각형을 그립니다.");
}
}
// 그림 그리기 함수
class Drawing {
void drawShape(Shape shape) {
shape.draw();
}
}
// 클라이언트 코드
public class Main {
public static void main(String[] args) {
Circle circle = new Circle();
Rectangle rectangle = new Rectangle();
Drawing drawing = new Drawing();
drawing.drawShape(circle);
drawing.drawShape(rectangle);
}
}
=====================================================================
Shape 클래스는 모든 도형 클래스(원, 사각형 등)의 추상 클래스로 정의되어 있으며, draw 메서드가 추상으로 선언되어 있습니다.
Circle과 Rectangle 클래스는 Shape를 상속받아 draw 메서드를 구현합니다.
Drawing 클래스는 Shape 객체를 입력으로 받아 draw 메서드를 호출하여 그림을 그리는 역할을 합니다.
이렇게 설계된 코드는 새로운 도형을 추가하려면 새로운 도형 클래스를 작성하고 Shape를 상속하면 됩니다.
이렇게 하면 기존 코드를 수정하지 않고도 시스템에 새로운 도형을 추가할 수 있으므로 OCP를 준수하는 예시 코드입니다.