검수요청.png검수요청.png

객체지향

위키원
qkfkrpf98 (토론 | 기여)님의 2021년 8월 5일 (목) 15:59 판
이동: 둘러보기, 검색

객체지향(Object Oriented)은 프로그램 구현에 필요한 객체를 파악하고 각각의 객체들의 역할이 무엇인지를 정의하여 객체들 간의 상호작용을 통해 프로그램을 만드는 것을 말한다. 우리가 실생활에서 쓰는 모든 것을 객체(Object)라고 한다. 객체는 클래스(class)라는 틀에서 생겨난 인스턴스(instance)이다. 따라서 객체지향 프로그래밍은 객체와 객체 간의 연결로 되어 있으며 각각의 객체 안에 자료구조알고리즘이 들어 있는 것이다.[1]

개요

객체 지향은 실제 세계를 모델링 하여 소프트웨어를 개발하는 방법으로서, 객체 지향 프로그래밍에서는 데이터와 절차를 하나의 덩어리로 묶어서 생각한다. 이는 마치 컴퓨터 부품을 하나씩 사다가 컴퓨터를 조립하는 것과 같은 방법이다. 여기서 객체(object)란 보고 만질 수 있는 것, 지성적으로 이해할 수 있는 것, 생각이 나 행동이 추구하는 바를 말한다. 또는 문제 영역에서 잘 정의된 역할을 갖고 있는 각각에 대해서 구별할 수 있는 품목(item), 단위(unit), 개체(entity)라 정의하기도 하며 단순히, 정의된 경계를 갖고 구별되는 어떤 것이라 말할 수도 있다. 이 방법은 오늘날 자바(java), C# 등의 프로그래밍 언어(programming language)들을 지배하고 있는 가장 중요한 맥박이라고 할 수 있다. 객체지향의 캡슐화, 상속, 다형성을 통해 여러 개의 객체 단위로 나누어 작업할 수 있기 때문에 개발자와 협업해 규모가 큰 프로젝트도 무리 없이 진행할 수 있으며 유지 보수도 뛰어나다는 장점이 있다. 하지만 코딩 난이도가 상승하며 객체에 대한 정확한 이해가 필요하여 설계 단계부터 많은 시간이 소요된다.[2][3][4][5]

역사

등장 배경

초기 프로그래밍 방식은 절차적 프로그래밍(Procedure Programming) 방식으로 명시된 순서대로 처리한 다음 결과를 도출하는 방식이었다. 하지만 이 방식은 조금만 복잡해지면 순서도로 나타내는 것이 불가능할 정도로 꼬인 '스파게티 코드'를 만들게 되는데 명령어 양이 증가함에 따라 중복 코드 대처가 힘들고, 특정 코드가 어디까지 영향을 미치는지 알 수 없기에 유지 보수가 굉장히 어려웠다. 이러한 문제를 해결하기 위해 에츠허르 데이크스트라(Dijkstra)는 프로그램을 함수(procedure) 단위로 나누고 프로시저(Procedure)끼리 호출을 하는 구조적 프로그래밍(structured programming) 방식을 제안하면서 이러한 위기를 벗어나게 된다. 하지만 함수는 데이터의 처리 방법을 구조화했을 뿐, 데이터 자체는 구조화하지 못했다. 그로 인하여 네임스페이스(Namespace) 포화 문제를 낳게 되며 엉뚱한 데이터가 엉뚱한 함수에 전달돼서 데이터를 오염시키는 문제가 발생하고 그런 가능성 때문에 프로그래머가 한 함수의 작동에 영향을 받는 변수를 조사해야 할 때 모든 변수를 다 조사해야 하는 어려움에 봉착했다. 또한, 만약 프로그램의 크기가 증가한다면 수많은 변수가 생기며 함수가 접근할 수 있는 데이터의 범위에 명시적인 제한을 걸어야 하는 상황이었다. 이를 극복하기 위한 대안으로 객체 지향 언어의 시초인 1960년 노위지안 컴퓨터링 센터조한 달크리스틴이 발표한 시뮬라67이다.[6][7][8]

  • 네임스페이스: 개체(entity)를 구분할 수 있는 범위를 나타내는 말로 일반적으로 하나의 이름 공간에서는 하나의 이름이 단 하나의 개체만을 가리키게 된다.[9]

발전

객체 지향 언어는 당시에 기존 절차적 프로그래밍과 매우 이질적이고, 컴퓨터 처리 능력이 별로 좋지 않아서 큰 주목을 받지 못하였지만 향후에 프로그래밍 언어가 많은 지원을 받으면서 스몰토크, 에이다 같은 프로그램이 등장하며 객체 지향에 대한 연구가 활발하게 진행되었다. C++, 델파이, FoxPro 와 같은 프로그램들은 객체 지향 언어에 가장 큰 영향을 미쳤던 GUI의 발전에 따라 점점 향상되었다. 화면에 떠 있는 여러 개의 창은 각자의 실행 콘텍스트(context)를 가지는데 콘텍스트의 현재 상태(활성화, 비활성화, 최소화 등)에 따라 같은 명령에도 다른 결과를 내보내야 했으며 사용자 상호작용을 위해 이벤트 처리도 수행해야 했다. 특히 이벤트 처리는 비동기적인 속성 때문에 기존 절차적 프로그래밍에서는 일종의 횡단 관심사가 되어 버려 코드 전체에 이벤트 처리 코드가 흩어져 있게 되는 문제가 있었다. 그래서 객체지향 프로그래밍를 도입하여 이벤트를 받았을 때 수행되는 기능(이벤트 핸들러/콜백)을 구현할 수 있는 단일 인터페이스를 정의하고, 프로그래머들은 이를 필요한 형태로 알아서 구현하며, 특정 이벤트가 일어났을 때 실행되어야 하는 기능들을 등록한 다음, 운영체제나 응용프로그램이 실제로 해당 이벤트가 발생했을 때 해당 이벤트에 등록된 이벤트 핸들러/콜백을 주욱 실행하기만 하면 되는 구조가 본격적으로 확산되면서 객체지향 프로그래밍 또한 빠르게 확산되었다.[6][7][8]

지원 언어

구성 요소

객체

객체(Object)는 물리적으로 존재(실제 메모리상에 할당됨) 하고 추상적으로 생각할 수 있는 것 중에서 자신의 속성을 가지고 있고 다른 것과 식별이 가능한 것이다. 현실 세계의 개체를 객체로 설계하는 것을 객체 모델링(Object Modeling)이라고 하며, 객체 모델링은 현실 개체의 속성과 행동을 추상화하여 객체를 정의하는 과정이라 할 수 있다. [10][8]

클래스

클래스(Class)란 공통된 특성을 가진 객체를 추상화하고 집단화하여 나타내는 것이다. 객체 타입(Object Type)을 의미하며, 객체들이 갖는 객체의 변수(valiable) , 메소드(method) 의 집합이다.한 클래스를 기준으로 상위클래스를 슈퍼클래스(부모클래스)라고 하며, 하위 클래스를 서브 클래스(자식 클래스)라고 한다. 클래스로부터 생성된 새로운 객체를 인스턴스(Instance)이다.[8][11]

메소드

메소드(Method)는 객체 지향 시스템이 갖는 전통적인 시스템 함수 또는 프로시저에 해당하는 연산기능. 즉, 객체를 실행할 수 있도록 하는 연산의 집합이다.[8]

메세지

메세지(Message)는 객체들 간의 상호작용을 하는데 사용하는 수단이며 객체에 명령을 내리는 것이라고 할 수 있다.[8]

원칙

소프트웨어의 유지 보수나 확장이 쉽고, 유연하게 설계하기 위해 2000년 초에 로버트C. 마틴(Robert C. Martin)이 명명한 객체 지향 프로그래밍의 다섯 가지 기본 원칙을 마이클 C. 페더스 (Michael C. Feathers)가 그 원칙의 앞 글자들을 따서 'SOLID'라는 이름으로 소개했다.[12][13]

단일 책임의 원칙

단일 책임의 원칙(SRP, Single Responsibility Principle)은 하나의 클래스는 각 하나의 목적 즉, 하나의 기능만 가지는 의미이다. 해당 클래스에서 제공하는 모든 서비스는 단 하나의 책임을 수행하는 데 집중되어야 한다는 원칙이다. 이는 책임 영역이 명확해지고 책임 변경에 있어 다른 책임의 변경으로 인한 연쇄 작용을 최소화하여 코드의 가독성 및 유지 보수에 있어서 유리하게 된다.[12][14]

개방 폐쇄의 원칙

개방 폐쇄의 원칙 (OCP, Open Close Principle)은 소프트웨어의 모든 구성요소(컴포넌트, 클래스, 모듈, 함수)는 확장에는 열려있고, 변경에는 닫혀있어야 한다는 원칙이다. 즉, 요구 사항의 변경이나 추가사항의 발생에 기존 구성요소는 수정이 일어나지 말아야 하며 쉽게 확장이 가능하여 재사용할 수 있어야 한다는 원칙이다. 이는 재사용 코드를 만드는 기반이며 추상화와 다형성 객체지향의 장점을 극대화하는 중요한 원리가 된다.[12][14]

리스코브 치환의 원칙

리스코브 치환의 원칙(LSP, The Liskov Substitution)은 부모 클래스를 가리키는 포인터에 해당 클래스를 상속하는 자식 클래스를 할당하더라도 모든 기능이 정상적으로 작동해야 하며 자식 클래스의 상세 내부를 부모 클래스는 알 필요가 없다는 뜻이다. 부모 클래스와 자식 클래스의 서로 간의 영향을 최소화하여 자식 클래스는 언제나 자신의 부모 클래스를 대체하게끔 한다. 즉, 부모 클래스가 들어갈 자리에 자식 클래스를 넣어도 계획대로 잘 작동해야 한다는 것이다.[12][14]

인터페이스 분리의 원칙

인터페이스 분리의 원칙(ISP, Interface Segregation Principle)은 사용하지 않은 인터페이스의 구현을 하지 않고, 최소한의 인터페이스만을 사용해야 한다는 원칙이다. 인터페이스를 구체적이고 작은 단위들로 분리시켜 사용하게 끔하여 인터페이스 크기를 축소시켜 책임을 최소화하게 된다.[12][14]

의존성 역전의 원칙

의존성 역전의 원칙(DIP, Dependency Inversion Principle)은 클래스 사이에서의 의존관계가 존재하되, 구체적인 클래스에 의존하지 말고 추상화된 클래스에 의존하게 하는 원칙이다. 상위와 하위 객체는 모두 추상화에 의존해야 상위계층과 하위계층의 독립이 유지될 수 있다.[12][14]

특징

객체 지향의 특징으로는 크게 캡슐화, 정보 은닉, 추상화, 상속성, 다형성이 있으며, 이 중 구조적 기법과 차별되는 개념은 캡슐화, 상속성, 다형성이 있다. 추가적으로 동적 바인딩이 있다.[15]

캡슐화

캡슐화(Encapsulation)란 데이터(속성)와 데이터를 처리하는 함수로 외부에서 쉽게 접근하지 못하게 하는 것이 핵심이다. 객체에 직접적인 접근을 막고 외부에서 내부에 정보를 직접접근하여 변경할 수 없으며, 객체가 제공하는 필드와 메소드를 통해서만 접근이 가능해진다. 이는 유지 보수나 확장 시 오류의 범위를 최소화하고 객체 내 정보 손상, 오용 방지, 조작법이 바뀌어도 사용방법 자체는 바뀌지 않고, 데이터가 변경되어도 다른 객체에 영향을 주지 못하기 때문에 독립성이 좋다. 객체를 모듈화할 수 있어 이식성이 좋다.[16]

상속성

상속성(Inheritance)은 이미 정의된 상위 클래스(부모 클래스)의 모든 속성과 연산을 하위 클래스(자식 클래스)가 물려받는 것을 의미하므로 하위 클래스는 상위 클래스의 모든 속성과 연산을 자신의 클래스 내에서 다시 정의하지 않고서도 즉시 자신의 속성으로 사용할 수 있게 된다. 또한, 물려받은 속성과 연산 외에 새로운 속성과 연산을 추가하여 사용할 수 있다. 상위 클래스와 하위 클래스가 서로 공유할 수 있기에 객체와 클래스의 재사용이 증대되는 중요한 개념이다.[15]

  • 다중 상속(Multiple inheritance): 한 개의 클래스가 두 개 이상의 상위 클래스로부터 속성과 연산을 상속받는 것을 말한다.[15]

정보 은닉

정보 은닉(Information Hiding)은 캡슐화에서 가장 중요한 개념으로, 다른 객체에 자신의 정보를 숨기고 자신의 연산만을 통하여 접근을 허용하는 것이다.[15]

추상화

추상화(Abstraction)는 불필요한 부분을 생략하고 객체 속성 중 공통적이고 중요한 것에만 중점을 두어 개략화, 즉 모델화하는 것이다. 객체들의 공통적 특성을 파악하여 필요 없는 특성을 제거하는 과정을 가리킨다. 이 과정은 복잡한 문제를 해결하기 위한 가장 기본방법이며 완전한 시스템 구축을 하기 전에 시스템 구조 및 구성을 가시적으로 볼 수 있고, 그 시스템과 유사한 모델을 만들어 여러 가지 요인을 테스트할 수 있다.[15][17]

다형성

다형성(Polymorphism)은 메시지에 의해 개체(클래스)가 연산을 수행하게 될 때 하나의 메시지에 대해 각 객체가 가지고 있는 고유한 특성으로 다른 여러 형태로 재구성되는 것을 말한다. 자바의 오버로드(Overload) 또는 오버라이드(Override)이 다형성의 대표적인 예라 할 수 있고, 이것을 구현하는 걸 오버로딩(Overloading)과 오버라이딩(Overriding)이라고 한다.[17]

동적 바인딩

동적 바인딩(Dynamic binding)은 실행 시간 중에 일어나거나 실행 과정에서 변경될 수 있는 바인딩으로 컴파일 시간에 완료되어 변화하지 않는 정적 바인딩(Static binding) 과 대비되는 개념이다. 프로그램이 실행되어야 메모리에 크기가 얼마만큼 할당되는지 알 수 있게 되는 것을 의미하며 C의 경우 malloc(), calloc()을 이용한 것이 동적 바인딩이다.[8][18]

장단점

장점

  • 재사용 및 생산성: 남이 만든 클래스를 가져와 이용할 수 있고 상속을 통하여 확장 사용이 가능하다. 그 말인즉, 프로그래밍 코드의 재사용을 극대화하여 한 프로그램 내에서 하위 클레스들이 상위 클래스의 속성을 표현한 코드를 재사용하며, 새로운 프로그램 개발 시 기존 프로그램이 갖고 있는 클래스 상속 구조에서 많은 클래스들을 소프트웨어 IC로 재사용하여 생산성 또한 높일 수 있다.[19][20]
  • 유지 보수: 상속을 통한 수정, 추가가 용이하며 캡슐화로 그 함수의 세부정보가 은폐되어 있어 주변에 미치는 영향을 최소화한다. 독립성의 증대는 객체 지향 프로그래밍에서 수정해야 할 부분이 클래스 내부에 멤버 변수나 메서드로 존재하기 때문에 해당 부분만 수정할 수 있게 된다.[19][20]
  • 대형 프로젝트에 적합: 객체 지향 프로그래밍의 특성 덕분에 면밀한 자료분석, 개발 시간 단축, 좀 더 복잡한 코딩이 가능하고 클래스 단위로 모듈화를 시켜 개발할 수 있으므로 업무 분담이 쉬워 대형 프로젝트일수록 적합한 장점을 가지고 있다.[6][19]

단점

  • 복잡성: 다중 상속으로 인하여 클래스의 상속관계에 혼란을 야기한다면 코드의 난이도가 급상승할 수 있다. 이 상태를 상태는 '라자냐 코드'라고 불리는 편이다. 그래서 대다수의 객체 지향 프로그래밍 언어들은 다중 상속을 지원하지 않았고 실제 구현이 전혀 없는 껍데기인 인터페이스만 추가로 상속할 수 있게 했는데, 이 또한 코드의 재 사용성을 현저하게 떨어뜨리는 문제가 있어 최근엔 믹스인(mixin)이나 트레이트(trait) 같이 다중 상속을 할 수 있는 방법을 찾고 있다.[6]
  • 캡슐화와 격리 구조 설계로 인한 성능 하락: 거의 대부분의 객체지향 언어에서 기능을 묶으면 결국 함수 호출이 추가로 들어가거나 계산식 중간에 포인터 연산 등이 필요해지며, 멤버 함수 같은 경우 어느 객체의 함수인지 지정해야 하기 때문에 추가 포인터 크기와 연산 비용이 들어간다. 인라인 함수컴파일러 최적화(특히 RVO(Return Value Optimization)) 등의 방법으로 어느 정도는 격차를 줄여주나 역시 그냥 절차적 프로그래밍보다는 무거워지게 되어 느린 실행 속도를 가지게 된다. 또한 객체 하나하나를 따로 나누게 되는 것을 주력하다 보니 비슷한 처리를 하는 코드도 독립성에 의해 서로를 건드릴 수 없게 되었고 이를 해결하기 위해 'getter'(접근자: 값을 반환하는 메소드), 'setter'(설정자: 필드에 값을 저장하는 메소드)사용이 너무 많아졌다. 이 과정에서 캡슐화가 깨짐으로 정보 은닉 특성 또한 약해져 의미가 퇴색되었고, 다른 프로그래밍 패러다임이 필요해졌다.[6]
  • 성능 격차: 객체 하나하나를 따로 캡슐화시키고 상속시 부모만 같으면 자식의 종류를 신경 쓰지 않다 보니 각자의 메모리 크기가 달라지며, 결국 고정된 연속 메모리에 담을 수가 없게 된다. 메모리 할당을 배열로 하지 못하게 되니 따로따로 생성하게 되고 이렇게 각각의 객체의 생성과 파괴가 반복되면 메모리 단편화라는 문제가 생기게 된다. 가비지 컬렉션 기능이 만들어진 이유 중 하나이기도 하다. 또 연속 메모리를 쓰기 힘들어진다는 건 캐시의 효율적 사용에 큰 문제가 생긴다는 뜻이기도 해서 성능 격차는 더 벌어지게 된다.[6]

각주

  1. 이수호, 〈객체 지향〉, 《인코뎀》, 2020-10-21
  2. 객체지향 언어의 장점과 단점, 개념, 종류, 절차지향 언어와의 비교〉, 《티스토리》, 2020-10-28
  3. 객체지향〉, 《생활코딩》, 2014-04-21
  4. 재희 jaiyah, 〈객체지향 프로그래밍이란?〉, 《티스토리》
  5. Object Oriented〉, 《네이버 지식백과》
  6. 6.0 6.1 6.2 6.3 6.4 6.5 객체 지향 프로그래밍〉, 《나무위키》
  7. 7.0 7.1 DLGNDUD, 〈객체지향의 역사와 이해〉, 《세다트리스 인공지능연구소》, 2020-08-29
  8. 8.0 8.1 8.2 8.3 8.4 8.5 8.6 객체 지향 프로그래밍〉, 《위키백과》
  9. 이름공간〉, 《위키백과》
  10. 개발자를 꿈꾸는 프로그래머, 〈Java - (5) 객체란? 객체 지향 프로그래밍의 특징〉, 《티스토리》, 2016-05-04
  11. 현승, 〈객체 지향 기법의 구성 요소〉, 《네이버 블로그》, 2011-08-20
  12. 12.0 12.1 12.2 12.3 12.4 12.5 allocProc, 〈객체지향 5원칙 : SOLID〉, 《medium》, 2020-05-28
  13. 객체지향 개발 5대 원리: SOLID〉, 《넥스트리》, 2021-06-06
  14. 14.0 14.1 14.2 14.3 14.4 TonyChoi Ms_Tony, 〈객체지향의 3요소 5원칙〉, 《티스토리》, 2017-12-07
  15. 15.0 15.1 15.2 15.3 15.4 코딩팩토리 〈(C++) 객체지향 언어의 5가지 특징〉, 《티스토리》, 2019-03-01
  16. radait, 〈자바(Java) 캡슐화(Encapsulation)란? 무엇인가?〉, 《티스토리》, 2019-05-21
  17. 17.0 17.1 radait, 〈객체지향언어란? (특징, 장점, 단점, 종류)〉, 《티스토리》, 2019-05-20
  18. ammff, 〈(언어기초) 동적/정적 바인딩이란? (쉬움주의)〉, 《티스토리》, 2016-05-22
  19. 19.0 19.1 19.2 koyo, 〈객체 지향 프로그래밍이 뭔가요?〉, 《velog》, 2020-11-26
  20. 20.0 20.1 sesok808, 〈객체지향 언어의 개념 및 특징, 장단점〉, 《티스토리》, 2014-03-26

참고 자료

같이 보기


  검수요청.png검수요청.png 이 객체지향 문서는 프로그래밍에 관한 글로서 검토가 필요합니다. 위키 문서는 누구든지 자유롭게 편집할 수 있습니다. [편집]을 눌러 문서 내용을 검토·수정해 주세요.