About OOP Design
개인과제를 진행하면서 OOP 관련 내용을 정리 하다보니 결국 한쪽을 선택해야 되는 상황에 이렀다.
나는 과제도 중요 하다고는 생각하지만 기본BASIC
이 더 중요하다 생각해 OOP를 이해하는데 신경을 많이 썻다.
🔗Post Link
S.O.L.I.D 원칙을 이해하면서
단일 책임 원칙
- 솔리드 원칙에서 가장 중요하게 이행해야될 부분이 있다.
단일 책임 원칙
인데, 클래스는 단 한가지에 책임만을 져야한다는 것이다.- 이 부분만 제대로 이행하더라도 나머지는 의존성을 줄이던지 천천히 해나가면 된다.
1
2
3
4
5
6
7
8
9
10
11
12
class PlayerCtrl
{
public:
void PlayerMovement() { ... }
void PlayerRotate() { ... }
void PlayerInput() { ... }
private:
Vector2 playerDirection;
Vector2 playerRotation;
// ...
};
- 위 코드에 문제점은 해당 클래스는 플레이어의 이동, 회전, 입력과 같은 모든 부분을 책임지고 있다.
- 이는 솔리드 원칙에
단일 책임 원칙
을 위배 하는 코드이다. - 이렇게 될 경우
PlayerCtrl
을 사용하게 되는 코드에 변경 또는 수정사항이 생겼을 때
연쇄적으로 많은 부분들을 변경하고 또 수정해야하는 불가피함이 존재한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class PlayerMovement
{
public:
void PlayerMove();
void PlayerAxis();
private:
Vector2 playerMoveDirection;
};
class PlayerRotation
{
public:
void PlayerRotation();
void PlayerQuaternion();
private:
Vector2 playerRotateDirection;
}
// ...
- 위와 같이 책임을 분리하여 모듈화 하면 어떤 수정사항이 생겼을 때
플레이어 이동PlayerMove
를 사용하는 코드에서 변경할 점이 없게 된다. - 이동 관련된 부분은 PlayerMovement 클래스만 수정하면 되기 때문이다.
- 이 후 우리가 할일은 모듈화된 클래스들을 의존성이 적게 잘 연결만 해주면 된다.
의존성 역전 원칙
- 의존성 역전 원칙은 솔리드 원칙에 가장 마지막에 해당하는 부분인데 아직도 내용 이해가 힘들다.
- 튜터님들에게도 계속해서 물어보고 했지만 역시 직접 사용을 해보지 않아서 그런 것 같다.
- 그러던 도중 정호 튜터님에게 간단한 예제와 함께 내용 이해를 할 수 있었는데 다음과 같다.
- 스위치는 문을 열기 위해 문을 직접 받아와 의존하고 있다.
- 위 이미지대로 코드를 표현하면 다음과 같이 표현할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Switch
{
public:
Door door;
public bool isActivate;
public:
void Toggle()
{
if(isActivate)
{
isActivate = false;
door.Close();
}
else
{
isActivate = true;
door.Open();
}
}
};
class Door
{
public:
void Open()
{
cout << "문 열림" << endl;
}
void Close()
{
cout << "문 닫힘" << endl;
}
}
- 위 코드를 해석해보면
Switch
클래스는Toggle()
에서 문이라는 객체에 대해 의존적이다. - 이 스위치는 오로지 문만을 위한 스위치이며 다른 스위치로 대체할 수 없다.
- 스위치는 문이 열리든 불이 꺼지든 상관 없이 그저 토글(딸깍)만을 해야한다.
- 그리고 내부적인 기능 동작은 문이나 전등에서 처리를 해야하고, 스위치는 누구인지 알 필요가 없어야한다.
- 위 내용을 토대로 다음과 같이 코드를 만들 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class ISwitchable
{
public:
virtual bool GetIsActive() const = 0;
virtual void Activate() = 0;
virtual void Deactivate() = 0;
};
class Door : public ISwitchable
{
public:
bool GetIsActive() override { return _isActive; }
void Activate() override
{
_isActive = true;
cout << "문 열림" << endl;
}
void Deactivate() override
{
_isActive = false;
cout << "문 닫힘" << endl;
}
private:
bool _isActive;
};
class Switch
{
public:
ISwitchable switchClient;
public:
void Toggle()
{
if(switchClient.GetIsActive())
switchClient.Dectivate();
else
switchClient.Activate();
}
}
Switch
클래스는 이제 토글만 해주면 된다.- Switch Client로 누가 들어오든 (Door, Light 등) 상관 없이 토글만 실행시켜주면,
내부적인 실제 로직은 내부에 들어가 있는 데이터가 직접 처리할 것이기 때문이다. - 이 내용을 이해하는데 너무 오랜시간이 걸렸고 실제로 사용하고 응용하기까진 시간이 더 걸릴 것 같다.
- 객체-지향-설계에 대해서 좀 더 이해할 수 있었고 앞으로 코드를 짤 때 생각하면서 짜는 습관을 들일것이다.
This post is licensed under CC BY 4.0 by the author.