상세 컨텐츠

본문 제목

SOLID 원칙

백엔드 공부진행도/Java

by myeongjaechoi 2024. 12. 19. 08:08

본문

SOLID란?

  • 객체지향 설계 원칙의 약어
  • Single Responsibility Principle (SRP) - 단일 책임 원칙
  • Open/Closed Principle(OCP) - 개방/폐쇄 원칙
  • Liskov Substitution Principle(LSP) - 리스코프 치환 원칙
  • Interface Segregation Principle(ISP) - 인터페이스 분리 원칙
  • Dependency Inversion Principle(DIP) - 의존성 역전 원칙

Single Responsibility Principle (SRP) - 단일 책임 원칙

  • 정의 : 클래스는 하나의 책임만 가져야 하며, 변경의 이유가 하나뿐이어야 한다.
  • 목적 : 코드의 가독성, 유지보수성, 테스트 용이성을 높임
  • Spring에서의 구현
    • 각 클래스가 특정 역할만 수행하도록 설계
    • 예: UserService UserRegistrationService, AuthenticationService, AuthorizationService로 분리.
@Service
public class UserRegistrationService {
    @Autowired
    private UserRepository userRepository;

    public void registerUser(User user) {
        // 사용자 등록 로직
    }
}

@Service
public class AuthenticationService {
    @Autowired
    private UserRepository userRepository;

    public boolean authenticate(String username, String password) {
        // 인증 로직
        return true;
    }
}

Open/Closed Principle(OCP) - 개방/폐쇄 원칙

  • 정의 : 소프트웨어 엔티티(클래스, 모듈 등)는 확장에는 열려 있어야 하고, 수정에는 닫혀 있어야 한다.
  • 목적 : 기존 코드를 수정하지 않고 새로운 기능을 추가할 수 있도록 설계
  • Spring에서의 구현
    • 인터페이스와 의존성 주입(DI)을 활용하여 확장성을 높임
    • 예: 결제 방식을 확장 가능한 구조로 설계
public interface PaymentStrategy {
    void processPayment(Order order);
}

@Component
public class CreditCardPaymentStrategy implements PaymentStrategy {
    @Override
    public void processPayment(Order order) {
        // 신용카드 결제 로직
    }
}

@Component
public class PayPalPaymentStrategy implements PaymentStrategy {
    @Override
    public void processPayment(Order order) {
        // PayPal 결제 로직
    }
}

@Service
public class OrderService {
    @Autowired
    private PaymentStrategy paymentStrategy;

    public void placeOrder(Order order) {
        paymentStrategy.processPayment(order);
    }
}

Liskov Substitution Principle(LSP) - 리스코프 치환 원칙

  • 정의 : 서브타입은 언제나 자신의 기반 타입으로 대체될 수 있어야 한다.
  • 목적 : 상속 관계에서 프로그램의 정확성을 유지
  • Spring에서의 구현
    • 부모 클래스나 인터페이스를 사용하는 코드가 자식 클래스에서도 문제없이 동작하도록 설계
    • 예: 동물 클래스와 이를 상속받는 구체적인 동물 클래스
public interface Bird {
    void fly();
}

@Component
public class Sparrow implements Bird {
    @Override
    public void fly() {
        System.out.println("참새가 날아갑니다.");
    }
}

@Component
public class Ostrich implements Bird { // LSP 위반 (타조는 날 수 없음)
    @Override
    public void fly() {
        throw new UnsupportedOperationException("타조는 날 수 없습니다.");
    }
}

Interface Segregation Principle(ISP) - 인터페이스 분리 원칙

  • 정의 : 클라이언트는 자신이 사용하지 않는 메서드에 의존하지 않아야 한다.
  • 목적 : 인터페이스를 작고 구체적으로 설계하여 불필요한 의존성을 제거
  • Spring에서의 구현
    • 큰 인터페이스를 여러 개로 나누어 필요한 기능한 구현하도록 만든다.
// Before ISP (큰 인터페이스)
public interface MessagingService {
    void sendEmail();
    void sendSMS();
}

// After ISP (작은 인터페이스)
public interface EmailService {
    void sendEmail();
}

public interface SMSService {
    void sendSMS();
}

@Service
public class NotificationService implements EmailService, SMSService {
    @Override
    public void sendEmail() {
        // 이메일 발송 로직
    }

    @Override
    public void sendSMS() {
        // SMS 발송 로직
    }
}

Dependency Inversion Principle(DIP) - 의존성 역전 원칙

  • 정의 : 고수준 모듈은 저수준 모듈에 의존해서는 안 되며, 둘 다 추상화에 의존해야한다.
  • 목적 : 코드의 유연성과 테스트 용이성을 높인다.
  • Spring에서의 구현
    • 의존성 주입(DI)을 통해 구체적인 구현 대신 추상화에 의존하도록 설계
public interface NotificationSender {
    void send(String message);
}

@Component
public class EmailNotificationSender implements NotificationSender {
    @Override
    public void send(String message) {
        System.out.println("Email sent: " + message);
    }
}

@Component
public class SMSNotificationSender implements NotificationSender {
    @Override
    public void send(String message) {
        System.out.println("SMS sent: " + message);
    }
}

@Service
public class NotificationService {
    private final NotificationSender notificationSender;

    @Autowired
    public NotificationService(NotificationSender notificationSender) {
        this.notificationSender = notificationSender;
    }

    public void notify(String message) {
        notificationSender.send(message);
    }
}

SOLID Principles 적용 시 이점

  1. 유지보수성(Maintainability): 코드가 명확하고 변경이 용이함.
  2. 확장성(Extensibility): 새로운 기능 추가 시 기존 코드를 수정하지 않아도 됨.
  3. 재사용성(Reusability): 독립적인 컴포넌트를 여러 곳에서 재사용 가능.
  4. 테스트 용이성(Testability): 각 컴포넌트가 독립적이라 단위 테스트 작성이 쉬움.

'백엔드 공부진행도 > Java' 카테고리의 다른 글

객체 지향  (1) 2024.12.26
자바 프로그램  (1) 2024.12.25
순차 지향 절차지향 객체지향  (0) 2024.12.21
동일성과 동등성  (1) 2024.12.19

관련글 더보기