Java

객체지향 설계의 SOLID 원칙 5가지

개발만파볼까 2023. 5. 25. 21:02
728x90
반응형
SMALL

SOLID 원칙은 다음과 같습니다:

  1. Single Responsibility Principle (SRP, 단일 책임 원칙)
  2. Open-Closed Principle (OCP, 개방-폐쇄 원칙)
  3. Liskov Substitution Principle (LSP, 리스코프 치환 원칙)
  4. Interface Segregation Principle (ISP, 인터페이스 분리 원칙)
  5. Dependency Inversion Principle (DIP, 의존성 역전 원칙)

1. Single Responsibility Principle (SRP, 단일 책임 원칙)

단일 책임 원칙은 클래스는 단 한 개의 책임을 가져야 한다는 원칙입니다. 이를 통해 클래스의 변경이 한가지 이유로 제한될 수 있습니다.

예를 들어, Book 클래스를 만든다고 가정해봅시다.

 

class Book {
    private String title;
    private String author;
    
    // Getters and setters
    
    void save() {
        // Save book to database
    }
}

 

Book 클래스는 책 정보를 저장하고, 데이터베이스에 책을 저장하는 두 가지 책임을 가지고 있습니다. 그러나 SRP에 따르면, 각 클래스는 하나의 책임만 가지는 것이 좋습니다. 따라서 아래와 같이 클래스를 나눌 수 있습니다.

 

class Book {
    private String title;
    private String author;
    
    // Getters and setters
}

class BookDatabase {
    void save(Book book) {
        // Save book to database
    }
}

 

2. Open-Closed Principle (OCP, 개방-폐쇄 원칙)

개방-폐쇄 원칙은 기존 코드를 변경하지 않고 확장할 수 있어야 한다는 원칙입니다. 이를 위해 추상화와 다형성이 사용됩니다.

 

 

interface Shape {
    double area();
}

class Rectangle implements Shape {
    private double width;
    private double height;
    
    // Getters, setters and constructor

    @Override
    public double area() {
        return width * height;
    }
}

class Circle implements Shape {
    private double radius;

    // Getters, setters and constructor

    @Override
    public double area() {
        return Math.PI * Math.pow(radius, 2);
    }
}

class AreaCalculator {
    double totalArea(Shape[] shapes) {
        double total = 0;
        for (Shape shape : shapes) {
            total += shape.area();
        }
        return total;
    }
}

위 코드에서 새로운 도형을 추가하더라도 AreaCalculator는 수정할 필요가 없습니다. 각 도형은 Shape 인터페이스를 구현하므로, AreaCalculator는 단순히 area() 메소드를 호출합니다. 이러한 방식으로 OCP를 준수하고 있습니다.

 

3. Liskov Substitution Principle (LSP, 리스코프 치환 원칙)

리스코프 치환 원칙은 부모 클래스를 자식 클래스로 치환할 수 있어야 한다는 원칙입니다.

예를 들어, 아래와 같은 클래스가 있을 때,

 

 

class Bird {
    void fly() {
        // Implementation
    }
}

class Duck extends Bird {
}

class Ostrich extends Bird {
}

 

Ostrich 클래스(타조)는 Bird 클래스의 fly 메소드를 사용할 수 없습니다(타조는 날 수 없습니다). 따라서, 이런 경우에는 Bird 클래스를 두 개의 서브 클래스로 분리하는 것이 좋습니다.

 

class Bird {
}

class FlyingBird extends Bird {
    void fly() {
        // Implementation
    }
}

class Duck extends FlyingBird {
}

class Ostrich extends Bird {
}

 

4. Interface Segregation Principle (ISP, 인터페이스 분리 원칙)

인터페이스 분리 원칙은 클라이언트가 자신이 사용하지 않는 메서드에 의존하지 않아야 한다는 원칙입니다. 즉, 매우 큰 인터페이스 보다는 여러 개의 작은 인터페이스가 낫다는 원칙입니다.

예를 들어, 아래와 같은 Worker 인터페이스가 있다고 가정해봅시다.

 

interface Worker {
    void work();

    void eat();
}

하지만 일부 일꾼들은 식사 기능을 필요로 하지 않을 수 있습니다. 이런 경우에는 인터페이스를 분리하는 것이 좋습니다.

 

interface Worker {
    void work();
}

interface Eater {
    void eat();
}

class HumanWorker implements Worker, Eater {
    public void work() {
        // Implementation
    }

    public void eat() {
        // Implementation
    }
}

class RobotWorker implements Worker {
    public void work() {
        // Implementation
    }
}

5. Dependency Inversion Principle (DIP, 의존성 역전 원칙)

의존성 역전 원칙은 상위 모듈이 하위 모듈에 의존하면 안 된다는 원칙입니다. 둘 다 추상화에 의존해야 합니다. 이 원칙을 준수함으로써 시스템의 결합도를 줄일 수 있습니다.

예를 들어, 아래 코드는 MySQLDatabase 클래스에 의존하는 User 클래스를 보여줍니다.

 

class MySQLDatabase {
    void save(User user) {
        // Implementation
    }
}

class User {
    private MySQLDatabase db;

    User(MySQLDatabase db) {
        this.db = db;
    }
    
    void save() {
        db.save(this);
    }
}

하지만 이렇게 구현하면 User 클래스는 MySQLDatabase 클래스에 강하게 의존하게 되고, 데이터베이스를 변경하려면 User 클래스도 수정해야 합니다. 따라서 이런 경우에는 인터페이스를 사용하여 의존성을 역전시킬 수 있습니다.

 

interface Database {
    void save(User user);
}

class MySQLDatabase implements Database {
    @Override
    public void save(User user) {
        // Implementation
    }
}

class User {
    private Database db;

    User(Database db) {
        this.db = db;
    }
    
    void save() {
        db.save(this);
    }
}

 

 

이렇게 하면, User 클래스는 Database 인터페이스에만 의존하게 되어 특정 데이터베이스에 강하게 결합되지 않습니다.

이처럼 SOLID 원칙은 소프트웨어의 유지 보수성과 확장성을 향상시키는 데 큰 도움을 줍니다. 이 원칙들을 지키면서 코딩하려면 초기에는 노력이 필요하지만, 결국에는 장기적인 이점을 얻게 될 것입니다.

728x90
반응형
LIST