객체 지향 프로그래밍(OOP)

객체 지향 프로그래밍 (Object Oriented Programming)은 객체를 중심으로 프로그램을 설계하고 구현하는 방법론이다. 자바스크립트에서 OOP는 클래스와 인스턴스, 생성자 함수, 상속 그리고 프로토타입 개념을 통해서 구현된다.

 

클래스와 인스턴스

클래스는 객체를 생성하기 위한 블루프린트 또는 템플릿이다. 클래스는 속성과 메서드를 정의하며, 인스턴스는 클래스를 기반으로 생성된 객체를 의미한다.

 

클래스

ES6 이전에는 자바스크립트에서 클래스를 정의하기 위해 생성자 함수와 프로토타입을 사용했다. 이후에는 'class' 키워드가 추가되어 키워드를 사용하여 클래스를 정의할 수 있게 되었다.

 

클래스 정의

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

    greet() {
        console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
    }
}

// 인스턴스 생성
const bak = new Person('Bak', 30);
bak.greet(); // "Hello, my name is Bak and I am 30 years old."

 

생성자 함수

생성자 함수는 클래스를 정의하는 전통적인 방법으로 'new' 키워드를 사용하여 생성자 함수를 호출하면 새로운 인스턴스가 생성된다.

function Person(name, age) {
    this.name = name;
    this.age = age;
}

Person.prototype.greet = function() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
};

// 인스턴스 생성
const bak = new Person('Bak', 25);
bak.greet(); // "Hello, my name is Bak and I am 25 years old."

 

상속과 프로토타입

상속은 한 클래스가 다른 클래스의 속성과 메서드를 상속받아 사용하는 개념이다. 자바스크립트에서는 프로토타입 기반 상속을 사용한다. 자바스크립트의 모든 객체는 프로토타입 객체를 가지고 있으며, 다른 객체로부터 메서드와 속성을 상속받을 수 있다.

 

클래스 상속

ES6에서는 'extends' 키워드를 사용하여 상속을 구현할 수 있다.

class Animal {
    constructor(name) {
        this.name = name;
    }

    speak() {
        console.log(`${this.name} makes a noise.`);
    }
}

class Dog extends Animal {
    constructor(name, breed) {
        super(name); // 부모 클래스의 생성자를 호출
        this.breed = breed;
    }

    speak() {
        console.log(`${this.name} barks.`);
    }
}

const rex = new Dog('Rex', 'Labrador');
rex.speak(); // "Rex barks."

 

프로토타입 상속

ES6 이전에는 프로토타입을 사용하여 상속을 구현하였다.

function Animal(name) {
    this.name = name;
}

Animal.prototype.speak = function() {
    console.log(`${this.name} makes a noise.`);
};

function Dog(name, breed) {
    Animal.call(this, name); // 부모 생성자 호출
    this.breed = breed;
}

Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.speak = function() {
    console.log(`${this.name} barks.`);
};

const rex = new Dog('Rex', 'Labrador');
rex.speak(); // "Rex barks."

 

상속의 이점

상속의 특징을 제대로 이해하고 적절한 상황에 맞게 활용하는 것이 중요하다.

 

코드 재사용성

상속을 통해 기존 클래스의 기능을 재사용할  수 있기 때문에 이를 통해 중복 코드를 줄이고 새로운 기능을 쉽게 추가할 수 있다.

class Animal {
    constructor(name) {
        this.name = name;
    }

    speak() {
        console.log(`${this.name} makes a noise.`);
    }
}

class Dog extends Animal {
    speak() {
        console.log(`${this.name} barks.`);
    }
}

const dog = new Dog('Rex');
dog.speak(); // "Rex barks."

 

'Dog' 클래스는 'Animal' 클래스의 'name' 속성과 'speak' 메서드를 재사용하여 기능을 확장한다.

 

코드의 가독성과 유지보수성 향상

상속으로 클래스 간의 관계를 명확히 하고, 코드를 더 구조적이고 일관성 있게 작성하여 코드의 가독성을 높이고 유지보수를 쉽게 할 수 있다.

class Shape {
    constructor(color) {
        this.color = color;
    }

    draw() {
        console.log('Drawing a shape');
    }
}

class Circle extends Shape {
    constructor(color, radius) {
        super(color);
        this.radius = radius;
    }

    draw() {
        super.draw();
        console.log(`Drawing a circle with radius ${this.radius}`);
    }
}

const circle = new Circle('red', 5);
circle.draw();
// "Drawing a shape"
// "Drawing a circle with radius 5"

 

'circle' 클래스는 'shape' 클래스를 상속받아 'color' 속성과 'draw' 메서드를 재사용하고 필요한 기능을 추가한다. 이를 통해서 코드가 더 구조적이고 명확해지도록 할 수 있다.

 

다형성(Polymorphism)

다형성은 같은 메서드가 다양한 클래스에서 다른 방식으로 동작하도록 하는 것으로 코드의 유연성을 높일 수 있다.

class Animal {
    speak() {
        console.log('Animal makes a noise');
    }
}

class Dog extends Animal {
    speak() {
        console.log('Dog barks');
    }
}

class Cat extends Animal {
    speak() {
        console.log('Cat meows');
    }
}

function makeAnimalSpeak(animal) {
    animal.speak();
}

const dog = new Dog();
const cat = new Cat();

makeAnimalSpeak(dog); // "Dog barks"
makeAnimalSpeak(cat); // "Cat meows"

 

'makeAnimalSpeak' 함수는 'Animal' 클래스를 상속받는 객체를 인수로 받아 다형성을 통해 다양한 동작을 수행할 수 있다.

 

클래스 간의 계층 구조 정의

상속 구조는 클래스 간의 계층 구조를 정의할 수 있어 복잡한 시스템을 더 쉽게 이해하고 관리할 수 있다.

class Vehicle {
    constructor(brand) {
        this.brand = brand;
    }

    start() {
        console.log('Starting the vehicle');
    }
}

class Car extends Vehicle {
    constructor(brand, model) {
        super(brand);
        this.model = model;
    }

    start() {
        super.start();
        console.log(`Starting the car ${this.brand} ${this.model}`);
    }
}

const car = new Car('Toyota', 'Corolla');
car.start();
// "Starting the vehicle"
// "Starting the car Toyota Corolla"

 

'vehicle' 클래스는 기본적인 차량의 속성과 메서드를 정의하고, 'Car' 클래스는 이를 상속받아 구체적인 차량 모델을 정의한다. 이는 클래스 간의 관계를 명확히 하고 계층 구조를 쉽게 이해할 수 있다.

 

객체 간의 관계 모델링

상속을 사용하면 객체 간의 관계를 모델링하여 복잡한 시스템을 설계하고 구현하는 데 유용하다.

class Employee {
    constructor(name, position) {
        this.name = name;
        this.position = position;
    }

    work() {
        console.log(`${this.name} is working as a ${this.position}`);
    }
}

class Manager extends Employee {
    constructor(name, department) {
        super(name, 'Manager');
        this.department = department;
    }

    manage() {
        console.log(`${this.name} is managing the ${this.department} department`);
    }
}

const manager = new Manager('Bak', 'Sales');
manager.work(); // "Bak is working as a Manager"
manager.manage(); // "Bak is managing the Sales department"

 

'manager' 클래스는 'Employee' 클래스를 상속받아 관리자의 속성과 메서드를 정의하여 객체 간의 관계를 명확히 모델링할 수 있다.

 

상속은 객체 지향 프로그래밍에서 매우 유용한 개념이지만 과도하게 또는 잘못된 방식으로 사용하게 되면 오히려 코드의 복잡성을 증가시켜 유지보수를 어렵게 만들 수 있다.

728x90
반응형

'Program Language > JavaScript' 카테고리의 다른 글

this  (0) 2024.08.26
JavaScript #17 고차 함수(High-order Function)  (2) 2024.07.24
JavaScript #15 비동기 자바스크립트  (0) 2024.07.23
JavaScript #14 ES6+ 문법  (4) 2024.07.23
JavaScript #13 DOM(Document Object Model)  (0) 2024.07.23

new

Instance

객체를 생성할때 사용한다.

C#에서는 내장 클래스인 string, int, double 등을 포함한 모든 클래스 object를 상속받기 때문에  new 키워드를 사용해서 객체를 생성할 수 있다. 

int n = new int();
string s = new string();
MyStruct structInstance = new MyStruct();
MyClass classInstance = new MyClass();

하지만 내장 클래스들은 구조체로 정의되어 있기 때문에 구조체 변수를 생성할 때 new를 사용하지 않고 객체를 바로 생성할 수 있다.

int n = 0;
float f = 1.0f;

string의 경우 .Net에서 특별히 내부적으로 string literal로 정의되어 있는데 때문에 일반적인 참조 타입과는 다르게 직접 변수를 할당하여 객체가 생성이 가능하다.  

 

* string literal : 문자열 상수는 소스 코드 상에 고정된 문자열 값이다.

 

Inherit

new 키워드는 상속과 관련해서도 사용이된다.

상속 관계에 있는 클래스에서 메서드, 프로퍼티, 이벤트 등의 멤버를 재정의할 때 사용되는데 일반적으로 멤버의 재정의에는 override 키워드를 사용하지만 new키워드를 통해서도 멤버의 재정의가 가능하다.

 

class BaseClass
{
	public void Print()
    {
    	Console.WriteLine("Base class");
    }
}

class DerivedClass : BaseClass
{
	public new void Print()
    {
    	Console.WriteLine("Derived class");
    }
}

여기서 new 키워드를 사용하여 재정의된 메서드는 부모 클래스에서 정의된 멤버와 자식 클래스에서 정의된 멤버가 모두 유지되는데 이는 덮어쓰는 override와 다르게 두 개의 멤버가 서로 다른 것으로 재정의된 메서드는 부모 클래스의 멤버와는 관계가 없는 새로운 멤버로 취급된다.

DerivedClass obj = new DerivedClass();
obj.Print();
// "Derived class" 출력

BaseClass obj = new DerivedClass();
obj.Print();
// "Base class" 출력

 

 

728x90
반응형

+ Recent posts