-
[TIL] 객체지향 코드 설계 1TIL 2024. 5. 16. 21:47
객체 지향이란?
객체지향(OPP)
- 추상화
- 다형성
- 상속
- 캡슐화
프로그래밍 언어와 문법을 배우면서 객체지향이란 말은 강의에서든 어떤 문서를 보든 정말 자주 언급되었다.
그래서 객체지향 어떤요소가 들어가고 각각 무슨 뜻인지는 알지만. 막상 코드를 설계할 때는 이렇게 짜는 것이 맞는지 또는 내가 객체지향에 맞게 작성하고 있는지 의구심이 들었다.
그렇게 감을 못잡고있던 도중 오늘 객체지향 특강이 듣게되었다.
프로그래밍에서 이론과 실무중 뭐가 우선인가?
프로그래밍에서는 실무가 먼저다.
실무를 관찰한 결과를 바탕으로 이론이 정립되기 때문에 먼저 코드를 짜는것이 먼저다.
따라서 시중에 나온 이론은 현재 쓰는 기술보다 뒤쳐질 수도 있다. (현재 쓰이는 기술은 아직 이론이 정립되있지 않기 때문에)
그러나 어느정도 보장되있는 이론이고, 한 때는 널리 쓰였기 때문에 우리는 알아둬야 한다.
응집도(Cohesion)와 결합도(Coupling)
응집도
하나의 모듈이 하나의 기능을 수행하는 요소들 간의 연관성
하나 클래스만 본다. (클래스 내부에 연관된 애들로만 구성되있는가)
결합도 (또는 의존도)
어떤 모듈이 다른 모듈에 의존하는 정도를 나타낸다.
클래스 간의 관계를 본다.
예를들어 여러가지의 클래스를 참조한다면, 하나의 클래스라도 문제가 생긴다면 작동하기 힘들 수 있다.
따라서 클래스 간의 연결을 최소화 하고 스크립트 안에서만 동작하도록 구성해야한다.
클래스간 의존도와 결합도는 균등하게 분배되어 있는게 좋다.
참고로 응집도와 결합도는 반비례하기 때문에
자연스럽게 응집도를 높이면 결합도가 낮아지게 된다.
최적의 클래스 설계는 결합도가 낮아지고 응집도를 높여야 된다.
리팩토링(refactoring)
결과의 변경 없이 코드의 구조를 재조정하는 것을 의미한다.
나는 그냥 코드 청소 정도로 이해하고 있다.
앞서 말한 응집도와 결합도를 위해 코드를 짜고 중간중간 리팩토링을 해주는 것이 좋다.
리팩토링 할 때 시도할 것들
1. 연관성이 없는 작업은 다른 객체(클래스)에게 위임한다.
2. 객체 내부의 상태를 캡슐화 하고 오직 메세지를 통해서만 상호작용한다.
(메세지: 메서드(함수) 기준으로 호출 )
변수로 호출하는 것은 지양하는 편이다(변수는 예외성이 높기 때문에) 변수 선언은 private를 권장하는 편이다.
(약간의 예외 : 싱글톤, 스크립터블, 프리팹)
객체지향에서 각각 객체를 능동적으로 봐야한다고 했다 왤까..
캡슐화
하나의 클래스 안에는 연관되어있는 속성과 기능들끼리 있어야한다.
예를들어 감기약에는 감기를 치료하는 성분이 있어야 하지 뜬금없이 다른 성분의 약이 섞여있으면 안된다.
추상화
코드의 확장성을 위해 추상화 된 클래스를 만들고 사용해야한다.
예를 들어 아이템을 만들때 아이템의 기본적인 구조만 추상화한 클래스를 만들어두면
그 클래스를 기반으로 다양한 아이템을 만들 수 있다.
마침 이번 팀 프로젝트에서 내가 맡은 파트가 아이템 만들기라서 강의를 기반으로 한번 구조를 짜봤다.
더보기게임은 벽돌깨기로 공이 아이템과 닿으면 효과가 발동한다는 가정하에 짜봤다.
내가 설계한 아이템 클래스 구조이다.
먼저 Item 클래스를 먼저 설계해서 모든 아이템들이 공통으로 받아야 할 부분을 선언해 놨다.
//Item.cs using UnityEngine; public class Item : MonoBehaviour //아직 초안입니다. { protected virtual void ItemEffect(GameObject ball) { Debug.Log("아이템 효과 발동"); } protected void ItemDestroy() { Destroy(this.gameObject); } private void OnTriggerEnter2D(Collider2D collision) { ItemEffect(collision.gameObject); } }
모든 아이템은 자신만의 효과가 있고, 공에 닿으면 사라져야한다.
따라서 각각의 기능은 상속받은 클래스가 정의할 수 있게 virtual로 선언했지만 사라지는 기능과 충돌 감지는 선언해주지 않았다.
//BallSizeUp using UnityEngine; public class BallSizeUp:Item { private float ballSize=1f; protected override void ItemEffect(GameObject ball) { ball.transform.localScale += new Vector3(ballSize, ballSize,0); ItemDestroy(); } }
//BallDamageUp.cs using UnityEngine; public class BallDamageUp:Item { private float ballDamage; protected override void ItemEffect(GameObject ball) { Debug.Log("공의 데미지를 증가시킵니다."); //Ball ball = ball.GetComponent<Ball>(); //ball.damage += ballDamage; Destroy(this.gameObject); } }
//BallCount Up using UnityEngine; public class BallCountUp : Item { private int ballCount = 2; //일단 2개만 복제 protected override void ItemEffect(GameObject ball) { for(int i=0; i<ballCount;i++) { Instantiate(ball); } Destroy(this.gameObject); } }
각각의 스크립트를 붙인 오브젝트를 프리팹으로 만들어 놓고 한번 테스트 해봤다.
사각형이 동그라미와 충돌하면 원하던 대로 충돌체에 효과를 줬다.
아직 초안이기도 하고 다른 팀원의 스크립트를 받지 못했기 때문에 실제 게임에서도 잘 적용될지는 잘 모르겠다.
많이 고민하고 어려워하던 내용이였어서 유익했던 특강이였던것 같다.
유익했지만 다 이해하지는 못함'TIL' 카테고리의 다른 글
[TIL] DOTween 사용 (0) 2024.05.20 [TIL] Interface 상속과 Json에 관하여 (0) 2024.05.17 [TIL] 유니티 개인과제 2 (0) 2024.05.14 [TIL] 유니티로 개인과제 1 (0) 2024.05.13 [TIL] Unity 3 + 알고리즘 문제 (0) 2024.05.10