객체 지향 프로그래밍

Web

2024년 8월 7일

·

12 min read

객체란 무엇인가?

프로그래밍 적으로는, 프로그래밍에서 사용되는 데이터 또는 식별자에 의해 참조되는 공간을 의미

일반적으로는, 특정 실체를 ‘객관화’하여 인식하거나, 이해하는 대상

객체라는 개념의 탄생 배경이 뭘까?

완전 초장기의 프로그래밍에서는, 프로그램은 무조건 순서대로 실행되었다. 즉 순차적 프로그래밍이라는 개념만 존재했다.

그러다, 이전에 만들어 둔 것과 같은 반복적인 동작이 필요한 상황이 생기기 시작했다. 그래서 특정 위치로 실행 순서를 강제로 변경하는 goto문이라는 것이 나오게 되었다.

하지만 이런식으로 실행순서를 바꾸다 보니, 코드가 조금이라도 커지는 순간 코드의 흐름을 제어하기 힘들어지기 시작했다.

그래서 실행 순서를 강제로 바꾸는 것이 아니라, 반복을 구간을 설정하고, 해당 코드를 호출하고 나면 다시 원래의 자리로 돌아오는 절차적 프로그래밍이라는 패러다임이 탄생하며, 함수라는 개념이 생겼다.

즉, 절차적 프로그래밍데이터를 처리하는 동작을 함수 단위로 분리하고, 재사용하는 형태로 프로그래밍을 하는 방식이 된다.

하지만 이 역시, 코드의 사이즈가 커지는 순간 한계에 부딪히게 된다. 패러다임의 한계는 프로그램의 덩치가 커져봐야 알 수 있다.

절차적 프로그래밍은 기본적으로 전역 변수의 형태로 만들어진다.

그에 따라, 절차적 프로그래밍은 프로그램의 덩치가 커지면, 변수에 같은 이름을 사용할 수 없게 된다. 예를 들어 foo라는 변수 이름이 다른 상황에서도 쓰여야하는 너무 적합한 변수명이라면? 문제가 생기는 것이다. foo_1, foo_2 이런식으로 관리한다고 해도 결국 사이즈가 커지면 관리에 큰 어려움이 생긴다. 이렇게 prefix가 늘어만 가던 상황에서 namespace라는 구원자가 등장한다.

NAMESPACE

namespace는 하나의 파일 단위, 혹은 모듈 단위로 prefix를 부여해서 관리하는 방식이다.

하지만, 여전히 prefix를 붙여 관리해야했다. 코드가 길어지면, 여전히 namepsace만으로는 비슷한 형태의 데이터를 쉽게 다루지는 못함

그래서 서로 연관이 있는 데이터들을 하나로 묶어, namespace처럼 관리할 수 있는 방식을 생각해냈다.

구조체

const character = {
  name: "cyc",
  hp: 500,
  mp: 500,
};

이런 식으로, 의미 있는 단위로 변수들을 하나로 묶음으로써, 변수명의 중복을 줄이고 함수나 배열 등에서도 하나의 변수처럼 활용할 수 있게 되었다.

구조체는 엄밀하게 말하면 하나의 Type이다.

객체 지향 프로그래밍 (Object-Oriented-Programing)의 등장

구조체의 등장으로, 데이터들을 의미있는 단위로 구조화하여 프로그래밍을 하기 시작했다.

이 과정에서, 동작보다는 데이터를 중심으로 코딩하게 되면 코드의 덩치가 커져도 일관성을 유지하기 좋다는 점을 깨닫게 된다.

그렇게 코드를 한데 모으다 보니, 하나의 패턴이 만들어진다는 것을 알게 된다.

const character = {
	name: 'cyc',
	hp: 500,
	mp: 500,
}
 
function character_attack(character) {...}
function character_skill(character) {...}
function character_move(character) {...}

이런 식으로 하나의 패턴이 완성되다 보니, 구조체에 항상 쓰이는 함수들도 묶어버리면 어떨까? 하는 아이디어가 나왔다. 그렇게 class가 등장한다.

Class

그렇게, 구조체와 함께 항상 쓰이는 함수들까지 하나로 묶어, 함수까지 포함하는 Class라는 개념이 나타났다.

Class에 등장으로 아래와 같은 프로그래밍 방식의 변화가 일어났다.

데이터와 처리 방법을 분리해서 개발하던 절차적 프로그래밍 방식 → 데이터의 처리 방식을 하나의 모듈로 관리되면서, 마치 작은 프로그램들이 독립적으로 돌아가는 형태를 띄게 됨 (컴포넌팅)

위의 부분에서 객체를 찍어낸다는 class, object의 개념이 등장하였다. 이렇게 작은 문제를 해결하는 독립된 객체를 만들고, 조립하여 개발하는 방식인 bottom-up 방식이 나타났다.

이 개념을 확장하면 → 프로그램은 모두 객체로 만들어져 있고, 객체들 간의 메시지를 주고받는 상호작용으로 이루어진다.

객체를 조립해서 사용하는 방식은, 재사용이 가능한 객체를 많이 만들어 놓는 것이 중요하다는 것을 알게 되었다.

객체의 재사용성을 높이기 위해 알아야할 개념

  1. 외부에서 알 필요없는 것들은 숨겨놓자! - 캡슐화

작은 문제를 해결하는 독립된 객체를 사용하게 되면, 객체의 모든 데이터에 접근할 필요가 없다.

외부에서 사용하는 필요한 내용만 접근해서 사용할 수 있게 하면, 안정성과 사용성 측면에서 용이하다.

외부로 노출해야하는 값과 내부에서만 사용하는 값을 구분 = 내부 데이터에 바로 접근하지 못하게 하고, 필요한 메소드만 열어둠 = 캡슐화

class Character {
  #hp = 300;
  #mp = 300;
  name = "cyc";
}
 
// Javascript에서는 변수명 앞에 #을 붙이면 private 필드로 동작한다.

JS에서는 기본적으로 Private가 없었다. 그래서 코드 컨벤션으로 약속을 하거나 / Closure를 사용해서 처리했다

지금은 변수명 앞에 #를 붙이면 private 필드로 동작하도록 지원해준다.

  1. 객체의 일부분만 재사용은 어떻게 해야되지? - 상속

객체가 중심이 되어 재사용하는 것은 좋다. 하지만 객체에는 여러 개의 변수, 함수가 섞여 있어서일부는 재사용하고, 또 다른 일부는 달라져야하는 상황이 생기게 되었다. 즉, 객체의 일부분만 재사용하는 방법을 모색하게 되었다.

그래서 객체의 공통된 부분만 따로 만들고, 그 코드를 상속받아서 활용하고, 다르게 동작하는 부분만 따로 작성하는 방법을 생각하게 된다. 이게 상속의 개념이다.

  1. 상속을 받을 수 있는 객체 이름을 따로 지어줘야겠는데? - 추상화
class Human {
  name = "";
  age = 0;
}
 
class Cyc extends Human {
  name = "cyc";
  age = 25;
}
 
class lhe extends Human {
  name = "lhe";
  age = 23;
}

우리가 모든 사람들을 한데 모아 “인간” 이라고 이라고 부르듯이, 공통적인 부분을 모아서 상위의 개념으로 정의하는 것을 추상화라고 한다.

  1. 각자의 방식으로 움직이자! - 다형성

추상화된 타입의 하위 타입은 여러가지 타입으로 참조할 수 있다는 개념이 바로 다형성이다.

예를 들어, 이동 수단이라는 개념으로 자동차와 비행기를 추상화하고, 이동에 대한 내용을 구현한다고 생각해보자. 비행기는 날아가고, 자동차는 도로로 이동하며 각자 이동 속도나 방법은 제각각이다.

하지만 이동수단이라는 점에서 하나로 묶어 같은 타입으로 취급할 수 있다.

class MoveAble {
  name = "";
  moveTo(x, y) {
    console.log(`${this.name} moves to (${x}, ${y})`);
  }
}
 
class Car extends MoveAble {
  name = "Car";
  moveTo(x, y) {
    console.log(`Car drives to (${x}, ${y})`);
  }
}
 
class AirPlain extends MoveAble {
  name = "Airplane";
  moveTo(x, y) {
    console.log(`Airplane flies to (${x}, ${y})`);
  }
}
 
const car = new Car();
const airPlain = new AirPlain();
 
const movement = [car, airPlain];
 
movement.forEach((move) => move.moveTo(300, 400));

상속 / 추상화 / 다형성 → 차이 및 요약

  • 상속은 자식 클래스가 부모 클래스의 속성과 메서드를 재사용하거나, 추가적인 기능을 확장하는 방법
  • 추상화는 클래스드르이 공통적인 부분들을 찾아서 재사용이 가능한 클래스를 설계하는 것
  • 다형성은 공통적인 메소드로 여러 가지 기능들을 만들어낼 수 있는 것
  • OOP