프로그래밍 언어의 추상화
프로그램은 실세계의 대상을 컴퓨터에 나타내어 문제를 해결하기 위한 것이기에 반드시 추상화 과정이 필요하다. 지금부터 추상화가 무엇인지에 대해서 알아보도록 하겠다.
추상화 (Abstraction)
추상화는 복잡한 대상을 간략하게 나타내는 것을 말한다. 추상화는 코드를 더욱 간결하게 작성하고 이해하기 쉽게 만들어주어 개발자가 더욱 효과적으로 프로그램을 관리할 수 있도록 도와준다 추상화는 대상의 관심있는 부분만 추려내는 방법과 대상의 관심 없는 부분을 삭제하는 방법을 통하여 이루어진다. 프로그래밍 언어에서 제공하는 추상화 종류는 다음과 같다.
- 제어 추상화(Control Abstraction): 현실에서 복잡한 제어 과정을 하나 혹은 여러 개의 간결한 이름으로 나타내는 과정이다. 주로 서브프로그램 개념을 활용하여 추상화를 진행한다. 제어 추상화는 수행되는 과정(How)은 숨기고 수행 대상과 결과(What)를 나타냄으로 달성 가능하다.
- 자료 추상화(Data Abstraction): 다양하고 복잡한 자료구조를 단순하게 나타내는 방법이다. 추상 자료형 개념을 도입하여 추상화를 진행한다. 자료 표현과 더불어 해당 자료에 관련된 연산을 묶어서 나타낸다.
캡슐화와 정보은닉 (Encapsulation, Information Hiding)
추상화 과정에서 "캡슐화"와 "정보 은닉"은 매우 중요하다. 이 두 단어는 엄밀히 따지면 의미가 다르다. 의미가 미세하게 다름에도 두 기능 사이에는 밀접한 관계가 있기에 흔히 같은 단어로 사용된다.
- 캡슐화(Encapsulation): 여러 요소를 하나의 단위로 묶을 수 있는 기능을 말한다. 대표적으로 C의 구조체(struct), 공용체(union) 등이 캡슐화를 지원하는 기능이다.
- 정보 은닉(Information Hiding): 구현 세부 사항을 외부에 숨기고 인터페이스만 외부에 공개하는 기능을 말한다. 대표적으로 C++의 클래스 내에서 사용되는 전용 멤버(private), 보호 멤버(protected) 등이 정보 은닉을 지원하는 기능이다.
추상 자료형 (ADT: Abstract Data Structure)
추상 자료형이란 자료 집합과 적용 가능한 연산을 함께 선언한 자료형이다. 추상 자료형의 구현 세부 사항은 캡슐화를 통해 외부에 공개되지 않아야 한다. 따라서 추상 자료형은 캡슐화 및 정보 은닉 원칙에 따라 설계되고 구현되어야 한다. 추상 자료형의 특징은 다음과 같다. 다음의 특성들은 모두 프로그램의 유지보수에 있어 매우 중요하다.
- 수정 용이성(Modifiability): 자료형을 사용하는 부분을 바꾸지 않고 구현 코드를 바꿀 수 있다.
- 재사용성(Reusability): 여러 상황에서 같은 코드를 재사용할 수 있다.
- 보안성(Security): 구현 세부 사항을 프로그램의 다른 곳에서 바꾸지 못하도록 보호한다.
객체지향 프로그래밍 (Objected Oriented Programming)
객체지향 개념은 소프트웨어 분야에 아주 중요한 원칙 중 하나로, 추상 자료형의 구현에 매우 효과적이다. 현실 세계의 개념을 추상화한 객체를 기반으로 프로그램을 구축하는 개발 방법이다.
객체와 클래스 (Object, Class)
객체(Object)란 특정 상태(State)를 유지하면서 외부 요구에 반응하는 행동(Behavior)을 보이는 대상이다. 프로그래밍에서는 이러한 대상을 컴퓨터에 추상화시킨 것을 객체라고 한다. 먼저 객체에서 사용되는 개념에 대해서 정리하겠다.
- 속성(Attribute): 객체의 상태를 정의하는 값을 말한다.
- 필드(Field): 객체 내의 속성을 저장하고 있는 이름을 말한다.
- 메소드(Method): 객체가 수행하는 동작 또는 기능을 말한다. 객체에 어떤 요청을 했을 때 그 요청을 처리하는 서브프로그램을 말한다.
- 메시지(Message): 객체 간 상호작용에서 한 객체가 다른 객체에게 보내는 요청이나 명령을 말한다. 메소드 호출을 통하여 이루어진다.
클래스(Class)란 객체를 생성하기 위한 일종의 틀(Template)이다. 클래스를 통해 생성된 객체를 해당 클래스의 인스턴스(Instance)라고 한다. 클래스는 상속(Inheritance)을 통하여 다른 클래스의 특성과 메소드를 이어받을 수 있으며 계층적인 구조를 구성할 수 있다. 클래스의 종류로는 다음이 있다.
- 슈퍼 클래스(Super Class): 부모 클래스, 기본 클래스라고도 불리며, 상속 관계에서 상위에 위치한 클래스를 말한다.
- 추상 클래스(Abstract Class): 객체를 생성할 수 없으며 하위 클래스에서 추상 메소드를 구현하여 사용할 수 있다.
- 구상 클래스(Concrete Class): 객체를 직접 생성할 수 있으며 모든 메소드가 구현된 클래스이다; 다른 클래스에서 상속받거나 인스턴스를 생성하여 사용할 수 있다.
다형성 (Polymorphism)
다형성이란 여러 타입의 데이터를 같은 이름으로 처리할 수 있는 특성을 말한다. 여러 타입을 다룰 수 있는 기능인 다형성은 다양한 수준에서 발생할 수 있는데, 주로 함수 수준이나 타입 수준에서 발생한다. 다형성 지원 수준에 따라 다형성 종류를 분류하면 다음과 같다.
- 다형 서브프로그램(Polymorphic Subprogram): 여러 타입을 다룰 수 있는 서브프로그램
- 다형 타입(Polymorphic Type): 타입을 인수로 받는 타입
다형성의 종류 (Types of Polymorphism)
결국 다형성이 필요한 이유는 여러 타입에 대하여 유사한 처리를 하기 위함이다. 서브프로그램의 다형성 종류를 나열하면 다음과 같다.
- 경험적 다형성(Ad Hoc Polymorphism): 실제로 다른 서브프로그램에 같은 이름을 붙인 형태의 다형성으로, 오버로딩(Overloading), 연산자 오버로딩(Operator Overloading)이 여기에 해당된다. 다른 서브프로그램에 같은 이름을 붙이는 것은 공통적인 의미를 가지기 때문이다.
- 매개변수적 다형성(Parameteric Polymorphism): 실제로 타입을 매개변수로 전달받는 다형성이다. C++의 템플릿(Template), Java의 제네릭(Generic)이 여기에 해당된다. 매개변수적 다형성을 이용하여 구현된 서브프로그램의 코드는 타입만 다를 뿐 같은 코드이다.
- 서브타입 다형성(Subtype Polymorphism): 타입 사이의 상속 관계에 의해 결정되는 다형성으로 순수 다형성(Pure Polymorphism)이라고도 한다. 상속(Inheritance)과 오버라이딩(Overriding)이 여기에 해당된다. 하위 클래스가 상위 클래스의 인터페이스를 구현하거나 메소드를 재정의함으로 이루어진다.
인터페이스와 트레잇(Interface, Trait)
인터페이스와 트레잇은 추상 클래스의 개념을 확장한 개념들이다.
- 인터페이스(Interface): 추상 메소드 집합으로만 구성된 타입을 말한다. 인터페이스에는 추상 메소드만 정의되어 있기에 구체적인 메소드 구현은 구상 클래스에 의해 구현되어야 한다.
- 트레잇(Trait): 인터페이스와 매우 유사하나, 인터페이스와 달리 메소드가 항상 추상 메소드이지 않고 일부 메소드는 구현되어 있을 수 있다.
인터페이스와 트레잇 모두 상속 관계를 강제하지 않는다. 상속 관계에 묶여 있지 않기에 다른 메소드를 자유롭게 구현 가능하며, 몇 개의 메소드를 가정하기에 타입처럼 취급할 수 있다. 따라서 인터페이스나 트레잇의 객체를 인수로 받을 경우 해당 메소드에서는 자유롭게 인터페이스나 트레잇에 선언된 메소드를 사용할 수 있다.