[유니티 / C#] 객체 지향 프로그래밍과 SOLID 원칙

객체 지향 프로그래밍 ( Object-Oriented Programming ) 이란?

현실 세계의 객체를 모델링하여 소프트웨어를 개발하는 방법론입니다.

 

여기서 객체란 데이터와 기능을 하나의 단위로 묶은 것을 뜻합니다.

 

객체 지향 프로그래밍은 상속, 추상화, 캡슐화, 다형성과 같은 원칙을 통해 복잡한 코드를 체계적으로 관리하고 재사용성을 높여, 대규모 소프트웨어 개발에 적합한 패러다임으로 자리 잡았습니다.

 

 

 

객체 지향 프로그래밍 vs 절차 지향 프로그래밍

  객체지향언어 절차지향언어
장점 ● 코드 재사용, 유지보수 용이
● 기능 추가 쉬움
● 실제 개념과 유사하여 설계가 직관적
● 대규모 프로젝트에 적합
● 실행 속도가 빠름
● 작은 규모의 프로그램을 빠르게 작성 가능
단점 ● 초기 설계가 미흡하면 유지보수 어려움
● 처리속도가 상대적으로 느림
● 코드 중복이 많아 유지보수가 어려움
● 프로그램이 커질수록 구조가 복잡
● 데이터 보안 취약

 

 

 

객체 지향 프로그래밍의 특징 4가지

 

캡슐화

- 데이터와 이를 다루는 메서드를 하나의 객체 안에 묶고, 접근 제한자(private, protected...)를 통해

외부에서 직접 접근하지 못하게 보호해줍니다. (정보 은닉)

 

//A 클래스
public class A : MonoBehaviour
{
    private int id = 915;

    public int GetId()
    {
        return id;
    }
}

//B 클래스
public class B : MonoBehaviour
{
    private int num;

    private void Start()
    {
        A copyA = new A();

        num = copyA.id;      //Error -> private 접근 제한자라 접근 불가
        num = copyA.GetId(); //public 접근 제한자라 접근 가능
    }
}

 

 

추상화

- 객체에 필요한 핵심 기능만 정의하는 것을 말합니다. 인터페이스나 추상 클래스를 통해 구현합니다.

상속과 비슷한 개념으로 복잡성이 감소하고 설계가 단순화됩니다.

//Game 클래스
public abstract class Game : MonoBehaviour
{
    protected string name;

    abstract protected void Login();
}

 

 

상속

- 이미 정의된 클래스(부모 클래스)의 속성과 메서드를 새로운 클래스(자식 클래스)가 물려받아 재사용할 수 있습니다.

코드의 재사용성을 높이고 추후 확장에 용이해집니다.

//MapleStory 클래스
public class MapleStory : Game
{
    private void Start()
    {
        name = "메이플스토리";
    }

    protected override void Login()
    {
        Debug.Log("이 게임의 이름은 메이플스토리입니다.");
    }
}

//LostArk 클래스
public class LostArk : Game
{
    private void Start()
    {
        name = "로스트아크";
    }

    protected override void Login()
    {
        Debug.Log("이 게임이 이름은 로스트아크입니다.");
    }
}

 

 

다형성

- 같은 이름의 메서드가 상황에 따라 다르게 동작하는 것 입니다.

다형성은 오버로딩과 오버라이딩으로 구현 가능하며, 코드의 유연성과 확정성이 높아집니다.

 

//오버로딩 => 같은 함수명이어도 매개변수의 타입, 개수가 다르면 문제없다
public class A : MonoBehaviour
{
    public void Attack(int a)
    {
        Debug.Log("공격");
    }

    public void Attack(int a, int b)
    {
        Debug.Log("공격2");
    }
}

//오버라이딩 => 부모 클래스의 함수를 자식 클래스에서 재정의(override)하는 것
//Game 클래스
public abstract class Game : MonoBehaviour
{
    abstract protected void Login();
}

//LostArk 클래스
public class LostArk : Game
{
    protected override void Login()
    {
        Debug.Log("이 게임이 이름은 로스트아크입니다.");
    }
}

 

 

 

SOLID 원칙

 

● 단일 책임 원칙 (Single Reponsibility Principle)

- 하나의 클래스는 하나의 책임(역할)만 가져야합니다.

 

● 개방-폐쇄 원칙 (Open-Closed Principle)

- 확장에는 열려있고, 수정에는 닫혀있어야합니다. 새로운 기능은 코드를 수정하지 않고 클래스, 모듈을 확장할 수 있어야합니다.

 

● 리스코프 치환 원칙 (Liskov Substitution Principle)

- 자식 클래스는 언제나 부모 클래스 대신 사용 가능해야 합니다.

부모 타입의 객체를 사용하는 코드가 자식으로 바뀌어도 정상 작동해야 합니다.

 

● 인터페이스 분리 원칙 (Interface Segregation Principle)

- 특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫습니다.

클라이언트는 자신이 사용하지 않는 메서드에 의존하지 않도록 인터페이스를 분리해야 합니다.

 

● 의존성 역전 원칙 (Dependency Inversion Principle)

- 고수준 모듈은 저수준 모듈에 의존해서는 안 되며, 추상화(인터페이스)에 의존해야 합니다.

이를 통해 모듈 간의 결합도를 낮추고 시스템의 유연성과 재사용성을 높일 수 있습니다.