ABOUT ME

-

오늘
-
어제
-
-
  • 객체지향...? 그게 뭐죠..;;;
    Front-end/Javascript 2020. 8. 30. 04:58

     

    객체지향...??

    컴퓨터로 프로그래밍을 하는 사람이라면 무조건 들어본 그 단어 객.체.지.향!

    객체지향적으로 생각해라, 구현하라 등 많은 조건들이 최근에는 객체지향의 개념으로 접근하여 구현됩니다.

     

    이러한 객체지향을 활용하여 개발을 하면서도, 사실 정확한 개념을 알지 않고서 개발을 하는 경우도 있고 어렴풋이 알고 개발하게 되면 설계에 구멍이 나는 경우가 있습니다.

     

    그래서 우린 먼저 객체지향의 개념부터 알아보겠습니다.

     

    객체지향의 사전적 개념

    객체 지향 프로그래밍(영어: Object-Oriented Programming, OOP)은 컴퓨터 프로그래밍 패러다임 중 하나이다. 객체 지향 프로그래밍은 컴퓨터 프로그램 명령어의 목록으로 보는 시각에서 벗어나 여러 개의 독립된 단위, 즉 "객체"들의 모임으로 파악하고자 하는 것이다. 각각의 객체는 메시지를 주고받고, 데이터를 처리할 수 있다.

     

    ? ? ? ? ? ? ? ?

     

    위 글은 위키피디아의 개념입니다.

    만약 객체지향을 이해하고 저 개념을 읽으면 이해하겠지만 저처럼 처음 접근하여 공부하는 사람에게 과연 몸소 느껴지는 설명일까요?

    조금 더 쉽고 현실적으로 알아봅시다.

     

    객체지향의 현실적 개념

    여기서 말하는 명령어의 목록으로서의 시각을 벗어났다는 의미는 현실에서의 개념을 투영했다고 이해할 수 있을 것 같습니다.

    즉, 현실의 개념을 코드로 투영한다는 것이죠 이를 추상화라고 표현하기도 합니다. 

     

    이러한 추상화의 과정을 통해 하나의 독립된 객체를 만들어 내게 되는데, 이 객체들은 각각의 역할과 데이터를 가진 하나의 현실 개념들이며, 이를 통해 자신의 역할을 수행하고 상호작용을 추구하는 것을 말합니다.

     

    그렇다면 이 독립된 객체들은 어떤 요소들이 있을까요?

     

    객체의 요소

    객체의 요소는 크게 두 가지로 나누어집니다. 이 두가지를 사용해서 객체를 자유롭게 표현 한 후 내부 및 외부에 전달해주는 역할을 합니다.

    • 변수
    • 행동

     

    예를들어 학생이 다수 있는 한 학급이 있다고 생각해봅시다.

     

    한 학생이 컴플렉스가 있었습니다. 바로 무서운 꿈을 꾸면 우는 행동이 있습니다. 이 학생은 평소에 잘 숨긴다고 생각했지만 특정 한 학생이 이 비밀을 알게되었습니다 😓

    비밀을 알게된 학생은 이 소문을 학급에 소문을 냈고, 컴플렉스가 있는 학생은 나만의 비밀이 아닌 모두가 아는 컴플렉스가 되어 큰 고민이 생기게 되었습니다.

     

    변수는 눈물과 꿈 그리고 행동은 컴플렉스가 있는 것을 말하는 것과 무서운 꿈을 꾸면 우는 행동이겠죠?

    그렇다면 여기서 알 수 있는 이야기는 무엇일까요?

    바로 내가 직접 컴플렉스가 있다고 행동하지 않았는데 누군가가 알게 되서 나만의 행동을 공개 당한 것입니다. 😵

     

    이처럼 나의 행동이 없이 외부에서 알아내서 공개가 되면 문제가 발생할 수 있습니다.

    현실에서도 문제지만 프로그래밍에서도 동일한 문제가 발생하게 됩니다. 그래서 항상 이를 인지하고 행동으로 만들어야합니다.

     

    사실 이 개념을 정확히 활용하여 개발하기는 쉽지 않습니다. 그래서 비즈니스 레이어를 통해 특정 객체에 관련된 것들을 모아서 접근하고 싶을 때 객체에 직접 접근하는 것이 아닌, 비즈니스 레이어를 통해 가져오는 방법도 사용합니다.😀

     

    그러면 이런 객체들을 가지고 어떻게 설계해야하는지에 대한 원칙들을 살펴보겠습니다.

     

    객체지향 설계의 5원칙 (SOLID)

    객체지향를 설계할 때 지켜야할 원칙이 있습니다. 총 5가지가 있으며 한 번 살펴보겠습니다.

     

    1. 단일 책임 원칙 (Single Responsibility principle)
    2. 개방-폐쇄 원칙 (Open/Closed principle)
    3. 리스코프 치환 원칙 (Liskov subsitution principle)
    4. 인터페이스 분리 원칙 (Interface segregation principle)
    5. 의존관계 역전 원칙 (Dependency inversion principle)

    단일 책임 원칙

    이는 모든 클래스는 하나의 책임만 가지는 것을 말합니다. 그 말인 즉슨 클래스는 완벽한 캡슐화를 이루어야한다는 것인데요,

    여기서 캡슐화란 추후에 살펴보겠지만 내부의 것들은 격리되어있으며 외부에선 접근할 수 없도록 은.닉.화 시키는 것을 말합니다.

     

    하나의 책임을 가진다는 것은 또한 해당 클래스가 본연에 맞는 일만 해야한다는 것입니다.

    class Seller {
      constructor(theater) {
        this.theater = theater;
      }
    
      판매_가능_티켓_조회(ticket) {}
    
      판매_수금(price) {}
    
      티켓_수량_감소(tickets, count) {}
    
      티켓_판매(movie, time, buyer) {}
      
    }

     

    위 클래스의 메소드를 보면 영화관의 티켓을 판매하는 판매원의 입장에서 생각해 보았을 때 필요없는 메소드가 무엇이 있을까요?

    바로 티켓수량감소 메소드일 것입니다. 

    프로그래밍을 하는 컴퓨터의 이세계 말고 현실 세상에서 영화 판매원의 입장을 생각해봅시다.

     

    구매자는 티켓을 특정 영화, 시간대를 조회해달라고 요청할테고, 금액을 지불할 것입니다.

    판매자는 먼저 해당 티켓 정보를 조회하고, 관람이 가능하다면 수금하여 정산 후 티켓을 최종적으로 판매하겠죠?

    어떻게 보면 티켓을 판매했으니 티켓의 수량이 감소하는게 맞을 수도 있습니다.

     

    하지만, 단일 책임 원칙으로 볼 땐 판매자는 티켓을 판매만 하는 책임을 가지고 있어야합니다. 즉 티켓을 조회해주고 판매 해주기까지의 행동은 조회 -> 수금 -> 판매의 행동에 대한 책임이 있지 수량을 감소시키는 행동에는 책임이 없습니다. 왜냐하면 감소시키는 역할은 극장의 포스기가 해주는 역할이기 때문입니다.

     

    이처럼 현실의 개념을 추상화하여 만든 객체들은 단일 책임 원칙에 의거하여 설계해야합니다.

     

    개방-폐쇄 원칙

    원칙명만 봤을 땐 뭐 어쩌라는거지..? 라는 느낌이 듭니다.

    개방은 확장에 열려있다는 의미이며, 폐쇄는 접근을 마음대로 할 수 없도록 하는 것입니다.

     

    즉, 클래스의 내부에서는 확장할 수 있도록 하지만 외부에서 내부의 데이터 변수 등을 수정 할 수 없게 하는 것입니다.

    Java 등의 언어에서는 접근 제어자(제한자)를 통해 private, protected로 특정 데이터 변수, 메소드를 감추어 폐쇄하는 정책을 가지고 있지만 Javascript는 존재하지 않아 기본적으로 개방-폐쇄 원칙에 어긋나게 설계가 되어있습니다. (ES6 이후 class와 private가 생기긴 했습니다.)

     

    하지만 자바에서도 setter와 getter를 통해 직접 접근하여 보통 사용하고 있으며 Javascript에서도 this로 접근해 사용하고 있습니다. 이는 객체에 직접 접근해서 수정하는 것이기 때문에 객체지향을 이상적으로 정확히 구현한 것은 아니며 이를 방지하기 위해 많은 고민을 해야합니다. ✍️

     

    그래서 클로져 등 폐쇄를 지키기 위한 방법도 있으니 차후에 추가로 알아보도록 하겠습니다.

     

    지금까지 객체지향의 개념과 설계 원칙에 대해서 알아봤습니다. 뭔가 복잡한 것들이 많이 지나갔는데 중요한 객체지향을 구성하는 중요한 키워드들이 또 있습니다..

     

     

    객체지향의 키워드들

    객체지향의 키워드는 총 5가지로 구성되어있습니다.

    • 캡슐화
    • 추상화
    • 상속
    • 다형성
    • 오버로딩(Overloading), 오버라이딩(Overriding)

     

    하나씩 개념을 살펴보겠습니다. 

     

    캡슐화

    위에서 객체지향설계 5원칙 중 단일 책임 원칙을 살펴볼 때 보았던 키워드죠?

    말 그대로 캡슐하면 떠오르는 개념으로 내부는 격리되어있으며 외부에서는 접근할 수 없도록 하는 은닉화를 말합니다.

    Javascript에서는 ES5 까지 Prototype 개념을 통해 캡슐화를 구현하였지만 최근에는 Class를 통해 구현하기도 합니다.

     

    사실 캡슐화가 단일 책임 원칙에서 강조가 되었었지만 실질적으로는 모든 원칙들이 이 캡슐화를 만족해야 가장 이상적인 객체를 만들 수 있습니다.

     

    추상화

    가장 처음에 살펴보았듯이 객체지향을 구현할 때 현실세계의 개념을 직접 프로그래밍에 투영하여 객체를 만드는 것을 말합니다.

    추상화가 잘 되어있어야 캡슐화가 원할히 구현되기 때문에 첫 객체 설계를 잘 해야합니다.

     

    상속

    상속은 많이 들어보셨을텐데요 객체지향의 꽃이라고 불리기도 합니다.

    자식에서 부모의 속성(성격)을 가지도록 하는 것이며, 넓게는 더 확장할 수 있도록 하는 개념입니다.

    Javascript에서는 Prototype 개념을 통해 부모를 상속받는 정책을 사용합니다.

     

    다형성

    다형성이란 키워드를 들어도 잘 이해가 되지 않으실텐데요, 개념으로는 '같은 것으로 다른 결과를 도출한다.' 라고 이해하시면 됩니다.

    만약 Object, Dog 객체가 있다고 가정할 때, Dog가 Object를 상속 받는다면 Dog는 자기 자신일 수도 있지만 Object 일 수도 있기 때문에 다른 결과를 도출할 수 있게 됩니다. 즉, 성질이 하나가 아니라 두개일 수도 있다는 의미입니다.

     

    오버로딩, 오버라이딩

    오버로딩(Overloading)은 해석하면 추가로 불러온다는 의미입니다.

    기존 함수는 동일하게 유지하되 동일한 함수명을 가진 함수의 파라미터를 다르게 하여 새롭게 함수를 만들 수 있다는 것인데요

    이게 어떤 이점이 있을까요?

     

    만약 내가 하나의 파라미터를 받는 함수를 만들었습니다. 그런데 추가 요구사항이 생겨서 파라미터를 두개를 받아야합니다.

    그러면 기존에 만들었던 함수에 만들었던 로직들이 추가 파라미터로 인해 꼬이는 현상이 발생하겠죠?

    이를 해결해주는게 오버로딩입니다.

     

    오버라이딩(Overriding)은 해석하면 추가로 탑승한다는 의미입니다. 메소드 오버라이딩이라도고 부릅니다.

    추가로 탑승한다..? 뭔가 어감상으로 프로그래밍에 적용하려니 이해가 안되는 것 같지만 간단합니다. 말 그대로 내가 추가로 탑승해서 조작을 할 수 있는 권한을 얻은겁니다. 

     

    대표적으로 상속을 할 때 부모에 있는 객체를 가져와 오버라이딩 하여 자식에서 사용하게 되는데요 이를 자식에서 덮어 쓰고 직접 추가로 통제하여 사용하는 것을 말합니다. 즉, 부모의 개념을 가져와서 내껄로 변경한다는 것이죠

    이를 활용하면 다형성을 극대화 하여 개발할 수 있습니다. 하지만 과도한 상속으로 인해 복잡해지는 구조가 될 수도 있습니다.

    댓글