오늘은 특강으로 객체지향에 관한 내용을 배워서 객체지향에 관한 내용으로 TIL을 써볼까 한다.
그 중 코딩에 너무 집중해버리면 놓쳐버릴지 모르는 단일책임원칙에 관한 내용이다.
단일 책임 원칙 ( Single Responsibility Principle, SRP )
단일책임원칙은 객체지향 설계의 SOLID원칙 중 하나로, 클래스나 모듈이 단 하나의 책임만을 가져야 한다는 원칙이다.
여기서 "책임"이란 클래스가 변경될 이유가 하나뿐이어야 한다는 것을 의미한다고 한다.(이 말을 듣고 정말 많은 생각을 하게 되었다.)
SRP를 준수할 시 유지보수와 재사용성, 가독성이 좋아지고 책임이 명확히 나누어져 있어 클래스의 기능별 테스트도 매우 쉬워진다.
아래는 SRP위반 사례 및 적용 사례를 보여주겠다.
아니 이런것도 SRP에 위반이 된다고 ? 라는 생각이 들 정도이다.
public class Character
{
public int health;
public int mana;
public void Move(float x, float y)
{
// 이동관련 코드
}
public void TakeDamage(int damage)
{
// 피격코드
health -= damage;
}
public void Attack()
{
// 공격 코드
mana -= 10;
}
public void PlaySound(string sound)
{
// 캐릭터 관련 사운드
}
}
이렇게 코드를 작성했을때 문제점을 생각해보자.
협업을 할때 매우 불편하다. 캐릭터 스크립트를 담당하는 사람은 캐릭터의 모든것을 만들어야 할 지경이다..
또한 이 상태에서 업데이트를 한다던가 하면 코드가 너무 길어지고, 캐릭터 클래스에 너무 많은것들이 담아지게 돼 가독성도 떨어지게되며, 결국은 클래스 분리를 선택하고 말것이다.
아래는 SRP를 준수한 코드를 보여주겠다.
// 캐릭터의 이동 책임을 담당하는 클래스
public class CharacterMovement
{
public void Move(float x, float y)
{
// 캐릭터 이동 코드
}
}
// 캐릭터의 데미지 처리 책임을 담당하는 클래스
public class CharacterHealth
{
public int health;
public void TakeDamage(int damage)
{
// 캐릭터가 데미지를 받는 코드
health -= damage;
}
}
// 캐릭터의 공격 책임을 담당하는 클래스
public class CharacterAttack
{
public int mana;
public void Attack()
{
// 캐릭터가 공격하는 코드
mana -= 10;
}
}
// 캐릭터의 사운드 처리 책임을 담당하는 클래스
public class CharacterSound
{
public void PlaySound(string sound)
{
// 캐릭터의 사운드를 재생하는 코드
}
}
// 게임 캐릭터 클래스는 각 기능을 담당하는 클래스를 사용할 수 있습니다.
public class Character
{
public string name;
public CharacterMovement movement = new CharacterMovement();
public CharacterHealth health = new CharacterHealth();
public CharacterAttack attack = new CharacterAttack();
public CharacterSound sound = new CharacterSound();
}
이렇게 단일책임 원칙을 적용한다면 생각나는 장점이 너무 많다.
협업에도 매우 유리하고, 다른 추가기능을 넣게 되더라도 다른 클래스에 별 다른 지장을 주지 않는다
예를 들면 공격이 아닌 마법공격이 추가되었으면 새로운 클래스를 만들어서 MagicAttack클래스에서 만들고 간단하게 추가해주어 사용하면 된다.
또한 어떤 한 기능에 문제가 생겼을때 이 문제가 여기저기 복잡하게 엮여있다면 연관이 있는 모든 코드를 수정해야 하지만
SRP를 준수했다면, 문제가 되는 부분만 수정하여 매우 안정적으로 문제해결이 가능하다.