• [TypeScript] 객체지향이란(What is Object Oriented Programing) ?

    2021. 3. 8.

    by. KimBangg

    1. 객체지향이 뭔지 그대는 알고 있는가?

     

    자바, C++ 등을 사용하는 유저라면 자신이 사용하는 언어가 "객체 지향적" 이라는 사실을 알고 있을 것이다.

    필자는 과거 자바를 주언어로 사용하며 객체는 "특정 사물"을 연결하는 느낌의 언어 라고 추상적으로 알고 있었는데, 실제 면접장에서 자바의 특징을 설명해달라고 했을 때 구체적인 말이 떠오르지 않았던 기억이 난다.

     

    최근 타입스크립트를 배우며, 객체지향과 관련된 강의가 시작되었는데 이를 계기로 객체 지향에 대해 이해 해보고자한다.

     

    2. 절차형 vs 객체 지향 

     

    1. 절차지향 프로그래밍 (Procedure programming)

     

    1-1 절차지향 프로그래밍이 무엇인가?

     

    절차지향 프로그래밍이 무엇인가? 라는 질문을 했을 때, 우리 머리 속에 먼저 떠오르는 느낌이라면 "일이 진행되는 순서대로 프로그래밍" 정도 일 것이다.

     

    하지만, 나는 본질적인 이해를 중요시 하기에, 조금 더 쉽고 명확한 정의로 다가가보려고 한다.

     

    자 그렇다면 절차형 프로그래밍이란 무엇인가? 필자가 생각했을 때의 정답은 '주먹구구식' 이라고 생각한다. 즉, 내가 생각하는 떠오르는 방식대로 짜는 것이다. 

     

     

    1-2. 예시

     

    "커피를 만드는 로직을 짠다고 한다면"

     

    1샷의 커피에는 7그램의 커피콩이 필요하고, CoffeeCup은 이러한 내용이 들어 가야 한다는 등의 로직을 만들고 이를 통해 실제 커피를 만들 때, 커피콩의 개수, 몇 잔의 샷이 들어간 커피를 만들지에 대한 입력을 해주면 된다.

     

    그렇기 때문에,  "짧은" 코드에 한해서는 이해 및 작성이 굉장히 편리 할 것이다.

     

    하지만 이후에 반복 사용 할 수 있도록 구조화 하는 것이 아니기에, 잔마다 다른 샷이 들어간 커피 여러 잔을 만들려고 한다면! 코드가 길어 질 것이며 커피를 만들기 위한 로직을 변경 하기 위해서는 코드에 대한 직접적인 수정이 요구 된다.

     

    {
        type CoffeeCup = {
            shots: number;
            hasMilk: boolean;
        }
        const BEANS_GRAM_PER_SHOT : number = 7;
        let coffeeBeans : number = 0;
        function makeCoffee(shots: number): CoffeeCup {
            if (coffeeBeans < shots * BEANS_GRAM_PER_SHOT) {
                throw new Error('Not enought coffee beans!');
            } 
            coffeeBeans -= shots & BEANS_GRAM_PER_SHOT;
            return {
                shots,
                hasMilk: false,
            }
        }
        coffeeBeans += 3 * BEANS_GRAM_PER_SHOT;
        const coffee = makeCoffee(2);
        console.log(coffee);
    }

     

    장점 : 코드를 따라가며 읽고, 작성하기 쉽다.

    단점 :  구조화가 되어 있지 않기에, 유지 보수 및 재사용이 어렵다, 코드가 길어지면 이해가 어렵다.

     

     

    2. 객체지향 프로그래밍 ( Object Oriented Programing )

     

    2-1 객체지향 프로그래밍이 무엇인가?

     

    그렇다면 객체지향이란 무엇인가? 그리고 왜 나온것인가 고민 해보도록 하자.

     

    다들 고민을 해보겠지만, 필자가 얻은 결론은 "귀찮음"으로 인한 효율성을 개발자들이 고민 한 것이라는 결론을 얻을 수 있었다.

     

    절차적 프로그래밍의 경우 "짧고, 규모가 작은" 프로그래밍의 경우 개개인별이 생각하는 로직으로 짜게 된다면 별도의 구조화 같은 작업을 하지 않고 "빠른" 개발이 가능해진다.

     

    하지만, 프로그램의 규모가 커지고 유저들이 증가함에 따라 이를 수정하고 보수 할 때, 주먹구구식으로 짠 그 코드들은 기억에서 사라질 것이며 에러가 발생한 "특정" 부분을 위해 전체 코드의 수정을 요구 할 수 있다.

     

    그리하여, 객체지향이 탄생 했다고 생각이든다. 

     

    이 객체지향에는 클래스와 오브젝트라는 구성요소가 존재하는데, 일반적인 예시로는 클래스는 붕어빵 틀, 오브젝트는 팥과 밀가루 반죽이라고 묘사된다.

     

    즉, "클래스라는 틀에 오브젝트라는 값을 전달하면 클래스 모양으로 정제화되어 코드가 완성된다" 라고 생각하면 용이 할 것이다.

     

    2-2. 예시

     

    절차형 프로그래밍과는 다르게 객체 지향은 위의 로직을 하나의 "틀"로 규정을 한다.

     

    그렇기 때문에! 우리가 원하는 오브젝트를 클래스라는 틀에 전달하면 손쉽게 이를 사용이 가능하다.

     

    뿐만 아니라, makeMachine과 같이 CoffeeMaker를 리턴으로 반환하는 function을 만듦으로써 이를 다채롭게 사용이 가능하다.

     

    즉, 순서가 중심이 아닌 사용 할 클래스 및 객체에 집중을 하며 코드를 사용하고 조정하는데 큰 이점을 가진다.

     

    {
        type CoffeeCup = {
            shots: number;
            hasMilk: boolean;
        }
        
        class CoffeeMaker {
            static BEANS_GRAM_PER_SHOT : number = 7; // class level => 오브젝트별로 새로 생성되지 않는다.
            coffeeBeans : number = 0; // istance(object)
    
            constructor(coffeeBeans: number) {
                this.coffeeBeans = coffeeBeans * CoffeeMaker.BEANS_GRAM_PER_SHOT;
            }
    
            static makeMachine(coffeeBeans:number):CoffeeMaker {
                return new CoffeeMaker(coffeeBeans);
            }
    
            makeCoffee(shots: number): CoffeeCup {
                if (this.coffeeBeans < shots * CoffeeMaker.BEANS_GRAM_PER_SHOT) {
                    throw new Error('Not enought coffee beans!');
                } 
                this.coffeeBeans -= shots & CoffeeMaker.BEANS_GRAM_PER_SHOT;
                return {
                    shots,
                    hasMilk: false,
                }
            }
        }
    
        const maker = new CoffeeMaker(3);
        console.log(maker);
        const maker2 = new CoffeeMaker(5);
        console.log(maker2);
        console.log(maker2.makeMachine(3); // static이 없을 때 사용 할 수 있는 방법
        const maker3 = CoffeeMaker.makeMachine(4); // static인 경우
        console.log(maker3);
    }

     

     

    장점 : "(주어)는 (동사)다." 처럼 사람이 생각하는 방식과 닮아있다. 즉, (객체)는 (메소드)다.

     

    단점 : 처리 속도가 상대적으로 다소 느리다. 설계의 많은 시간이 소요되며 설계를 잘못하면 다시 처음부터 짜야한다. 테스트가 어렵다.

     

    댓글