객체 지향 프로그래밍 입문 완강

jihunnit·2023년 1월 2일
0

TIL

목록 보기
6/16
post-thumbnail

초보 웹 개발자를 위한 스프링5 프로그래밍 입문
DDD start 등의 좋은 책들의 저서이신
최범균님의 객체 지향 프로그래밍 입문 강의를 완강하였다.

원래는 디자인 패턴을 공부하고 있었으나, 디자인 패턴 전에 먼저
객체 지향의 개념에 대해 명확히 이해할 필요가 있다고 생각했기에
관련 책, 혹은 강의를 찾아보던 중이었는데

원래는 조영호님의 "오브젝트"를 읽으려고 했으나
마침 인프런 연말 맞이 30% 할인 기간이었기에
옳다구나, 하고 바로 구매하였다.
(물론 오브젝트도 나중에 읽어볼 계획이다.)

강의의 내용은 객체지향을 구성하는 다양한 요소들을 다룬느 것인데 크게

  • 캡슐화

  • 다형성과 추상화

  • 상속과 기능 재사용

  • 기능과 책임분리

  • 의존과 DI

  • DIP

로 구성되어 있다. 하나 하나 자세히는 아니더라도 간략하게
설명을 달아보자면

캡슐화

기능의 구현을 캡슐에 감싸서 외부에서 볼 수 없게 하는 것이다.
강의에서는 Tell, Don't Ask에 대해 말씀하시는데
가령 회원의 나이가 필요한 코드일 경우

if(member.getAge()>=20){ // 이것은 객체에게 나이를 묻는 것이다.
	return "adult";
}

가 아니라

if(member.isAdult(20){ // member 객체의 메서드를 통해 스스로 어른 여부를 말하게 함
	return "adult";
}

형태로 바꾸는 것이다.

이러한 캡슐화를 통해, 우리는 기능을 밖에서 사용하는 코드에 미치는 영향을 최소화하며 내부 기능 구현만을 변경할 수 있게 된다.

다형성과 추상화

에 대해 알아보고자 한다. 다형성은 객체 지향에서 가장 중요한 요소라고 대학교의 강의에서도 배우고 그랬다.
다형성(polymorphism) 은 여러 모습을 갖는 것을 의미하는데, 객체 지향에서는 이것을 한 객체가 여러 타입을 갖는 것을 의미한다. 클래스 상속 혹은 인터페이스 구현을 통해 다형성을 얻는다고 할 수 있다.

추상화는 데이터나 프로세스 등을 의미가 비슷한 개념이나 의미있는 표현으로 정의하는 과정이다.

예를 들자면, 운송 수단이라는 것에 대해 생각해보자.
운송 수단에는 다양한 것들이 있을 수 있다.
요즈음 있는 배민 라이더 같은 분들은 오토바이를 운송 수단으로 사용하고, 택배의 경우는 트럭을 운송 수단으로 사용하고, 해외에서 오는 물건의 경우는 배나 비행기를 운송 수단으로 사용한다.

이들은 다른 것들이지만, 뭔가를 옮겨준다는 점에서 공통점을 가지고 있고 이것을 가지고 추상화를 할 수 있을 것이다.
Transport interface를 만들고, 이를 구현하는 운송 수단들의 내부 구현을 달리 한다면 가능할 것이다.

그렇게 하면 우리는 이런 식으로 선언을 할 수 있을 것이다.

Transport tp = new truck();
tp.transfer(from, to, what);

이 내용에 대해 우리는 여튼 이 tp라는 객체가 실제로 뭔지, 이 객체의 실제 클래스에서는 transfer라는 메서드를 어떻게 구현하였는지는 궁금하지 않다. 우리는 여튼 이게 Transport interface를 구현한, 운송 수단이라는 것 자체만 중요하다.

이렇게 추상화를 통해, 기능의 구현을 감추고 의도를 명확하게 드러낼 수 있다. 또한 확장과 변경을 손쉽게 하여, 객체지향의 원칙 중 하나인 OCP(Open - Closed Principle)를 달성할 수 있다.

물론, 추상화는 실제로 변경, 확장의 가능성이 있을 때 고려해야지, 무작정 추상화를 남발하면 코드의 복잡성을 증가시킬 수 있다.

상속과 기능 재사용

이 부븐을 대학교의 객체 지향 프로그래밍 강의에서는 핵심처럼 다뤘기에 나는 이게 객체 지향에서 매우 매우 중요하고 지켜야 할 요소라고 생각했으나.. 강의를 들으니 아닌 것 같다.
상속을 통한 기능의 재사용은 장점이 맞으나, 상속 관계에서 상위 클래스의 변경이 하위 클래스에 미치는 영향이나 코드의 복잡성 증가 등 문제가 있기에, 상속을 잘 쓰는 것이 매우 중요하다고 할 수 있다.
이 강의에서는 상속보다는 조립(필드로 다른 객체를 참조하는 방식)을 통해 기능 사용 문제를 해결하라고 가르친다. 실제로 나도 알게 모르게 이런 식으로 문제들을 해결해 왔고 이것이 맞다고 본다. 다만, 정말로 하위 타입 관계가 맞을 경우에는 상속을 고려할 필요도 있을 것이다.

기능과 책임 분리

어떠한 객체가 어떠한 기능을 한다. 라는 말은 그 객체가 그러한 책임을 진다는 말과 동일하다. 이러한 책임을 우리는 한 객체가 모두 짊어지게 할 것이 아니라 적절하게 분배할 수 있게 분리해야만 한다.
여기서는 책임을 분리하는 몇가지 방법에 대해 알려주는데

  1. 패턴 적용하기
    전형적인 역할 분리 방법으로, 우리가 Spring 등에서 익숙히 사용하던 Controller - Service - Repository 등이 있다.
  2. 계산 분리
    이는 계산과 관련한 코드를 Calculator 등 클래스를 만들어서 분리하는 방식이다.
  3. 외부 연동
    외부와 연동하는 코드를 클래스로 분리하는 방식이다.
  4. 연속적인 if-else의 추상화

등이다.

역할 분리에서 주의할 점은, 각 역할을 분리한 클래스를 생성할 때 그 클래스의 이름이 클래스의 역할을 분명하게 표현해야 한다는 점이다.

의존과 DI

의존은 기능의 구현을 위해 다른 구성 요소를 사용하는 것이다. 의존 관계에 있다면, 변경 사항이 전파될 가능성이 존재한다.
그렇기 때문에, 우리는 의존하는 대상을 최대한 적게 잘 설계해야만 한다.

또한 우리가 의존 대상 객체를 직접 생성할 경우, 생성 클래스가 변경될 시 의존 코드 또한 변경될 수 있으므로, 우리는 의존 대상 객체를 직접 생성하지 않는 방식을 찾아야 한다.

이러한 방식에 대해서 강의에서는 3가지를 제시한다.

  • 팩토리, 빌더 패턴
  • 의존 주입 ( Dependency Injection )
  • 서비스 로케이터

이 중, 의존 주입 방식이 아무래도 우리가 주로 사용하게 될 방식일 것이다. 의존 주입 방식은 상위 타입을 사용할 경우 의존 대상의 변경 시 설정만 변경하면 되며, 대역 객체를 사용하여 테스트할 수 있다는 장점이 있다.

DIP

의존 역전 원칙이라고 불리는 DIP는

  • 고수준 모듈이 저수준 모듈의 구현에 의존하면 안된다.
  • 저수준 모듈이 고수준 모듈에서 정의한 추상 타입에 의존해야 한다.

라는 내용을 담고 있다.
즉 우리는, 고수준 모듈(의미 있는 단일 기능, 상위 수준 정책) 에 의존하여 추상화를 하고, 이에 의존하여 실제 구현을 해야 한다는 뜻이다.

마무리

이렇게 객체 지향 프로그래밍 입문 강의의 내용을 정리하였다.
다음부터는, 디자인 패턴과 관련한 글을 적어보고자 한다.
원래 이 사이트를 이용하여 공부를 하던 중, 그냥 헤드 퍼스트 디자인 패턴을 구매하였다.
이 책을 통해 디자인 패턴을 공부하며 내용을 정리할 생각이다.

profile
인간은 노력하는 한 방황한다

0개의 댓글