안녕하세요!
객체 지향 프로그래밍에 대해 빡세게 알아야 하는 순간이 와버렸습니다.
하지만 걱정마시죠. 생각보다 쉽습니다.

👉이전 글 보러가기


객체 지향 프로그래밍의 특징부터 알아보자

객체 지향 프로그래밍을 하려고 마음을 먹었다면 알아야 할 객체 지향의 특징이 4개가 있습니다. 바로 캡슐화, 상속화, 다형성, 추상화입니다.

  • 캡슐화: 객체에 대한 모든 속성,메서드들을 묶어서 인터페이스로 만들고, 외부에선 그 인터페이스만을 갖다 쓰게 만듦. 객체 내부가 어떻게 구현되어 있는지 숨겨 외부의 영향 최소화
  • 상속화: 부모/자식 클래스라는 개념을 만들어서 자식 클래스가 부모 클래스의 속성과 메서드들을 물려받음. 이로 인해 코드의 중복을 줄여 유지보수 용이
  • 다형성: 하나의 인터페이스 내에서 다양한 다른 구현을 가진 객체들이 있을 수 있음. 이로 인해 유연한 코드 작성 가능
  • 추상화: 복잡한 현실 세계의 개념이나 사물을 단순화하여 필요한 속성과 행위만 추출하는 것

당장 무슨 말인지 모르겠고 알아보고 싶은 마음이 사라지신다구요? 아래에 차근차근 설명드리겠습니다~


객체?

객체는 Java에서 클래스로 만들 만한 것을 객체라 합니다. 그럼 어떤 것을 객체로 만들면 좋을까요?
우리가 변수는 어떨 때 만들어야 할 지 아실겁니다. 주로 숫자, 문자, 불리언 값들이 자주 쓰일 때, 이름을 지어서 갖다 쓰고 변경도 하고 더하고 빼고 그러잖아요? 객체 또한 비슷합니다.

객체는 자주 쓰이는 하나의 틀이라 생각하면 쉽습니다.


객체가 없는 삶…

출처 - 리그오브레전드 공식 사이트

자 우리는 이제 객체지향이란게 없는 세상으로 갔다고 생각해 봅시다. 그리고 한번 프로그램을 만들어봅시다.

리그 오브 레전드를 예시로 들어 볼까요?
리그 오브 레전드에는 지금 작성하고있는 2023년 3월 30일 기준으로 163명의 챔피언(플레이 가능 캐릭터)이 있습니다. 완전 많네요 ㄷㄷ

이제 챔피언들을 만들게 될거예요. 맨 처음에 가렌(리그오브레전드 챔피언 이름입니다)부터 만들어보자구요! 

우리가 가렌이란 챔피언을 만들기 위해선 해당 챔피언의 정보를 입력해 줘야겠죠? 음.. 챔피언의 능력치들이랑 스킬정도만 먼저 입력해봅시다.

출처 - 꺼무위키

일단 우리는 완벽하게 만들 건 아니지만 전부 1레벨 기준으로 싸운다고 생각하고 체력, 공격력, 방어력만 넣어서 만들어볼게요.

출력 결과

리그오브레전드 세상에서 가렌이 생겼습니다! 이제 스킬도 넣어줄까요? 스킬은 모든 리그오브레전드 챔피언이 동일하게 패시브, Q, W, E, R 스킬이 있습니다.

출처 - 리브레 위키

스킬의 메커니즘을 구현할 필요 까진 없을것 같고 저희는 스킬들을 사용할 때 가렌이 외치는 대사를 출력하도록 하죠. 속으로는 스킬을 쓴다고 생각해 주세요…ㅋㅋㅋ
그럼 가렌이 [WQ평타R평타평타] 순서로 스킬을 쓴다고 하죠. 

출력 결과

드디어 가렌을 우리가 사용할 수 있게 되었습니다!!! 아 아직이죠. 리그 오브 레전드에선 총 10명의 플레이어가 게임을 하고, 각 플레이어가 각자의 챔피언을 선택하며 게임이 시작됩니다. 
 
게임 매칭이 잡혀서 플레이어 1부터 10중 우리가 플레이어 1이 되었고, 가렌을 픽했다고 가정해봅시다.

출력 결과

아까 가렌의 출력과 같아졌죠? 이걸 상속이라고 부릅니다. 위에 객체지향 프로그래밍의 특징에 상속화가 있었죠? 물론 위 코드는 객체지향 프로그래밍이 아니었기 때문에 진정한 상속이라 부르기 어렵습니다.


문제점⚠️

제가 리그오브레전드를 만들기 시작할 때 했던 말이 있습니다.

리그 오브 레전드에는 지금 작성하고있는 2023년 3월 30일 기준으로 163명의 챔피언(플레이 가능 캐릭터)이 있습니다…

저희는 이제 겨우 가렌의 공격력, 방어력, 체력, 스킬들을 구현 완료했습니다.
리그오브레전드 세상에 163개의 챔피언을 다 추가하려면… 럭스의 lux_HP, lux_CP, lux_DEF, lux_Q(), lux_W() 구현하고… 또 다리우스, 또 신짜오, 그렇게 밀리오까지… 다~~~하면 코드가 장난아니게 길고 더럽겠죠?
거기에 플레이어 10명이 그 사이에서 자신의 챔피언의 데이터를 가져오려면 음… 너무 비효율적이예요.

이런 문제점을 해결하기 위한 것이 바로 객체지향 프로그래밍입니다. 제일 위에 제가 작성한 4개의 객체지향 특징으로 이 문제를 해결할 수 있어요.


인터페이스 만들기

이제 하나의 파일에서 구현하는것이 아니기 때문에 먼저 파일의 구조를 생각해봅시다. champion이란 폴더를 만들고 그 안에 Champion.java 인터페이스를 만들게요. 그리고 champion폴더 안에 여러 챔피언들의 객체도 같이 넣어보죠!

이런식으로..?

우리는 먼저 객체로 만들 녀석을 찾아야합니다. 프로그래머는 중복을 싫어합니다. 그래서 주로 중복으로 많이 나오는 값들의 집합을 객체로 지정합니다.

모든 챔피언의 공통점이 있습니다. 공격력, 방어력, 체력 그리고 4개의 스킬들을 가진다는 것이죠. 그럼 챔피언을 객체로 만드는게 좋아보이죠?

이렇게 객체로 만들 수 있는 녀석을 찾기 위해 공통된 속성들을 찾아내고 뽑아내는것을 우리는 추상화라고 합니다.

추상화를 해서 객체로 만들 녀석을 정했으나 일단 객체를 만들기 전에 먼저 인터페이스를 만들어봅시다!

인터페이스란 클래스들이 필수로 구현해야 하는 추상 자료형

이게 무슨소리일까요? 그냥 간단하게 객체가 구현해야 할 여러가지 변수나 함수들을 자세한 구현 없이 표면만 만든다는 뜻입니다. 예시를 볼까요?

class가 아닌 interface로 지정해야합니다!!!

보시면 뭔가 볼품없어보이죠? 이 인터페이스는 챔피언이라면 당연히 가지고 있어야 할 요소들을 미리 지정을 해놓는 것입니다. 그래서 실질적인 구현은 있지 않아요.
 
인터페이스에선 주로 변수를 지정할땐 모든 객체에서 변하지 않을 상수를 지정할 때만 사용합니다. 그래서 이렇게 스탯값을 가져올 때 함수 형식으로 int값을 return받아서 사용하게 됩니다.
 
이제 챔피언에 해당하는 각각의 객체에 구현을 할 것입니다. 어서 가렌 객체를 만들러 가봅시다!!


객체를 드디어 만들자!

드디어 객체를 만들 시간입니다!!!
아까와 같이 가렌을 구현해 보겠습니다. 우리는 이제 가렌 Class를 만들어서 가렌을 마음껏 불러올 수 있게 될 것입니다. champion 폴더에 Garen.java를 같이 만들어봅시다.

아까와 같은 정보를 저장했지만, 함수명에 굳이 garen_Q와 같이 챔피언 이름을 적어서 구분을 하지 않았습니다.
그 이유는 이제 각각의 챔피언들이 다 객체이다보니 챔피언마다 각각의 HP, CP등등이 있는 구성이라 함수 이름으로 어떤 챔피언의 체력인지 구분하지 않아도 된 것입니다.
 
이제 챔피언을 추가하는게 간단해졌는데 다리우스도 만들어볼까요?

간단하죠?

이렇게 하나의 인터페이스 내에서 구현한 내용만 다르고 형태는 인터페이스와 같은 객체가 여러 개 있을 수 있는것이 바로 객체지향 프로그래밍의 특징중 다형성입니다.


부모와 자식

그런데 갑자기 나온 @Override가 궁금하실겁니다. 이건 해당 함수가 부모 클래스의 함수를 재정의한다는 뜻인데요. 이것이 상속화입니다!
부모는 자식에게 많은 것을 상속해 주잖아요?

지금 Champion.java 인터페이스를 부모라고 생각해 봅시다.
이 부모는 스탯들 그리고 QWER 스킬들을 맨 처음 갖고 있었어요. 그리고 Garen.java 객체가 생기면서 Champion.java 안에 있는 스탯들과 스킬들을 다 물려받았어요. Garen은 거기서 가렌 챔피언에 맞게 구현만 했을 뿐인거죠.

그럼 챔피언 인터페이스는 부모, 가렌 객체는 자식이 된겁니다. 여기서 추가적으로 생각해볼수 있는것은 다리우스 또한 챔피언의 자식이겠죠? 그럼 이런 구도가 그려지게 됩니다.

결론적으로 상속화는 자식이 부모의 요소들을 물려받는것이라고 생각하시면 됩니다.


객체 사용하기

좋아요. 저희는 객체를 잘 만들었어요. 근데 이걸 어떻게 쓰는지 막막하네요… 가렌과 다리우스를 리그오브레전드 세상으로 발 디딜 수 있게 만들어보자구요.
 
먼저! 저희가 이전에 구현했던 LeagueOfLegend는 싹 다 없새고 새로 시작합시다.

잘가…

자자 이제 player1을 만들고 그 친구를 가렌으로 만들어보자구요!

참 그런데.. 자료형을 뭘로 지정할까요? 해당 플레이어를 가렌이나 다리우스같은 챔피언으로 지정할건데 String이나 Int같은걸로 지정할 순 없잖아요?

그.래.서 우리는 클래스 자체를 자료형으로 사용할겁니다. player1을 가렌으로 만들어볼게요!

위와 같이 변수를 생성할 때 우리가 만든 Garen 클래스를 사용하는 변수로 만들고 싶다면 new라는 녀석을 쓴 후 Garen()으로 클래스를 불러와서 player1에 넣어주면 되는겁니다. 자료형은 똑같이 Garen이 되는것이구요.
 
그럼 정말로 player1은 가렌이 되었을까요? 한번 확인해보겠습니다.

”.”을 찍게 되면 해당 변수가 사용할 수 있는 메서드나 요소들이 다 나오게 됩니다. 놀랍게도 저희가 위에서 만들었던 스탯과 스킬함수들이 전부 들어가 있어요! 한번 다 사용해보죠.

출력 결과

결과가 아예 똑같네요? 메인 함수가 아주 간결해졌습니다.


객체 변경하기

음.. 그런데 아직 객체지향의 장점이 와닫지 않으시다구요? 그럼 조건 하나를 추가해볼게요. 저 플레이어1을 갑자기 다리우스로 바꾸는겁니다. 변수들 보면 값을 원할 때마다 바꾸던데 player1이라고 못할게 있겠어요? 한번 해보죠.

⚠️⚠️⚠️⚠️⚠️⚠️⚠️

빨간줄이 떠버리네요… 생각해보면 int형 변수라면 int에 포함되는 1,2,3,4,5 등의 숫자들 끼리에서만 바꿀 수 있는데 player1은 Garen형 변수이기에 Garen 자료형이 포함하는 Garen()객체로만 선언할 수 있습니다.ㅠㅠ
 
그럼 바꿀 방법은 없는걸까요? 아니죠! Garen객체와 Darius객체 둘 다를 포함하는 자료형으로 선언하면 됩니다. 바로 그 둘의 부모 Champion 인터페이스죠! 한번 해볼까요?

👍👍👍👍👍👍

빨간줄이 사라졌습니다!! 그럼 해당 줄 말곤 아무 코드도 수정하지 않고 그대로 바로 프로그램을 실행해보겠습니다!

출력 결과

변경한 것이라곤 player1을 Garen()에서 Darius()로 바꾼 것 밖에 없는데 main함수의 모든 결과가 다리우스 객체값으로 바뀌었습니다.
 
객체 지향을 하지 않았다면????

여기 있는 player1의 스탯들을 하나하나 garen의 변수에서 darius의 변수로 바꿔줘야 했을겁니다. 혹시나 바꿔야할게 100개가 있다면…?ㄷㄷㄷ 끔찍하죠
 
이를 위해 우리는 인터페이스를 만든것입니다. 인터페이스의 자식 클래스들 안에선 자유롭게 변경할 수 있거든요!

이렇게 외부에서 객체들을 가져다가 변수로 지정할 때, 인터페이스만을 가져다 써서 사용성을 극대화하는 것을 객체 지향 프로그래밍 특성에서 캡슐화라고 부릅니다.


객체의 재활용

환경에 대한 관심이 높아지면서 리사이클링의 관심도가 높아진 요즘. 코드 또한 재활용할 수 있게 되었습니다.

장난입니다…

player2가 나타났습니다. 근데 얘도 다리우스 원챔충이라네요? 그럼 하게 해줘야죠.
이제 우리는 챔피언들을 객체로 만들었기에 두렵지 않습니다. player2한테 다리우스의 정보를 또 입력해주지 않아도 되거든요. 우리는 다시 Darius 객체만 불러오면 됩니다.

player2는 player1과 다르게 Q평타W평타R평타평타 콤보를 할거라 해서 이에 맞게 코드를 추가했습니다.
결과를 보겠습니다.

출력 결과

스탯값, 스킬 시전 대사는 플레이어1과 플레이어2가 완전 같습니다. 그렇지만 두 플레이어의 스킬 콤보는 달랐는데요.
이렇게 똑같은 객체를 여러 변수가 불러와서 쓰는 것이 가능하고, 각 변수들이 객체를 사용하는 것에 따라 다양한 결과값이 나올 수 있습니다.


마치며

이렇게 우리는 객체 지향 프로그래밍의 특징인 추상화, 상속화, 다형성, 캡슐화를 알아보았습니다.
결론적으로 객체 지향 프로그래밍을 해야하는 이유는 위 특징들을 사용하면서 오는 장점들을 누릴 수 있다는 것입니다.
 
처음에 볼땐 어려운 정의들이라 생각되어도 알고 보면 다 저희 개발자들이 편하라고 만들어진 개념들입니다.ㅎㅎ
 
이 객체 지향 프로그래밍을 하기 좋은 언어가 대표적으로 JAVA이고, 그러다보니 Spring은 객체 지향 프로그래밍을 하기 위해 우리를 많이 도와주는 프레임워크로 되어있습니다.
 
앞으로 Spring 공부를 진행하면서 Spring이 제공하는 기능들을 써 볼텐데, 객체 지향의 개념을 이해하셨다면 “아 이게 객체 지향의 ~~를 도와주기 위한 기능이구나”라고 생각되시면서 공부에 더 도움이 될 것이라 생각됩니다.
 
해당 글은 아마 JAVA 게시글이 많아지면 JAVA쪽으로 옮기지 않을까 예상되네요.
 
그럼 지금까지 제 글을 읽어주셔서!!

👉다음 글 보러가기