# SRP 단일 원칙
- 모든 클래스는 단 하나의 책임을 가져야 한다는 것을 말한다.
즉, 하나의 클래스에 하나의 역할만 구현하라는 것이다.
학생 클래스는 '학생' 이라는 역할에 대해서만 구현해야한다.
학생이면 학생이지 학생이면서 학교이면서 공부일 수는 없으니까 말이다.
게임 개발을 하다보면 학생이면서 학교이면서 공부인 구조를 쉽게 찾아볼 수 있는데 굉장히 좋지 못한 구조이다.
추가, 삭제, 변경 등의 작업이 어려워져 유지보수가 힘들고 협업자가 보았을 때 한눈에 코드를 이해하기가 어려워
스케줄에 차질이 생길 수도 있다.
나도 한때는 편하고 빠르게 개발하기 위해 이를 무시한적이 있었는데 결국에는 부메랑처럼 돌아와 내 뒤통수를 때리는 뼈아픈 경험도 있었다.
(일정이 빡빡해서, 시간이 없고 빨리 만들어야하니까 처럼 변명해도 소용 없다. 결국 내게 되돌아오거나 인수받은 사람에게...)
# OCP 폐쇄-개방 원칙
- 확장에 대해서는 개방되어 있지만 수정에 있어서는 폐쇄적이여야 한다는 것을 말한다.
즉, 기존의 코드를 변경하지 않으면서 확장할 수 있게 구현해야한다는 말이다.
아니, 기존 코드를 변경하지 않으면서 확장하라니!?
이 말은 생각보다 간단하다.
아래 코드블럭을 보면 Animal을 상속받은 Monkey와 Dog가 있다.
여기서 Monkey는 네발로 걷는것이 기본인데 상황에 따라서는 두발로 걸을 수 있도록 기능을 확장하고 싶다.
이 때 기존에 구현한 Animal의 Move()를 수정할 필요는 없다.
Animal을 상속받은 Monkey의 Move에서 해당 기능을 확장하면 되는 것이다.
만약 Animal의 Move를 수정하여 문제가 발생하면 굳이 문제 생길 일 없던 Dog도 영향을 받아 문제가 발생하게 된다.
(Monkey의 Move만 수정했으면 문제가 발생 시 Monkey만 문제가 되었을 것이다.)
물론, 모든 확장을 이렇게 하라는 것이 아니다. 현재 상황은 그저 예시를 든거 뿐이고 상황에 따라 구현하면 된다.
여튼 위와 같이 확장할 때 기존 기능을 건들어서 문제가 발생하는 상황이 일어나지 않도록 하는 것이 중요하다.
public class Animal
{
public virtual void Move()
{
// 네발로 걷는다.
}
}
public class Monkey : Animal
{
public override void Move()
{
// 기본적으로 네발로 걷지만 조건에 따라 두발로 걸을 수 있게
// 기능을 확장한다.
base.Move();
}
}
public class Dog : Animal
{
public override void Move()
{
// 그냥 네발로 걷는다.
base.Move();
}
}
# LSP 리스코프 치환 원칙
- 부모클래스의 위치에 자식 클래스로 대체했을 때 잘 작동해야 한다는 것을 의미한다.
이게 무슨 말인가하면 Animal을 상속 받는 Dog에 Animal 대신 Monkey를 상속받도록 수정했을 때
잘 작동해야 한다는 것이다.
(물론 override 키워드는 virtual로 바꿔주는 정도는 해야지만)
# DIP 의존 관계 역전 원칙
- 의존 관계를 맺을 때 변화하기 어려운 것이나 변화가 없는 것에 의존하라는 의미다.
즉, 쉽게 수정이 일어날 구체적인 클래스보다 인터페이스나 추상 클래스와 관계를 맺으라는 말이다.
아래 코드블럭에 주석으로 예시를 적어놓았다.
public abstract class Animal
{
public abstract void Move()
{
}
}
public class Monkey : Animal
{
public override void Move()
{
}
}
public class Dog : Animal
{
public override void Move()
{
}
}
// 첫번째 예시
public class Program
{
// Animal이라는 추상적인 클래스와 관계를 맺고 있다.
Animal animal = null;
public void SetAnimal(Animal animal)
{
// 만약 이러한 구조일 때 Monkey라는 클래스가
// 더 이상 필요가 없어서 제거가 되었다면?
// 현재 구조에서는 아무런 영향을 받지 않을 것이다.
this.animal = animal;
}
}
// 두번째 예시
public class Program
{
Monkey monkey = null;
public void SetMonkey(Monkey monkey)
{
// 만약 이러한 구조일 때 Monkey라는 클래스가
// 더 이상 필요가 없어서 제거가 되었다면?
// Monkey 클래스가 없어졌기 때문에 에러가 발생할 것이고
// 현재 Class에서 사용중인 Monkey 객체는 모두 지워야 한다.
this.monkey = monkey;
}
}
# ISP 인터페이스 분리 원칙
- 사용하지 않는 인터페이스는 구현하지 말라는 말이다.
범용성이 뛰어난 인터페이스보다 여러개의 구체적인 인터페이스가 낫다.
즉, 필요 없는 상속 구조는 정리하라는 말이다.
'프로그래밍 > 기본기ㆍ자료구조' 카테고리의 다른 글
스레드와 프로세스의 차이 (0) | 2021.02.07 |
---|---|
C# string 비교 == 과 Equals() (2) | 2021.02.05 |
OOP 객체지향 4가지 특징 (0) | 2021.02.03 |
C, C++, C# 언어의 차이점 (2) | 2021.02.02 |
Dictionary와 HashTable의 차이 (0) | 2021.02.01 |