객체지향(OOP)과 절차적 프로그래밍(PP)
오늘은 프로그래밍에서 중요한 개념 중 하나인 객체지향 프로그래밍(Object Oriented Programming)과 절차적 프로그래밍(Procedure Programming)에 대해 알아보고자 합니다.
대개 객체지향 프로그래밍 언어를 처음 마주하고 학습하면서 점점 익숙하다 싶을 쯤에 몇 부분에서 장벽을 마주하게 되죠. 보통 '객체'라는 개념에 대해 처음 마주하면 많은 분들이 어려워합니다. 특히 자바의 경우 '객체지향 언어'라고 수없이 들었지만 왜 객체지향인지 모르고 배우는 경우가 다반사죠. 그러다가 '객체'라는 것을 배우기 시작하면 이제 멘탈이 나가기 시작합니다. 이런일이 발생할 수밖에 없는 것이 어떤 언어를 배우건 거의다 초기에는 절차적인 방식으로 코드를 짜고 배웁니다.
예로들어 대표적 객체지향 언어인 Java 언어를 예로들어보죠.
두 수를 입력받고 다음에 'a'를 입력받으면 덧셈을, 'b'를 입력받으면 뺄셈을, 'c'를 입력받으면 곱셈을 하여 출력하라. 라고 주어진다면 보통 다음과 같이 짤 겁니다.
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int first = in.nextInt();
int second = in.nextInt();
char type = in.next().charAt(0);
if(type == 'a') {
System.out.print(first + second);
}
if(type == 'b') {
System.out.print(first - second);
}
if(type == 'c') {
System.out.print(first * second);
}
}
}
여기서 객체지향 언어의 특징이라곤 찾아볼 순 없죠. 이런식의 짧은 코딩만 해왔기 때문에 객체를 배우기 시작하면 거기서부터 프로그래밍에 대해 흥미가 떨어진다거나 객체지향 언어하고 거리를 두게되는 일들이 많습니다. 그래서 이번 기회로 한 번 객체가 무엇인지 제대로 짚고 넘어가보고자 합니다.
- 객체와 객체지향 , 절차와 절차지향
먼저 객체지향과 절차지향에 대해 알아보기 전에 OO지향이란 단어에 대해서 짚고 갈 필요가 있습니다. 아마 여러분들 뿐만 아니라 거의 통용되는 말로 쓰이는 것이 있습니다.
절차지향 언어 : C언어
객체지향 언어 : Java, Python, C# 등등..
물론 아주 틀린말은 아닙니다. 다만 엄밀히 말하자면 어디까지나 '지향'이라는 것이고 하나의 프로그래밍 패러다임이지 C언어는 절차적으로만 프로그래밍한다. Java는 객체지향적으로 프로그래밍을 해야한다.가 아니라는 것이죠.
방금 위에서 코드를 보았듯이 필요한 경우 어떤 언어이건 상관없이 절차지향적으로 코딩할 수 있습니다. 반대로 C언어로도 객체지향적으로 코딩할 수는 있습니다. 유사 객체지향이랄까요.
그리고 여러분이 반드시 기억하셔야 할 것은 기본적으로 모든 코드는 '절차적인 틀'이 있습니다. 사실 절차지향이라는 말은 올바른 말이 아니고 절차적 프로그래밍이라고 하는데, 기본적으로 절차라는 틀을 깨지 않는 선에서 객체지향적 프로그래밍을 하느냐 마느냐의 차이라고 보는게 좀 더 올바른 관점이지 않을까 합니다.
그래서 절차지향 프로그래밍에 대해 검색하면 '절차지향'이 아닌 '절차적 프로그래밍'이라고 합니다. 사실 조금만 생각해보아도 프로그래밍의 기본 틀이 절차를 기반으로 두고 있는데 이 절차를 지향한다는 것도 웃기긴 하죠.
또한 '절차'에 대해 조금 오해가 있는게 Procedural 단어가 '절차상의'로 번역되는 건 맞지만, 내포하고 있는 의미는 사실 '함수'입니다. 이 것을 파고드는 것은 조금 내용이 깊어지니 일단은 넘어가도록 합시다.
정리하자면 OO지향이란 코딩하는 방식 또는 방법론의 차이이지 특정 언어가 특정지향만 지원한다는 것은 아니라는 것이죠.
또한 객체지향 프로그래밍의 반대 개념이 절차지향이라고 오해하는 분들이 많은데 절대 반대개념이 아닙니다. 어디까지나 프로그래밍 접근 방법이 조금 상이할 뿐 정반대 개념이 아니죠. 대개 절차적 프로그래밍은 '데이터를 중심으로 함수'를 만들어 쓰는편이고, 객체지향은 '데이터와 기능(함수)들을 묶어 하나의 객체'로 만들어 씁니다.
그렇기 때문에 정확한 표현으로 말하자면 '객체지향 프로그래밍(OOP : Object Oriented Programming)'과 절차적 프로그래밍 (PP : Procedure Programming)이라는 말이 더 정확합니다.
그러면 왜 C를 절차적 프로그래밍 언어, Java를 객체지향 프로그래밍 언어라고 부르는 것일까요? 이는 언어에서 지원하는 기능과 특징에 있습니다. 객체지향 언어와 절차적 언어를 구분하는 방법이야 많지만 대개 아래와 같은 기준아래 절차적 언어와 객체지향 언어가 나뉩니다.
1. 캡슐화, 다형성, 클래스 상속을 지원하는가?
2. 데이터 접근 제한을 걸 수 있는가?
보통은 위 기준을 만족하면 객체지향, 만족하지 않으면 절차적 성격이 강해집니다.
(물론 함수형 언어 등 그 외의 다른 패러다임들도 있습니다. 하지만 일단 가장 개괄적으로 여기에서는 객체지향과 절차적 프로그래밍에 대해 알아보기로 하겠습니다.)
요즘에는 객체지향적 프로그래밍이 대세인지라 상용 언어 중 대부분이 객체지향적입니다. 반면에 C는 그렇지 않죠. 이는 프로그래밍 언어의 역사를 보면 이해할 수 있을겁니다.
과거에는 지금과 같은 큰 규모의 하드웨어와 소프트웨어가 필요하지 않았습니다. 그래서 오래된 언어들인 C, 포트란, 코볼같은 언어들이 절차적 언어의 대표였죠. 하지만 점점 소프트웨어의 발전 속도가 빨라지면서 자연스레 코드도 복잡해지기 시작했습니다. 그렇다보니 복잡한 알고리즘을 짤 때 절차적 프로그래밍을 하면 순서도(흐름도)가 꼬이기 시작하면서 코딩한 코드가 사람이 읽으면서 동작을 이해할 수 없게 되는 일명 '스파게티 코드'가 되어버린다는 단점이 대두되었습니다.
이러한 문제를 극복하기 위한 대안으로 객체지향적 프로그래밍이 나온 것이죠. 그리고 이 대안은 현재까지도 대세를 유지하고 있습니다.
이렇게 언어의 패러다임이 변화하면서 앞서 말했던 절차적 프로그래밍 언어들도 객체지향의 특징들을 가져오기 시작합니다. 예로들어 C++가 있죠. C언어 기반으로 여기에 더해 상속, 캡슐화 등을 지원하게 됩니다. 또한 그 외의 언어들도 자체 업데이트를 통해 객체지향 프로그래밍의 특징들을 하나 둘씩 갖고오게 되죠.
다만 이러한 것 때문에 대표적으로 C++같은 경우 객체지향 언어라고 하는 사람들이 꽤나 있습니다. 하지만 방금전에 말했지만 하나의 패러다임일 뿐 객체지향적 특징을 지원한다고 하더라도 객체지향 언어라고는 하지 않습니다. C++ 같은 경우 객체지향보다는 멀티 패러다임 언어라고 하는 것이 더욱 올바를 겁니다.
아무래도 C를 계승해서 온 언어라 C의 패러다임도 포함되어 있어 코딩 스타일의 유사점이 많이 있습니다.
이렇게 각 언어별 지향점이 조금씩 상이하다보니 코딩하는 사람 또한 스타일이 굳어지게 됩니다. 특히 프로그래밍에 처음 발을 들여놓을 때 C언어를 먼저 배우고 C++를 배운 사람하고 Java언어를 먼저배우고 C++를 배운 사람하고 코딩 스타일의 차이가 확연하게 납니다. 또한 알고리즘을 짜기위한 문제 접근 방식도 차이가 조금씩은 있습니다.
그럼 절차적 프로그래밍과 객체지향 프로그래밍에 대해 알아보도록 하죠.
먼저 절차적 프로그래밍(Procedure Programming)입니다. 단어 그대로 '절차적'으로 코드를 구성한다는 것입니다. 쉽게 말하면 '흐름도(순서도)'라고 보시면 됩니다.
데이터에 대한 순서를 파악하고 필요한 기능을 함수로 만들어 절차적으로 진행시키는 방법입니다.
반면에 객체지향 프로그래밍(Object Oriented Programming)은 어떨까요? 객체지향 프로그래밍의 경우 기능들을 묶어 하나의 객체로 만든다고 했습니다. 아래 그림과 같은 형식이죠.
즉, 고객이 할 수 있는 행위(기능)들과 데이터들을 하나로 묶어 고객이라는 객체 만들고, 자판기에서 할 수 있는 행위들과 데이터들을 묶어 자판기라는 하나의 객체로 묶어서 푸는 겁니다.
그리고 각 객체의 메소드나 필드를 호출하면서 서로간의 상호작용을 통해 알고리즘을 구성하는 방식인 것이죠.
"잠깐. 객체가 뭐야?"
사실 우리가 객체 생성이니, 객체지향이니 프로그래밍에서 객체(Object)라는 말을 수없이 듣죠. 하지만 객체를 만들고 생성하는 방법, 즉 프로그래밍 언어로써의 객체 정의는 알지언정 '객체'라는 단어 그대로의 정의는 잘 모르고 갑니다. 그렇다보니 처음 객체지향 프로그래밍을 할 때 많은 사람들이 어려움을 겪죠.
사실 그도 그럴것이 프로그래밍의 역사 자체가 서양문화를 기반으로 탄생하고 발전해왔기 때문에 우리 입장에서는 받아들이고 이해하는데 어려움을 겪을 수밖에 없습니다. 객체라는 말을 우리가 평소에 쓰는 단어가 아니죠.
일단 객체에 대해 한 단어로 말하자면 '실체'라고 보면 됩니다. 잘 이해가 안되어도 괜찮습니다. 잠깐 17세기로 돌아가 철학 이야기를 해보도록 하죠.
17세기의 철학은 우리가 흔히 말하는 근대 철학의 시초가 되는 시점입니다. 이는 다시말해 철학이 태동하던 시대였는데, 한 가지 특징이라 하면 바로 자연과학의 등장이죠. 과거의 자연학은 '사물의 본질은 무엇인가'에 대한 의문에 대해 이를 설명하기 위한 그 자체의 형상 또는 본질을 규명하는 데에 집중해왔습니다. 하지만 17세기에 접어들면서 이러한 관점과는 달리 사물의 본질(성질)을 규명하는 것이 아닌 자연현상이 발생하는 법칙을 설명하고자 하는 움직임으로 바뀌게 됩니다.
조금 어렵게 말하면 사물의 본성이나 형상보다도 현상 상호의 관계를 문제로 한다는 것이죠. 이러한 관점은 여러분이 잘 아는 아이작 뉴턴, 갈릴레오 갈릴레이 등을 통한 물리학(역학)의 새로운 패러다임과 비약적 발전을 이루게 되죠. 과거에는 자연은 영적, 동적인 신의 부수적 역할이었다면 17세기 자연철학은 철학과 과학을 신학에서 벗어나 독립적인 학문으로서 자리를 잡기 시작했죠.
이러한 철학적 변화는 단순히 자연현상 뿐만 아니라 가치관 사고방식을 변화시키게 됩니다. 데카르트가 이성을 가진 인간을 신으로부터 독립시키게 되었죠. 여기서부터 '실체'에 대한 연구가 시작됩니다. 방금 인간을 신으로부터 독립시키게 되었다고 했죠? 즉, 우리가 객관적으로 인지할 수 있는 주체인 '나'는 신이 없어도 사고를 할 수 있다는 것이죠.
"나는 생각한다. 고로 존재한다" - 데카르트
이 말은 누구나 한 번쯤은 들어봤을겁니다. 앞서 말한 철학적 패러다임을 매우 함축적으로 보여주는 문장이죠.
그리고 주체에는 항상 객체(대상)가 붙어다니기 마련입니다. 간단하게 생각해보죠. 주체(나)가 밥을 먹는다는 행위를 한다면 밥을 먹히는 대상인 밥이라는 대상이 있어야 합니다. 이러한 대상을 객체라고 말하죠.
한마디로 주체는 실체인 내가 스스로를 가리키는 말이 되고, 객체는 주체가 사고하는 무언가가 되는 것이죠.
즉, 제가 여러분을 바라볼 때 제 스스로는 주체가 되고, 여러분은 객체가 되는 것입니다. 반대로 여러분들 입장에서는 여러분들 스스로가 주체가 되고 제가 객체가 되겠죠. 이제 조금은 감이 오시나요?
객체에 대해 한 문장으로 설명하자면 이렇습니다.
'인간 중심에서 객관적으로 인지할 수 있는 대상들이 객체(Object)다.'
이를 프로그래밍과 접목시켜본다면 앞서 봤던 객체지향 분석에서 왜 자판기와 고객을 분리시켰는지 이해할 수 있을겁니다. 어떤 동작들을 중심으로 절차에 따라 함수를 만들고 진행하는 방식이 아닌 동작의 주체가 누군지 분류하여 동일성을 갖는 기능들을 하나의 묶음으로 만들어 하나의 자판기라는 객체와 고객이라는 객체를 만드는 것이죠.
그러면 위의 예제인 고객이 음료수를 사는 과정을 간단하게 절차적 프로그래밍과 객체지향적 프로그래밍이 어떻게 다른지 한 번 보도록 하죠. 언어는 Java와 C++로 보여드리도록 하겠습니다.
먼저 Java부터 보여드리도록 하겠습니다.
[절차적 - Java]
절차적 프로그래밍은 아까 말했듯이 데이터 중심으로 함수를 만들고 순서에 따라 순차적으로 진행한다고 했습니다. 위 그림에 적혀있는 그대로 한 번 만들어보도록 하죠.
public class Main {
// 주스 잔여 개수
static int Orange_juice = 10;
static int Apple_juice = 20;
public static void main(String[] args) {
int customer_changes = 1000;
String customer_has = null;
// 오렌지 주스가 먹고싶군요
String want_juice = "Orange juice";
if(want_juice.equals("Orange juice")) {
if(Orange_possible(customer_changes)) {
int changes = getOrangeJuice();
System.out.println("오렌지 주스가 정상적으로 구매되었습니다");
customer_has = want_juice;
customer_changes -= changes;
}
else {
System.out.println("오렌지 주스를 구매하실 수 없습니다");
}
}
else if(want_juice.equals("Apple juilce")) {
if(Apple_possible(customer_changes)) {
int changes = getAppleJuice();
System.out.println("사과 주스가 정상적으로 구매되었습니다");
customer_has = want_juice;
customer_changes -= changes;
}
else {
System.out.println("사과 주스를 구매하실 수 없습니다");
}
} else {
System.out.println("없는 물품입니다");
}
System.out.println("잔액 : " + customer_changes + "\t갖고있는 음료 : " + customer_has);
}
// 오렌지주스 구매 가능?
static boolean Orange_possible(int pay) {
if (Orange_juice > 0) {
if (pay >= 500) {
return true;
}
}
return false;
}
// 오렌지 주스 꺼내기
static int getOrangeJuice() {
Orange_juice--;
return 500;
}
// 사과주스 구매 가능?
static boolean Apple_possible(int pay) {
if (Apple_juice > 0) {
if (pay >= 300) {
return true;
}
}
return false;
}
// 사과주스 꺼내기
static int getAppleJuice() {
Apple_juice--;
return 300;
}
}
이렇게 '필요에 의해 함수들을 만들고 순차적으로 진행하는 방식'을 절차적 프로그래밍이라고 합니다. 반면에 객체로 묶으면 어떻게 변하는지 보도록 하죠.
[객체지향 - Java]
public class Main {
public static void main(String[] args) {
Customer customer = new Customer(1000);
Vending_Machine vm = new Vending_Machine(10, 3);
// 오렌지 주스가 먹고싶군요
String want_juice = "Orange juice";
int pay = vm.buy(want_juice, customer.getChanges());
// 지불비용이 0원일 때 == 구매 실패시
if(pay == 0) {
customer.resetting_juice(pay, null);
}
else {
customer.resetting_juice(pay, want_juice);
}
System.out.println(customer);
}
}
// 고객
class Customer {
private int changes;
private String hasJuice = null;
public Customer(int changes) {
this.changes = changes;
}
public int getChanges() {
return changes;
}
public void setJuice(String hasJuice) {
this.hasJuice = hasJuice;
}
// 잔액 설정
public void resetting_juice(int changes , String hasJuice) {
this.changes -= changes;
this.hasJuice = hasJuice;
}
public String toString() {
return "잔액 : " + changes + "\t갖고있는 음료 : " + hasJuice;
}
}
// 자판기
class Vending_Machine {
// 자판기에 남아있는 주스 개수
private int Orange_juice; // 오렌지 주스 가격 : 500
private int Apple_juice; // 사과 주스 가격 : 300
public Vending_Machine(int Orange_juice, int Apple_juice) {
this.Orange_juice = Orange_juice;
this.Apple_juice = Apple_juice;
}
// 오렌지주스 판매가 가능한지 검사
private boolean Orange_possible(int pay) {
if (Orange_juice > 0) {
if (pay >= 500) {
return true;
}
}
return false;
}
// 사과주스 판매가 가능한지 검사
private boolean Apple_possible(int pay) {
if (Apple_juice > 0) {
if (pay >= 300) {
return true;
}
}
return false;
}
public int buy(String kind, int pay) {
if(kind.equals("Orange juice")) {
if(Orange_possible(pay)) {
Orange_juice--;
System.out.println("오렌지 주스가 정상적으로 구매되었습니다");
return 500;
}
System.out.println("오렌지 주스를 구매하실 수 없습니다");
return 0;
}
else if(kind.equals("Apple juice")) {
if(Apple_possible(pay)) {
Apple_juice--;
System.out.println("사과 주스가 정상적으로 구매되었습니다");
return 300;
}
System.out.println("사과 주스를 구매하실 수 없습니다");
return 0;
}
System.out.println("없는 물품입니다");
return 0;
}
}
차이점이 보이시나요? 각각의 객체에서 수행할 수 있는 함수들과 상태(필드)를 묶어서 하나의 클래스로 만들고 각각 객체를 만들어서 활용하죠. 자바 언어를 이해하진 못하더라도 구조상의 차이는 확실히 알 수 있을 것이라 봅니다.
이는 C++도 마찬가지 입니다. 혹여 C++에 익숙하신 분들을 위해서 준비해보았으니 참고하시길 바랍니다.
[절차적 - C++]
#include <iostream>
#include <string.h>
using namespace std;
static int Orange_juice = 10;
static int Apple_juice = 20;
// 오렌지주스 구매 가능?
int Orange_possible(int pay) {
if (Orange_juice > 0) {
if (pay >= 500) {
return 1;
}
}
return 0;
}
// 오렌지 주스 꺼내기
int getOrangeJuice() {
Orange_juice--;
return 500;
}
// 사과주스 구매 가능?
int Apple_possible(int pay) {
if (Apple_juice > 0) {
if (pay >= 300) {
return 1;
}
}
return 0;
}
// 사과 주스 꺼내기
int getAppleJuice() {
Apple_juice--;
return 300;
}
int main() {
int customer_changes = 1000;
char *customer_has;
char want_juice[] = "Orange juice";
if(!strcmp(want_juice, "Orange juice")){
if(Orange_possible(customer_changes)){
int changes = getOrangeJuice();
cout << "오렌지 주스가 정상적으로 구매되었습니다" << endl;
customer_has = want_juice;
customer_changes -= changes;
}
else {
cout << "오렌지 주스를 구매하실 수 없습니다" << endl;
}
}
else if(!strcmp(want_juice, "Apple juice")){
if(Apple_possible(customer_changes)){
int changes = getAppleJuice();
cout << "사과 주스가 정상적으로 구매되었습니다" << endl;
customer_has = want_juice;
customer_changes -= changes;
}
else {
cout << "사과 주스를 구매하실 수 없습니다" << endl;
}
}
else {
cout << "없는 물품입니다" << endl;
}
cout << "잔액 : " << customer_changes << "\t갖고있는 음료 : " << customer_has << endl;
return 0;
}
아마 C++로 하시는 분들이거나 C언어를 배우고 C++로 넘어오시는 분들은 위와같은 방식이 매우 익숙하실 겁니다. C언어도 물론 struct라는 구조체가 있지만 대부분의 객체지향 프로그래밍 언어들의 특성인 오버로딩, 오버라이딩, 상속 등을 유연하게 사용할 수가 없어 객체 지향 언어라고 불리우진 않죠.
[객체지향 - C++]
#include <iostream>
#include <string.h>
using namespace std;
class Customer {
private:
int changes;
char* hasJuice = nullptr;
public:
Customer(int changes) {
this -> changes = changes;
}
int getChanges() {
return changes;
}
void setJuice(char* hasJuice) {
this -> hasJuice = hasJuice;
}
// 잔액 설정
void resetting_juice(int changes , char* hasJuice) {
this -> changes -= changes;
this -> hasJuice = hasJuice;
}
string toString() {
return "잔액 : " + to_string(changes)+ "\t갖고있는 음료 : " + hasJuice;
}
};
class Vending_Machine {
private:
// 자판기에 남아있는 주스 개수
int Orange_juice; // 오렌지 주스 가격 : 500
int Apple_juice; // 사과 주스 가격 : 300
public :
Vending_Machine(int Orange_juice, int Apple_juice) {
this->Orange_juice = Orange_juice;
this->Apple_juice = Apple_juice;
}
private:
// 오렌지주스 판매가 가능한지 검사
int Orange_possible(int pay) {
if (Orange_juice > 0) {
if (pay >= 500) {
return 1;
}
}
return 0;
}
// 사과주스 판매가 가능한지 검사
int Apple_possible(int pay) {
if (Apple_juice > 0) {
if (pay >= 300) {
return 1;
}
}
return 0;
}
public:
int buy(char* kind, int pay) {
if(!strcmp(kind, "Orange juice")) {
if(Orange_possible(pay)) {
Orange_juice--;
cout << "오렌지 주스가 정상적으로 구매되었습니다" << endl;
return 500;
}
cout << "오렌지 주스를 구매하실 수 없습니다" << endl;
return 0;
}
else if(!strcmp(kind, "Apple juice")) {
if(Apple_possible(pay)) {
Apple_juice--;
cout << "사과 주스가 정상적으로 구매되었습니다" << endl;
return 300;
}
cout << "사과 주스를 구매하실 수 없습니다" << endl;
return 0;
}
cout << "없는 물품입니다" << endl;
return 0;
}
};
int main(){
Customer customer(1000);
Vending_Machine vm(10, 3);
char want_juice[] = "Orange juice";
int pay = vm.buy(want_juice, customer.getChanges());
// 지불비용이 0원일 때 == 구매 실패시
if(pay == 0) {
customer.resetting_juice(pay, NULL);
}
else {
customer.resetting_juice(pay, want_juice);
}
cout << customer.toString() << endl;
return 0;
}
이렇게 C++로도 객체지향 프로그래밍을 할 수 있습니다.
누가 주체이고 주체가 어떤 행동을 하는지 판별하기 쉬울 겁니다.
- 객체지향 프로그래밍 vs 절차적 프로그래밍
그러면 이제 여러분들은 이러한 의문이 들 수 있습니다.
"그러면 어떠한 방식이 좀 더 좋다는 것이지?"
사실 여기에 정답은 절대 없습니다. 다만 한 가지 확실한 것은 현재 페러다임은 객체지향 프로그래밍이 대세이긴 합니다. 특히나 워낙 거대해진 프로그램상 절차적 프로그래밍을 한다면 자칫 스파게티 코드가 되기 쉽고 자연스레 유지보수 관점에서도 떨어지죠. 그럼에도 장점도 뚜렷하게 있습니다. 한 번 살펴보도록 하죠.
[절차적 프로그래밍 장점]
1. 객체나 클래스를 만들 필요 없이 바로 프로그램을 코딩할 수 있다.
2. 필요한 기능을 함수로 만들어 두기 때문에 같은 코드를 복사하지 않고 호출하여 사용할 수 있다.
3. 프로그램의 흐름을 쉽게 추적할 수 있다.
[절차적 프로그래밍 단점]
1. 각 코드가 매우 유기성이 높기 때문에 수정하기가 힘들다. (새로운 데이터나 기능을 추가하기가 어려움)
2. 프로그램 전체에서 코드를 재사용 할 수가 없어 프로젝트 개발 비용과 시간이 늘어날 수 있다.
3. 디버그(오류 검사)가 어렵다.
[객체지향 프로그래밍 장점]
1. 모듈화, 캡슐화로 인해 유지보수에 용이하다.
2. 객체지향적이기 때문에 현실 세계와 유사성에 의해 코드를 이해하기 쉽게 만든다.
3. 객체는 그 자체가 하나의 프로그램이기 때문에 다른 프로그램에서 재사용이 가능하다.
[객체지향 프로그래밍 단점]
1. 대부분의 객체 지향 프로그램은 속도가 상대적으로 느려지고 많은 양의 메모리를 사용하는 경향이 있다.
2. 현실 세계와 유사성에 의해 코드를 이해하기 쉽게 만드는 만큰 설계 과정에 시간이 많이 투자된다..
보통의 경우 절차적으로 코딩할 때에는 대개 프로젝트 규모가 엄청 크지 않고 재사용할 일이 크지 않은 경우에 많이 쓰는 편입니다. 앞서 말했듯이 프로그램 자체가 가벼워지고 오히려 객체를 만드는 것보다 개발 시간이 확연히 줄어들기 때문이죠.
반대로 매우 큰 규모의 프로젝트라던가 코드를 재사용을 고려해야 할 때는 객체 지향 프로그래밍이 유용합니다. 대신에 초기 개발비용은 소모되더라도 유지보수 관점에서 매우 안정적이기 때문이죠.
그리고 앞서 보셨듯이 C++언어로도 절차적, 객체지향 프로그래밍 모두 가능한지라 특유의 C에서 넘어온 코딩 스타일과 Java나 Python같은 언어에서 넘어온 코딩스타일이 조금씩 다르게 나타납니다.
이렇게 오늘은 객체지향, 절차적 프로그래밍에 대해 알아보았습니다.
사실 두 개념이 상반되는 개념이 아니라는 것을 꼭 이해하고 가셨으면 합니다. 모든 언어는 절차적이고 거기에 더해 객체라는 기능을 추가한 언어들이 객체지향적 언어라고 불리는 것이죠.
그럼 이만 글을 끝맺도록 하겠습니다.
'프로그래밍 기초' 카테고리의 다른 글
메모리 구조 [Memory Structure] (84) | 2021.01.31 |
---|---|
2진수의 수와 음수 표현법 [1의 보수와 2의 보수] (73) | 2021.01.01 |
프로그래밍 언어와 빌드 과정 [Build Process] (22) | 2020.11.27 |
프로그래밍 언어의 단어와 문법 - 2 [프로그래밍] (4) | 2020.10.24 |
프로그래밍 언어의 단어와 문법 - 1 [프로그래밍] (17) | 2020.10.24 |