뭉균의 개발일지

[CS지식] 객체지향 프로그래밍이란? 본문

CS

[CS지식] 객체지향 프로그래밍이란?

박뭉균 2024. 9. 10. 13:36

✏️ 객체지향 프로그래밍이란?

객체지향 프로그래밍(OOP, Object-Oriented Programming)은 프로그램을 객체(object)라는 단위로 구성하여 개발하는 방법론으로 현실 세계의 개념을 코드로 표현하고자 하는 접근법입니다. 객체는 데이터(속성, property)와 그 데이터에 작용하는 함수(메서드, method)를 하나로 묶은 단위입니다. OOP의 핵심은 코드의 재사용성, 유지보수성, 확장성을 높이는 데 있습니다.

 

📚 용어 정리

객체지향 프로그래밍에서 주로 사용되는 용어를 정리하겠습니다. 

 

  • 객체(Object)
    • 현실 세계의 사물이나 개념을 프로그래밍적으로 표현한 것입니다. 객체는 속성과 행동을 가집니다. 예를 들어, '자동차'라는 객체는 '색상', '모델' 등의 속성과 '운전하다', '멈추다' 등의 행동을 가질 수 있습니다.
  • 인스턴스(Instance)
    • 객체지향 프로그래밍에서 클래스에 의해 생성된 구체적인 객체를 의미합니다. 클래스는 설계도이고, 인스턴스는 그 설계도를 바탕으로 만들어진 실제 사례(예시)입니다.
  • 클래스(Class)
    • 객체를 만들기 위한 설계도입니다. 클래스는 객체의 구조(속성)와 동작(메서드)을 정의하며, 이 클래스에서 여러 객체를 생성할 수 있습니다. 예를 들어, 자동차라는 클래스에서 특정 차량 객체를 여러 개 만들 수 있습니다.
붕어빵을 만드는 상황으로 예시를 들어보면, 붕어빵(객체)을 만들기 위해서는 붕어빵틀(클래스)이 필요합니다. 이 붕어빵틀로 실제(인스턴스) 붕어빵을 만들어냅니다.  

 

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

 

각 특징들을 설명하는 과정에서, 이해를 돕기 위해 예시 코드를 작성했고 코드는 JavaScript를 사용했습니다.

 

캡슐화(Encapsulation)

객체 내부의 데이터를 숨기고, 외부에서는 지정된 메서드를 통해서만 접근하도록 제한하는 방식입니다. 이를 통해 객체 간의 상호작용을 명확히 하고, 객체 내부 구현을 보호할 수 있습니다.

 

class Person {
    // private 필드 선언 (앞에 #을 붙임)
    #name;
    #age;

    constructor(name, age) {
        this.#name = name;
        this.#age = age;
    }

    // public 메서드
    getName() {
        return this.#name;
    }

    getAge() {
        return this.#age;
    }

    setAge(age) {
        if (age > 0) {
            this.#age = age;
        } else {
            console.log("나이는 0보다 커야 합니다.");
        }
    }
}

const person = new Person("홍길동", 30);

console.log(person.getName()); // 홍길동
console.log(person.getAge());  // 30

person.setAge(35);
console.log(person.getAge());  // 35

// private 필드에 직접 접근할 수 없음
// console.log(person.#name); // 오류: private 필드에 접근할 수 없습니다.
// console.log(person.#age);  // 오류: private 필드에 접근할 수 없습니다.

상속(Inheritance)

기존 클래스(부모 클래스)의 속성과 메서드를 새로운 클래스(자식 클래스)가 물려받아 사용할 수 있게 하는 기능입니다. 이를 통해 코드의 재사용성을 높일 수 있습니다. 예를 들어, 동물이라는 부모 클래스를 상속받아 개, 고양이 등의 자식 클래스를 만들 수 있습니다.

 

// 부모 클래스 Animal
class Animal {
  constructor(name) {
    this.name = name;
  }

  sound() {
    console.log(`${this.name} 울음소리`);
  }
}

// 자식 클래스 Dog
class Dog extends Animal {
  sound() {
    console.log(`${this.name} 멍멍!`);
  }
}

// 자식 클래스 Cat
class Cat extends Animal {
  sound() {
    console.log(`${this.name} 야옹!`);
  }
}

// 인스턴스 생성 및 사용
const dog = new Dog('Buddy');
const cat = new Cat('Whiskers');

dog.sound(); // 출력: Buddy 멍멍!
cat.sound(); // 출력: Whiskers 야옹!

 

다형성(Polymorphism)

같은 이름의 메서드가 여러 클래스에서 다른 방식으로 동작할 수 있도록 하는 개념입니다. 즉, 하나의 인터페이스(메서드)가 여러 형태로 구현될 수 있습니다. 예를 들어, 달리다()라는 메서드는 개 객체에서는 네 발로 달리고, 새 객체에서는 날아가는 방식으로 달리기를 구현할 수 있습니다.

 

// 부모 클래스 Animal
class Animal {
  constructor(name) {
    this.name = name;
  }

  // 부모 클래스의 달리다 메서드 (기본 정의)
  run() {
    console.log(`${this.name}이(가) 이동하고 있습니다.`);
  }
}

// 자식 클래스 Dog
class Dog extends Animal {
  // run 메서드를 개에 맞게 오버라이드
  run() {
    console.log(`${this.name}이(가) 네 발로 달리고 있습니다.`);
  }
}

// 자식 클래스 Bird
class Bird extends Animal {
  // run 메서드를 새에 맞게 오버라이드
  run() {
    console.log(`${this.name}이(가) 날아가고 있습니다.`);
  }
}

// 인스턴스 생성 및 다형성 확인
const dog = new Dog('버디');
const bird = new Bird('지르피');

dog.run(); // 출력: 버디가 네 발로 달리고 있습니다.
bird.run(); // 출력: 지르피가 날아가고 있습니다.

 

추상화(Abstraction)

복잡한 시스템을 간단하게 표현하는 것입니다. 필요한 속성이나 메서드만 노출하고 불필요한 부분은 숨깁니다. 추상 클래스나 인터페이스를 통해 구현됩니다.

 

class Animal {
    constructor() {
        // 추상 클래스는 직접 인스턴스화할 수 없도록 제한
        if (new.target === Animal) {
            throw new Error("추상 클래스는 직접 인스턴스화할 수 없습니다.");
        }
    }

    // 추상 메서드처럼 동작하는 메서드
    makeSound() {
        throw new Error("자식 클래스에서 makeSound 메서드를 구현해야 합니다.");
    }
}

class Dog extends Animal {
    // Dog 클래스에서 구체적으로 구현된 메서드
    makeSound() {
        console.log("멍멍!"); // 개의 소리 출력
    }
}

class Cat extends Animal {
    // Cat 클래스에서 구체적으로 구현된 메서드
    makeSound() {
        console.log("야옹!"); // 고양이의 소리 출력
    }
}

// const animal = new Animal(); // 오류: 추상 클래스는 직접 인스턴스화할 수 없습니다.

const dog = new Dog();
dog.makeSound(); // 멍멍!

const cat = new Cat();
cat.makeSound(); // 야옹!

 

 

  • Animal 클래스: 추상 클래스 역할을 합니다. new.target을 사용하여 이 클래스를 직접 인스턴스화하지 못하도록 제한합니다. makeSound() 메서드는 추상 메서드처럼 동작하며, 이를 자식 클래스에서 반드시 구현해야 합니다.
  • Dog와 Cat 클래스: Animal 클래스를 상속받아 makeSound() 메서드를 구체적으로 구현한 자식 클래스들입니다.

만약 Animal 클래스에서 makeSound() 메서드를 구현하지 않고 사용하려 한다면, 오류가 발생합니다.

 

🏳️ 결론

이번 포스팅을 통해 객체지향 프로그래밍(OOP)의 기본 개념과 주요 특징들을 살펴봤습니다. 위에서 언급한 특징들은 객체지향 프로그래밍이 효율적이고 유지보수가 용이한 소프트웨어 개발을 가능하게 하는 강력한 방법론임을 보여줍니다. 이해하고 활용하는 데 있어 시간과 노력이 필요하지만, 그 결과는 더욱 견고하고 관리하기 쉬운 코드를 제공할 것입니다.