이 글을 쓰는 시점에서 대략 2년 정도 C#, C++로 프로그래밍 공부를 하였고 내가 객체 지향적으로 코딩을 하는 능력이 매우 부족하다는 것을 느끼게 되었다. 그래서 처음으로 돌아가 객체 지향의 기본적인 개념들을 다시 공부해 보려고 한다.
객체 지향 프로그래밍(Object Orient Programming, OOP)
객체 지향 프로그래밍이란 프로그램 구현에 필요한 객체들을 정의하고 그 객체들 간의 상호작용으로 프로그램을 만드는 것으로 "어떤 객체가 어떤 작업을 수행할 것인가"가 핵심이 된다.
객체(Object)
실생활 속에서의 객체는 눈에 보이는 물건, 사람, 논리, 사상, 철학 등 우리가 인지할 수 있는 모든 요소라고 말할 수 있다.
객체 지향 프로그래밍에서의 객체란 이런 실생활 속의 객체들의 특성을 함수와 변수로 나타내어 클래스로서 정의하고 클래스를 통해 만들어낸 실체(instance)라고 할 수 있다.
객체 지향 프로그래밍의 장점
- 유지보수의 용이함
객체들간의 상호작용으로 프로그래밍이 구현되기 때문에 객체 지향적으로 잘 만들어진 프로그램은 컴퓨터 부품을 교체하는 것처럼 프로그램을 변경할 때 모든 것을 바꾸지 않고 필요한 부분만 교체할 수 있어 유지보수가 용이하다.
- 코드의 재사용
하나의 클래스만 만들어 두어도 그 객체를 사용하는 여러 부분에서 이미 만들어둔 클래스를 사용하여 코드를 재사용할 수 있기 때문에 코드를 간결하게 줄일 수 있다.
- 인간 친화적
객체 지향 프로그래밍은 현실에서의 객체들끼리의 상호작용을 코드로 나타내는 것이기 때문에 인간 친화적이고 직관적이다.
이러한 객체 지향 프로그래밍의 장점은 객체 지향 프로그래밍의 4가지 특징 추상화, 캡슐화, 다형성, 상속에서 비롯되는 것이다.
객체 지향 프로그래밍의 4가지 특징
- 추상화
추상화란 간단하게 말해서 객체의 특성을 추출하는 작업이다.
스위치를 예로 들어본다면 "키다", "끄다" 라는 작업과 "켜져있는지 꺼져있는지"의 상태 3가지를 추상화를 통해 추출할 수 있다. 그리고 이것을 코드로서 정의해 본다면 "키다", "끄다"라는 작업은 On(), Off()라는 함수로, "켜져있는지 꺼져있는지"의 상태는 isOn이라는 Boolean변수 또는 SwicthType이라는 enum변수로 정의할 수 있다.
이렇게 추상화를 통해 만들어진 코드는 코드를 구현하지 않은 사람이 On()함수를 보며 "이건 스위치를 키는 작업을 하겠구나", Off()함수를 보며 "이건 스위치를 끄는 작업을 하겠구나"생각하며 함수의 구현을 굳이 알지 않아도 자연스럽게 코드를 사용할 수 있다. 이것을 통해 '추상화는 프로그램의 구현을 현실에서의 관점으로 인간이 직관적으로 이해하기 쉽게 구현하는 것'이라고 생각할 수 있다.
추상화의 특징이라고 할 수 있는것은 가독성이 좋고 재활용에 용이하다는 것이다.
추상화를 통해 만들어진 코드는 현실에서의 작용과 비슷하기 때문에 직관적으로 이해하기 쉬운 가독성 좋은 코드라 할 수 있다. 또한 객체의 특성을 기반으로 클래스를 정의하기 때문에 특정한 작업에서만 필요한 필드가 아닌 객체의 특성으로 필드가 구성되어 있어 객체의 특성을 필요로하는 곳 어디에서든 사용할 수 있기 때문에 재활용에 용이하다고 할 수 있다.
추상화에서 가장 중요한 것 중 하나를 작명이라고 할 수 있다. 추상화를 통해 만들어진 코드는 프로그램을 구현한 사람 외의 사람이 코드를 보더라도 직관적으로 이해할 수 있어야 하고 그 직관을 결정하는 것이 함수와 변수의 이름이기 때문이다. 극단적으로 스위치를 키는 함수의 이름을 Off()로 짓는다면 함수를 사용하는 사람은 "나는 스위치를 끄는 함수를 실했했는데 왜 스위치가 켜지지"하며 작업이 꼬일 수 있다. 프로그램을 만드는 작업은 기본적으로 여러 사람과 협업을 통해 진행되고 개인이라 하더라도 자신의 코드를 까먹는 경우가 대부분이기 때문에 위의 문제는 작업 진행에 있어서 큰 피해이가 될 것이다.
- 캡슐화
캡슐화는 클래스의 변수와 함수의 직접적인 노출을 줄이고 변수와 함수를 하나로 묶어 객체가 다른 객체의 의존 없이 독립적으로 존재할 수 있도록 하는 것이다.
public class Square()
{
public float Width;
public float Height;
public float Area;
public Square(float width, float height)
{
Width = width;
Height = height;
Area = Width * Height;
}
}
위와 같은 생성자를 통해 너비, 높이, 넓이를 설정할 수 이는 도형 클래스가 있다고 해보자
변수들의 접근제한자가public이기 때문에 언제든지 도형의 너비, 높이, 넓이에 접근할 수 있다.
이렇게 된다면 어떤 문제가 발생할 수 있을까
public void Main()
{
Sqaure square = new Square(2f, 3f);
//너비가 3이고 높이가 3이지만 넓이는 6
square.Width = 3f;
or
//너비가 2이고 높이가 4이지만 넓이는 8
square.Height = 4f;
or
//넓이가 음수인 문제 발생
square.Area = -1f;
}
위와 같이 도형의 변수에 쉽게 접근할 수 있기 때문에 도형의 정보가 옳바르지 않게 변경될 수 있다.
이러한 문제를 방지하기 위한 것이 캡슐화이다.
캡슐화를 적용하면 클래스를 이렇게 수정할 수 있다.
public class Square()
{
private float width;
private float height;
private float area;
public Square(float width, float height)
{
this.width = width;
this.height = height;
area = width * height;
}
public float GetWidth() => width;
public float GetHeight() => height;
public float GetArea() => area;
public void SetWidth(float width)
{
if(width < 0f)
return;
this.width = width;
area = width * height;
}
public void SetHeight(float height)
{
if(height < 0f)
return;
this.height = height;
area = width * height;
}
}
이렇게 클래스를 수정할 변수 자체는 private로 외부에 대한 접근을 제한하고 SetWidth, SetHeight함수를 통해 변수 하나를 수정하여도 Square객체 자체가 잘못된 작업에 대해 예외처리 작업을 하고 수정된 너비, 높이에 따라 넓이를 다시 설정하는 작업을 하여 Square객체가 외부의 영향 없이 옳바르게 존재할 수 있게 된다.
캡슐화에 대해 다시 말해보자면 객체의 속성에 대한 접근을 접근제한자로 제한하여 외부에서의 잘못된 작업을 방지하고
데이터와 작업을 하나로 묶어 객체가 독립적으로 존재할 수 있도록 하는 것 이라고 할 수 있다.
- 상속
상속은 기존의 클래스로 새로운 클래스를 정의하여 클래스 간의 관계를 만드는 것이다. 상속을 하는 클래스를 부모 클래스, 슈퍼 클래스라고 부르며 상속을 받는 클래스를 자식 클래스, 서브 클래스라고 부른다.
자식 클래스는 부모 클래스의 변수와 함수들이 자동으로 정의되며 접근 제한자에 따라 직접 접근할 수 있다.
상속을 사용하였을 때의 장점은 코드의 재활용과 유지 보수의 용이함, 다형성이다. 자식 클래스는 부모 클래스의 변수와 함수가 그대로 정의되기 때문에 클래스들의 공통되는 특징들을 부모 클래스로 정의하고 그것을 상속 받게 되면 똑같은 코드를 다시 작성하지 않을 수 있고 부모 클래스를 수정하는 것으로 자식 클래스들의 수정 작업을 하지 않을 수 있게 된다.
public class Human
{
public string Name;
public void Breath()
{
}
}
public class Man : Human
{
}
public class Woman: Human
{
}
Man과 Woman이라는 클래스가 Human이라는 클래스를 상속 받는 코드이다.
Man과 Woman클래스가 Human를 상속받았기 때문에 Name, Breath()를 코드로 작성하지 않아도 자동으로 정의되어 사용할 수 있게 된다.
객체 지향 프로그래밍의 특성 중 하나인 다형성의 대부분이 상속에서 발생한다.
- 다형성
다형성은 하나의 객체가 여러 타입으로 변할 수 있다는 것이다. 주로 상속을 통한다.
public class Human
{
}
public class Man : Human
{
}
public class Woman: Human
{
}
Human클래스가 있고 그것을 상속받는 Man, Woman클래스가 있다고 했을 때 Man, Woman클래스는 당연하게 Man, Woman클래스로 나타난다. 여기서 추가적으로 부모 클래스인 Human으로도 두 클래스를 나타낼 수 있는데 이것을 다형성이라고 한다.
다형성과 관련된 것으로 오버라이딩(overriding)과 오버로딩(overloading)이 있다.
오버라이딩은 자식 클래스가 자신에게 맞게 부모 클래스의 함수를 재정의 하는 것을 말한다.
부모 클래스의 작업을 실행하면서 추가적으로 자신의 작업을 실행하게 수정하거나 부모 클래스를 작업을 하지 않고 자신의 작업만 실행하게 재정의할 수 있다.
오버로딩은 하나의 함수를 여러 형태로 정의하는 것을 말한다.
오버로딩을 하기 위해서는 함수의 이름이 같아야 하며 매개변수가 달라야 한다. 오버로딩은 함수를 유연하게 사용할 수 있도록 한다고 할 수 있다.
'기타' 카테고리의 다른 글
[기타] 드로우콜, 배칭 (0) | 2024.10.28 |
---|---|
[기타] Compute Shader (0) | 2024.05.28 |
[기타] 객체 지향 SOLID 법칙 (0) | 2024.05.09 |