이번에는 좋은 객체지향 설계를 위한 5가지 원칙인 SOLID에 대해서 정리해보려고 한다.
원래는 의존성 주입하는 방식들에 대한 글을 쓰려했으나 이것을 먼저 정리하는 것이 좋을 것 같다고 생각되어 정리하게되었다.
SOLID 원칙같은 경우에는 굳이 Spring이 아니더라도 좋은 객체지향 프로그램을 만들고 싶다면 지켜야 될 원칙이다.
어떤 내용인지 한 번 살펴보자.
1. SRP (Single Responsibility Principle, 단일 책임 원칙)
단일 책임 원칙이란 한 클래스는 하나의 책임만을 가져야 한다는 원칙이다.
예를 들어서 학생들을 저장하고 조회하는 기능을 만드려고 하는데, 이 클래스 내에서 프로그램의 실행까지 이루어진다면,
이는 한 클래스가 하나의 책임이 아닌 여러 책임을 가지게 되는 것이므로 SRP 원칙에 위배된다고 볼 수 있는 것이다.
public class SaveStu implements Save{
Map<Long, Student> storage = new HashMap<>();
@Override
public void save(Student student) {
storage.put(student.getId() , student);
}
@Override
public Student findById(Long memberId) {
return storage.get(memberId);
}
}
public class Main{
public static void main(String[] args) {
SaveStu sst = new SaveStu();
Student stu1 = new Student(1, "GG_BB");
sst.save(stu1);
}
}
예제로 위에 코드를 보자.
상속을 받아 메소드를 구현한 클래스 하나와, 그 클래스를 실행하기 위한 클래스 하나로 나누어져 있는 걸로 볼 수 있다.
이렇게 각자 하나의 책임을 가진 클래스라면 SRP를 잘 적용한 것이다.
만약 위 두 코드가 한 클래스에 모여있다면 SRP를 위반 한 것이 되는 것이다.
2. OCP (Open/Closed Principle, 개방/폐쇄 원칙)
소프트웨어 요소(각 파일 등)는 확장에는 열려 있으나 변경에는 닫혀 있어야한다.
이 원칙의 해결법 부터 말하자면 다형성과 의존성 주입을 잘 이용해야 한다는 것이다.
아무리 객체지향을 잘 적용했다고 해도, 기능을 바꿔야 할 때 구체 클래스를 바꿔야 할 것이다.
일단 다형성만을 사용한다면, 이 때 실행하는 코드에서 해당 기능을 하는 클래스로 변경를 해줘야 할 것이다.
하지만 저번 글에서 정리했던 의존성 주입을 사용한다면, 실행 코드를 고쳐 변경하지 않아도 원하는 기능을 사용하게끔 할 수 있는 것이다.
이와 관련한 예제는 이전 글에서 조금 참고해보거나 다음에 작성할 글을 읽어보면 더 이해하기 쉬울 것 같다.
3. LSP (Liskov Substitution Principle, 리스코프 치환 원칙)
프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야한다는 내용이다.
다형성 내에서 인터페이스를 상속 받은 구체 클래스에서는 그 인터페이스의 규약을 다 지켜야 한다는 것이다.
에를 들어 저장하는 기능에다가 조회하는 기능을 넣는다거나 하면 안된다는 것이다.
4. ISP (Interface Segregation Principle, 인터페이스 분리 원칙)
특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다는 내용이다.
예를 들자면 통합 기능을 담은 저장만을 위한 인터페이스, 조회만을 위한 인터페이스를 따로 만드는 것이 좋다는 것이다.
위에 코드에서는 저장과 조회기능이 하나씩 말고는 없어서 애매한 감이 있지만, 여러 저장 옵션과 여러 조회 옵션 등이 존재한다면
해당 원칙을 적용했을 때 인터페이스가 명확해지고, 대체 가능성이 높아진다.
5. DIP (Dependency Inversion Principle, 의존관계 역전 원칙)
프로그래머는 추상화에 의존해야지, 구체화에 의존하면 안된다 라는 내용이다.
쉽게 말하자면, 구현 클래스에 의존하지말고, 인터페이스에 의존하라는 뜻이다.
이 원칙을 따르게 되면 구현 클래스를 유연하게 바꿈으로써 프로그램 작성에 도움이 될 수 있다.
하지만 이 원칙에는 약간의 문제가 있다.
Save sv = new SaveStu();
인터페이스에 의존하기 위해서는 위와 같이 코드를 작성해야 하는데, 이렇게 되면 인터페이스에 의존하기는 하지만,
동시에 구현 클래스에도 의존하고 있는 것이기 때문에 문제가 DIP를 위반하게 되는 것이다.
이 문제 또한 의존관계 주입을 통해 해결 할 수 있으며, 이와 관련한 내용으로는 전 글이나 다음에 작성할 글을 읽어보면 좋을 것 같다.
이렇게 각 원칙 (SRP, OCP, LSP, ISP, DIP)의 앞글자를 따서 SOLID 원칙이라고 불린다.
참고로 이 내용들은 면접에서 나올 수도 있다고 하고, 좋은 객체지향 프로그램을 작성하고 싶다면 이 원칙들을 기억해두면 좋을 것같다.
다음 내용으로는 의존관계 주입을 하는 방법들에 대해서 정리를 할 것이다.
'Spring' 카테고리의 다른 글
[Spring 핵심 원리] 빈 생명주기 콜백 (0) | 2022.03.20 |
---|---|
[Spring 핵심 원리] 의존관계 주입에 대하여 (생성자 주입과 Lombok) (0) | 2022.03.20 |
[Spring 핵심 원리] 싱글톤 패턴 (0) | 2022.03.20 |
[Spring 핵심 원리] 수동 빈 등록을 통한 의존관계 주입 (0) | 2022.03.20 |
[Spring 핵심 원리] Spring이란? (0) | 2022.03.20 |