SOLID 디자인 원칙 - ① 단일 책임 원칙
디자인 패턴은 소프트웨어 개발과정에서 자주 마주치게 되는 문제들에 적용할 수 있는 몇 가지 패턴들을 의미합니다. 디자인 패턴을 활용하면 읽기 쉽고, 이해하기 쉽고, 수정하기 쉬우며 재사용성이 높은 코드를 작성할 수 있게 됩니다. 그리고 이런 효율적인 코드를 작성하기 위해서 제안된 중요한 다섯 개의 원칙이 있습니다. 이 원칙들의 앞글자를 따서 SOLID 디자인 원칙이라 부르고 그 다섯 개의 원칙은 다음과 같습니다.
- Single Responsibility Principle(SRP, 단일 책임 원칙)
- Open-Closed Principle(OCP, 열림-닫힘 원칙)
- Liskov Substitution Principle(LSP, 리스코프 치환 원칙)
- Interface Segregation Principle(ISP, 인터페이스 분리 원칙)
- Dependency Inversion Principle(DIP, 의존성 역전 원칙)
이 다섯개의 원칙들은 디자인 패턴이 존재하는 이유에 모두 녹아들어 있기 때문에 디자인 패턴을 본격적으로 다루기 전에 이 5개의 원칙들을 먼저 살펴볼 필요가 있습니다. 이번 글에서는 첫 번째 단일 책임 원칙을 살펴보겠습니다.
Single Responsibility(SRP, 단일 책임 원칙)
단일 책임 원칙이란 "모듈, 클래스, 함수는 하나의 역할(책임)만 가져야 한다." (위키피디아)라는 뜻입니다. 이를 예시를 통해서 살펴보겠습니다. 다음과 같이 Diary(일기장) 클래스를 만든다고 생각해봅시다. 일기장에는 매일매일 글을 쓸 수 있기 때문에 글을 추가하는 기능인 add(const string& entry) 함수를 제공해주는 것은 일기장의 역할 중 하나로 볼 수 있습니다.
class Diary
{
public:
explicit Diary(const string& title) : title(title) {}
void add(const string& entry);
vector<string> get_entries() const { return entries; }
private:
string title;
vector<string> entries;
};
void Diary::add(const string& entry)
{
static int count = 1;
entries.push_back(to_string(count++) + ": " + entry);
}
int main()
{
Diary j{ "My Diary" };
j.add("I cried today");
j.add("I ate a bug");
return 0;
}
SRP를 위반하는 설계
이제 작성된 일기를 저장하는 기능이 필요하다고 가정해봅시다. 파일에 저장하는 기능을 Diary 클래스에서 다음과 같이 구현할 수 있습니다.
void Diary::save(const string& filename)
{
ofstream ofs(filename);
for (auto& s : entries)
ofs << s << endl;
}
그런데 이렇게 Diary 클래스에 직접 저장하는 역할을 수행하도록 설계하는 것은 "모듈, 클래스, 함수는 하나의 역할(책임)만 가져야 한다." 에 위배되는 방식입니다. 일기의 역할은 어디까지나 항목들을 기입/관리하는 것이지 하드디스크에 파일을 쓰는 것이 아니기 때문입니다. 만약 데이터 저장 방식이 변경된다면 이런 방식으로 파일을 저장하는 클래스들을 모두 수정해야 하는 문제가 발생합니다.
SRP를 만족하는 설계
그래서 일기를 기입/관리하는 역할을 하는 Diary 클래스로 부터 파일을 저장하는 역할을 분리하여 다음과 같이 PersistenceManager 클래스를 만들 수 있습니다.
class PersistenceManager
{
public:
static void save(const Diary& d, const string& filename)
{
ofstream ofs(filename);
for (auto& s : d.get_entries())
ofs << s << endl;
}
};
이제 하나의 클래스는 다음과 같이 하나의 역할만을 수행하게 되어 "모듈, 클래스, 함수는 하나의 역할(책임)만 가져야 한다." 라는 원칙을 만족합니다.
- Diary 클래스: 일기를 기입/ 관리하는 역할
- PersistenceManager 클래스: 일기를 저장하는 역할
전지전능 객체
Single Responsibility Principle(SRP, 단일 책임 원칙)을 가장 극단적으로 위배하는 경우로 전지전능 객체가 있습니다. 전지전능 객체는 가능한 많은 기능을 담아 하나의 괴물 같은 클래스를 이룹니다. 이런 클래스는 문제를 찾기도 수정하기도 굉장히 어려워집니다. 효율적인 코드를 작성하기 위해서는 전지전능 객체가 되는 것을 피하는 것이 좋습니다.
<출처>
유튜브 채널 "코드없는 프로그래밍": https://www.youtube.com/channel/UCHcG02L6TSS-StkSbqVy6Fg
길벗 출판사: 모던 C++ 디자인 패턴(Dmitri Nesteruk 저)
위키피디아: https://en.wikipedia.org/wiki/Single-responsibility_principle