|
러스트로 객체 지향 프로그래밍을 다루는 방법을 설명합니다. |
들어가며
객체 지향 프로그래밍(Object Oriented Programming)은 ‘객체’라는 단위로 현실 세계를 모델링하는 방법론입니다. 객체 단위로 프로그램을 분리할 수 있기 때문에 유지 보수성이 높아지는 장점이 있습니다. 객체 지향의 특징은 캡슐화, 다형성, 상속 등이 있습니다. 러스트는 객체 지향 언어가 아니기에 이러한 특징들을 완벽히 지원하지는 못합니다. 하지만 러스트는 객체 지향의 핵심적인 개념을 트레잇과 같은 형태로 차용하여 러스트로도 충분히 객체 지향 프로그램을 작성할 수 있습니다.
캡슐화
캡슐화(encapsulation)는 객체의 내부 정보를 적절히 숨겨 외부에서 접근할 수 없도록 제어하는 것을 말합니다. 이는 객체와 상호작용하는 유일한 방법이 공개 API를 통하는 것을 의미하며, 코드는 객체의 내부에 직접 접근하여 데이터나 동작을 변경할 수 없습니다. 러스트는 pub 키워드를 사용하여 함수와 데이터를 캡슐화할 수 있습니다.
아래 예제는 pub 키워드를 사용하여 가시성을 적절히 제어하여 외부에 노출해야 할 부분과 그렇지 않은 부분을 분리하여 캡슐화를 달성하는 예제입니다. pub 키워드를 사용한 부분은 외부에 노출되고 그렇지 않은 부분은 내부로 은닉됩니다.
예제 1.1 캡슐화를 위해 pub 키워드를 사용하는 예제
가시성 제어
객체 지향 언어는 정보 은닉(information hiding)과 캡슐화(encapsulation)라는 개념을 제공합니다. 정보 은닉은 객체의 속성과 메서드를 외부로부터 보호하는 것을 말합니다. 은닉을 통해 객체의 속성이나 메서드에 직접 접근하지 못하도록 차단하여 개발자가 잘못된 조작을 하지 못하도록 합니다. 그래서 시스템의 안정성을 높일 수 있습니다.
러스트는 가시성(visibility)이라는 방법으로 객체 지향의 정보 은닉과 캡슐화를 지원합니다. 앞서 pub라는 키워드를 배웠습니다. pub는 모듈의 정보를 외부에 노출하는 기능을 제공합니다. 가시성은 모듈뿐만 아니라 함수와 구조체 등에도 적용이 가능합니다.
러스트의 pub 키워드에는 다양한 기능이 있습니다. 지금까지는 외부에 정보를 공개하거나 차단하는 방법으로만 사용했지만 pub 키워드에 정보 제한자 기능을 사용하여 대상을 한정할 수 있습니다.
예제 1.2 러스트의 정보 제한자
간단한 예제를 하나 살펴보겠습니다.
예제 1.3 가시성 예제
위와 같이 정보 제한자를 적절히 사용하여 가시성을 제한할 수 있습니다.
다형성
다형성(polymorphism)은 객체가 문맥에 따라 다른 자료형으로 형태를 취할 수 있게 하는 것을 말합니다. 러스트는 트레잇(trait) 키워드와 dyn 키워드를 사용하여 다형성을 제공합니다. 트레잇은 객체 지향의 인터페이스와 유사합니다. 트레잇은 함수를 추상화하여 트레잇을 구현하는 구조체들이 같은 이름의 API를 제공하도록 합니다. dyn 키워드는 컴파일러에게 트레잇의 구현체를 런타임에 찾아야 한다고 알려주는 키워드입니다.
아래 예제는 트레잇과 dyn 키워드를 사용하여 다형성을 확인하는 예제입니다. say_hello() 함수는 Hello 트레잇의 인스턴스를 파라미터로 받아 hello_msg라는 공통 인터페이스를 호출합니다.
그림 1.1 Hello와 Student의 관계
예제 1.4 공통 인터페이스
아래 예제는 Hello 트레잇을 구현한 예제입니다. 트레잇은 “impl 트레잇 이름 for 구조체 이름”의 형식으로 정의합니다. Student와 Teacher는 서로 다른 자료형이지만 Hello라는 동일한 이름으로 활용됩니다.
예제 1.5 Hello 트레잇의 구현체
상속
상속(inheritance)은 기존에 정의된 자료형을 기반으로 새로운 자료형을 만드는 것을 말합니다. 상속을 사용하면 기존 코드를 재사용하면서 수정이 필요한 부분만 재정의하여 사용할 수 있기 때문에 유지 보수성을 크게 높일 수 있습니다. 다만 상속이 너무 지나치면 상위 클래스와 하위 클래스 간의 결합도가 필요 이상으로 높아지는 문제가 있습니다.
애석하게도 러스트에서는 상속을 구현하기 쉽지 않습니다. 데코레이터나 프록시 패턴 등을 사용하여 상속과 유사하게 동작하도록 구현하는 방법이 현재로선 최선입니다. 아래 예제는 트레잇과 데코레이터 패턴을 사용하여 상속을 흉내 내는 예제입니다.
그림 1.2 러스트의 유사 상속
Pointable은 x와 y를 반환하는 함수가 선언되어 있습니다. 일종의 부모 클래스의 인터페이스 역할을 합니다. Point는 부모 클래스의 구현체와 같은 역할을 합니다.
예제 1.6 부모 클래스
ColorPoint는 Point를 확장한 하위 클래스처럼 동작합니다. 러스트는 상속을 제공하지 않기에 내부적으로 point 인스턴스를 가지고 있습니다. 그리고 부모 클래스의 함수를 호출하는 것처럼 만들기 위해 point 인스턴스의 함수를 호출합니다.
예제 1.7 하위 클래스
결론
러스트는 객체 지향 언어는 아니지만 객체 지향 언어가 가지는 다양한 특징들을 다양한 방법으로 구현할 수 있습니다. 그래서 객체 지향의 장점을 취하면서도 러스트만의 강점인 메모리 안정성을 내세워 여러분의 시스템을 견고하게 만들 수 있습니다.
객체 지향 언어가 제공하는 캡슐화, 상속, 다형성 등의 특징을 러스트에서도 구현 가능합니다. 예를 들어, 러스트에서는 Traits를 사용하여 상속을 구현하고, Trait Objects를 이용하여 다형성을 제공합니다. 또한 Rust의 모듈 시스템은 캡슐화를 제공하며, 안전한 타입 체크와 함께 객체와 유사한 구조를 사용할 수 있게 합니다.
따라서 러스트를 사용하면 객체 지향 언어의 장점과 러스트만의 강력한 메모리 안정성을 동시에 활용하여 시스템을 더욱 견고하게 만들 수 있습니다. 이는 시스템의 안정성과 신뢰성을 높이는 데 크게 기여하며, 개발자들이 더 나은 소프트웨어를 개발하는 데 도움이 됩니다.
이 포스팅이 러스트 개발자에게 많은 도움이 되길 바라며, 이만 줄이도록 하겠습니다. 이전 포스팅 ‘러스트로 크로스 플랫폼과 GUI 프로그래밍 시작하기’도 참조해 주시기를 바랍니다.
VD사업부 S/W Platform Lab의 김백기입니다.
감사합니다.
|
|
