개요

현대 프로그래밍 패러다임 중 가장 주류가 된 프로그래밍 패러다임.

절차 지향 프로그래밍의 한계와 이를 개선한 객체 지향 프로그래밍의 특징과 설계에 대한 주관적인 생각 이야기

 

 


절차 지향 프로그래밍의 한계

1. 데이터와 데이터를 다루는 함수의 분리

절차 지향 프로그래밍은 어떤 타입을 설계할 때, 타입을 다루는 함수를 작성할 때마다 첫 번째 인자로 어떤 데이터를 다룰 것인지 주소값을 받아야 했다.

이는 함수가 길어지는 동시에 함수 내부에서도 포인터로 데이터를 다뤄야 하는 불편함이 있다.

 

2. 함수의 이름을 항상 다르게 작성

함수의 이름은 전역 이름공간을 사용하기 때문에 모든 함수마다 이름을 다르게 설정해야 한다.

 

3. 프로그래밍을 확장하기 불편

어떤 함수가 필요한지 명확하게 호출해야 했기 때문에, 수정사항이 발생 시 변경사항이 많이 발생한다.

 

 


객체지향 프로그래밍

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

1. 캡슐화

데이터 데이터를 다루는 함수같이 작성하게 하는 것

 

객체지향에서 객체란 무엇을 이야기하는 것일까.

객체는 어떠한 대상을 이야기하고 대상이 구성하고 있는 속성과 속성들의 상태(state)로 이루어져 있으며,

이러한 객체가 행동(behavior)하는 기능을 포함하고 있다.

 

볼펜을 예로 들어보자. 볼펜은 플라스틱이라는 재질과 사이즈, 무게, 볼, 잉크, 스프링, 스위치 등의 속성으로 구성되어 있으며, 스위치를 눌러 펜촉이 나온 상태와 들어간 상태 등을 갖는다.

이러한 볼펜은 스위치를 눌러 상태를 전환하는 기능과 볼이 눌리면서 잉크가 나오는 펜을 사용한다는 기능 등의 행동이 가능하다.

 

객체지향에서는 이러한 객체의 상태(필드,멤버 변수) 기능(메소드,멤버 함수)을 하나의 볼펜이라는 클래스(Class) 이름의 캡슐에 넣어 사용한다.

이것이 객체지향의 첫 번째 특징인 캡슐화이다.

 

캡슐화된 객체는 외부에 드러내지 않고 함부로 데이터에 접근할 수 없도록 접근 지정이 가능하여 보다 안전한 객체의 관리가 가능하다.

 

2. 상속

부모 객체의 코드를 자식 객체가 물려 받는 것

 

인간은 어떠한 대상들을 바라볼 때 대상들의 공통적인 특징을 묶어 카테고리화 한다.

한국어, 영어, 일본어, 중국어 등을 의사소통이라는 공통적인 특징으로 언어라는 이름의 카테고리에 묶을 수 있었고,

이러한 언어들은 의사소통이라는 목적을 위해 매개체인 데이터와 데이터를 전달하고 수신하는 공통적인 기능을 갖고 있다.

 

이렇게 우리가 대상을 그룹핑(Grouping)하여 생각하는 이유는 정보를 효과적으로 인지하고 사용할 수 있기 때문이다.

의사소통이라는 일반적인 특징을 갖고 있는 언어라는 정보는 새로운 언어의 정보가 유입된다 하더라도

표현을 위한 데이터와 기능을 포함하고 있을 것이라는 생각의 틀이 형성되기 때문에

우리는 대상의 그룹핑을 통해 효과적으로 생각을 한다.

(물론, 어린아이가 하늘을 날고 날개가 있는 것을 새라는 카테고리에 생각하여, 비행기를 엄청 큰 새라고 이야기하게 되는 일반화의 오류가 발생할 수 있다.

하지만 이는 어린아이가 생각한 분류 목적이 다를 뿐 잘못된 것이라 할 수 는 없을 것이다.)

 

객체지향 프로그래밍에도 객체마다 유사한 상태와 행동의 공통적인 부분을 추상적인 형태로서

상위 객체를 형성하고 상속을 통해 정보를 물려 받는 특징이 있다.

이것이 객체지향의 두 번째 특징인 상속이다.

 

3. 추상화

구현 세부 정보를 숨기는 일반적인 인터페이스를 정의하는 행위를 추상화라 정의한다.

인터페이스는 서로 다른 부분이 만나고 소통하거나 서로에게 영향을 미치는 영역을 의미하며,

추상화를 잘 하면 잘 할 수록 데이터를 다루기 쉬워진다.

 

우리는 객체를 이야기할 때 바라보는 목적에 따라 다르게 이야기 할 수 있다.

단순히 필기만을 목적으로 바라본 볼펜은 필기라는 결과를 달성할 수 있다면 잉크의 색상이나 볼펜의 구조, 볼펜의 재질이 중요하지 않을 것이다. 

그러나 선물용으로 볼펜을 바라본다면, 볼펜의 외형과 재질, 상징성 등을 생각하며 볼펜을 바라보게 될 것이다.

이처럼 객체를 바라볼 때 목적에 따라 필요한 정보와 불필요한 정보가 나뉘게 된다.

객체지향 프로그래밍에서도 객체의 불필요한 세부 정보를 숨기고 목적에 맞는 인터페이스를 정의하여 사용한다.

이를 객체지향의 특징인 추상화라 한다.

 

4. 다형성

다형성이란 여러 형태를 갖는 것을 의미한다.

인터페이스는 같아도 동작하는 행동은 다른 것을 다형성이라 한다.

가상 함수 (Virtual Function) 를 상속받은 자식 객체는 가상함수의 인터페이스를 유지한 채로

구현 세부사항을 바꾸는 오버라이딩 (Overriding) 을 할 수 있다.

 

위에서 이야기한 언어(상위 객체)를 상속받는 각각의 언어들(한국어, 영어 등)은 의사소통이라는 공통적인 특징을 갖고 있지만 한글과 알파벳이라는 형태와 문법이라는 형태로 자신에게 맞게 그 특징을 재정의 하고 있다. (Overriding)

또한 같은 언어라 할지라도 상황이라는 변수에 따라 의미가 달라질 수 있다. 대표적으로 동음이의어를 이야기할 수 있는데, 객체 지향에서도 같은 식별자의 메소드라 할지라도 매개변수에 따라 기능을 달리하는 특징이 있다. (Overloading)

이렇게 다양한 형태를 보일 수 있는 성질을 객체지향의 마지막 특징인 다형성이라 한다.

 

 

객체지향적 설계

객체의 정보를 다루는 특징들은 다른 객체와의 협력 관계를 통해 비로소 객체지향적 설계가 이루어진다.

협력이란 서로가 맡은 역할을 적절한 상황에서 요청과 응답을 주고 받는 것을 의미하며, 객체들은 추상화된 인터페이스를 통해 서로 정보(메시지)를 주고 받고 각자의 역할을 수행하며 협력 한다.

 

플레이어와 몬스터 사이의 협력관계를 예로 들면,

플레이어가 몬스터를 공격하였을 때, 플레이어는 공격이라는 기능을 통해 몬스터에게 일정 데미지의 공격이라는 정보(메시지)를 전달하게 되고, 몬스터는 전달받은 정보를 바탕으로 최종적으로 받을 데미지를 계산하여 자신에게 적용할 것이다. 

그리고 받은 데미지에 따라 생존과 사망여부를 스스로 판단하여 자신의 상태를 결정할 것이다.

 

이러한 협력 관계가 원활하게 구축되기 위해서는 무엇을 위한 프로세스인지 목적이 명확해야 하며, 목적에 따라 어떠한 객체가 무엇을 해야 하는가를 설명할 수 있어야 한다.

 

플레이어가 성장하기 위한 방식으로 전투를 선택했고 전투의 대상을 몬스터로 정했다면, 몬스터는 플레이어를 공격하고 공격받을 수 있어야 하며, 사망시 플레이어에게 보상을 지급할 수 있는 책임과 역할을 갖는 객체여야 할 것이다.

그리고 이 것이 몬스터의 책임과 역할이며 플레이어와 몬스터 객체의 협력 관계를 통한 게임 플레이의 흐름이 될 것이다.

 

SOLID 원칙

 

단일 책임 원칙(Single Responsibility Principle)

A module should be responsible to one, and only one, actor.
모듈은 단 하나의 액터에게만 책임을 져야 한다

모듈은 두 개 이상의 액터를 책임지게 된다면,

하나의 액터에서 발생한 요청사항으로 모듈이 수정이 발생하였을 때 다른 액터에 주는 영향을 고려해야한다.

따라서 유지보수 측면에서 고려해야할 사항이 많아져 Side Effect를 다루기 어려워 진다.

 

 

개방-폐쇄 법칙(Open-Closed Principle)

객체는 확장에는 열려 있어야 하고, 변경에는 닫혀 있어야 한다.

기존 코드를 수정하기보다는 새로운 코드를 추가하는 방식으로 설계해야 시스템을 쉽게 변경할 수 있다.

 

 

리스코프 치환 원칙(Liskov Substitution Principle)

상속 관계에 해당하는 원칙으로 하위 객체가 상위 객체를 대체할 수 있어야 한다.

is - a

[하위 객체] is a [상위 객체] 의 문장이 성립해야 한다.

 

 

인터페이스 분리 원칙(Interface Segregation Principle)

타입이 다른 타입을 의존할 때, 필요한 인터페이스만을 의존하도록 설계하라는 원칙이다.

의존하는 타입이 불필요한 인터페이스를 갖고 있지 않도록

인터페이스를 분할하여 필요한 인터페이스에만 의존할 수 있도록 설계해야 한다.

타입간의 결합도를 메시지 수준으로 낮춤으로 인하여,

불필요한 인터페이스로 인한 유연성과 확장성의 제한을 해결할 수 있다.

( 꼭 필요한 부분에만 연결하자 )

 

 

의존성 역전 원칙(Dependency Inversion Principle)

고수준 정책을 구현하는 코드는 저수준의 세부사항을 구현하는 코드에 의존하면 안된다는 원칙이다.

다형성을 적극 활용하여 저수준 세부사항의 변화에 확장성 있게 설계해야 한다.

 

Player는 Weapon을 의존해야 한다.

Player가 저수준인 Sword 또는 Sword 1에 의존하고 있다면 무기를 교체하는 변화에 민감할 것이다.

728x90

'Program > C (C++,C#)' 카테고리의 다른 글

[C++] Class 기본 함수  (1) 2022.06.02
[C++] 레퍼런스와 클래스  (0) 2022.05.30
[C] 스택 프레임과 호출 규약  (0) 2022.05.30
[C] 구조체 ( Structure )  (0) 2022.05.30
[C] 열거형 ( Enumeration )  (0) 2022.05.29

+ Recent posts