본문 바로가기
Java

Objects 시리즈_2장.객체지향 프로그래밍

by Jordy-torvalds 2020. 4. 20.
반응형

객체지향 패러다미으로의 전환은 클래스가 아닌 객체에 초점을 맞출 때에만 얻을 수 있다.

  • 어떤 클래스가 필요한지를 고민하기 전에 어떤 객체들이 필요한지 고민하라.
  • 객체를 독립적인 존재가 아니라 기능을 구현하기 위해 협력하는 공동체의 일원으로 봐야한다.

도메인

정의

문제를 해결하기 위해 사용자가 프로그램을 사용하는 분야


클래스 구현 혹은 다른 개발자가 개발한 클래스 사용시 중요한 것.

  • 클래스의 경계를 내, 외부로 구분 짓는 것.
  • 어떤 부분을 외부로 공개하고 어떤 부분을 감출지 결정하는 것

객체

정의

  • 객체가 상태와 행동을 함께 가지는 존재
  • 스스로 판단하고 행동하는 자율적인 존재
  • 캡슐화(데이터와 기능을 한 덩어리로 내부에 묶는 것)하여 문제 영역의 아이디어를 적절하게 표현할 수 있게 한 것.

접근 수정자(access modifier)

  • 접근 가능한 범위를 설정함으로써 데이터와 기능에 무분별한 접근을 막아주는 기능.
  • 앞서 말한 내, 외부 구분에서도 활용된다.

퍼블릭 인터페이스(public interface)

외부에서 접근이 가능한 부분. 인터페이스로 줄여 쓰기도 한다.

구현(implementation)

외부에서 접근 불가능하고 오직 내부에서만 접근 가능한 부분.

인터페이스와 구현

  • 위 두 가지를 합쳐 인터페이스와 구현의 분리라고 한다.
  • 인터페이스만 공개하고 구현은 접근을 방지함으로써 클라이언트 프로그래머에 대한 영향은 걱정하지 않고도 내부 구현을 마음대로 변경할 수 있다. 이를 구현 은닉(implementation hiding)이라 한다.
    • A객체의 B메서드를 인터페이스로 공개해놓으면 클라이언트 프로그래머는 이를 사용한다. 이 때 B메서드의 내부 구현된 로직이 변경되어도 이를 사용하는 클라이언트 프로그래머는 영향을 받지 않는다.
  • 이 처럼 인터페이스와 구현을 잘 분리해 클라이언트 프로그래머가 인터페이스만 알아도 사용할 수 있게 함으로써 머릿속에 담아둬야 하는 지식의 양을 줄일 수 있다.
  • 또한 결합도가 낮아짐에 따라 내부 구현의 변경도 쉽다.

협력 (collaboration)

시스템의 어떤 기능을 구현하기 위해 객체들 사이에 이뤄지는 상호작용

요청 (request)

객체가 다른 객체의 인퍼이스에 공개된 행동을 수행하도록 요구하는 것

응답 (response)

요청을 받은 객체는 자율적인 방법에 따라 처리하고 이에 대해 다시 알려주는 것

메세지 전송과 수신

  • 객체가 다른 객체에게 요청을 보내는 것은 메세지 전송, 그리고 요청이 도착했을 때 메세지 수신했다고 한다.
  • 수신된 메세지를 처리하기 위한 객체 자신만의 방법을 메소드(method) 라고 한다.

메세지와 메소드

  • 메시지는 객체와 다른 객체 간에 통신 수단이고, 메소드는 앞서 말했듯 수신받은 메세지에 대한 처리 방법이다.
  • 메세지와 메소드를 구분하는 것에서 다형성(polymolphism)의 개념이 출발한다.

추상 클래스

정의

추상화(abstraction), 상속(inheritance), 다형성(polymolphism)을 통해 객체 지향적인 설계를 할 수 있게 하는 타입.

세부 내용

  • 추상 클래스의 경우 관련된 클래스와 공통적인 비즈니스 로직은 메소드로 구현하고, 그외 메소드는 추상 메소드로 하여 상속받은 클래스에 위임해서 구현되도록 하고 싶을 때 사용하는 타입이다.
  • 이렇듯 부모 클래스에서 기본적인 알고리즘의 흐름을 구현하고 중간에 필요한 처리를 자식 클래스에게 위임하는 디자인 패턴을 템플릿 메소드 패턴(template method pattern) 이라고 한다.
  • 파라미터가 특정 추상 클래스를 되어 있어도 런타임 때 이를 구현한 서브 타입을 넘기는 것이 가능하다.

오버 라이딩과 오버 로딩의 차이

  • 부모 클래스의 접근 지정자와 반환 타입, 변수명이 일치
  • 파라미터이 다름

상속과 다형성

다시 한 번 의존성이란?

  • 어떤 클래스가 다른 클래스에 접근할 수 있는 경로를 가지거나 해당 클래스의 객체의 메소드를 호출할 경우 두 클래스 사이에 의존성이 존재한다고 한다.

이해와 디버깅이 쉬운 코드 / 유연성 있고 확장이 가능한 코드

  • 이해와 디버깅이 쉬운 코드의 경우 컴파일 시점의 의존성과 실행 시점의 의존성이 동일하다.
  • 반면에 유연성 있고 확장이 가능한 코드는 컴파일 시점의 의존성과 실행 시점의 의존성이 다르다.
  • 이해와 디버깅이 쉬운 코드는 유연성이 떨어지고 확장이 어렵다.
  • 반면에 유연성이 있고 확장이 가능한 코드는 이해와 디버깅이 다소 어렵다.
  • 두 속성은 반비례 관계에 있어 필요에 따라 적당히 조절하는 것이 필요하다.
  • 저자는 이와같은 의존성의 양면성을 트레이오프의 산물이라고 표현했다.

차이에 의한 프로그래밍

  • 클래스를 하나 추가하고 싶은데 그 클래스가 기존의 어떤 클래스와 매우 흡사하다면, 기존의 코드를 가져와 약간만 추가하거나 수정해서 클래스를 만들고 싶을 것이다.
  • 이러한 재사용을 가능하게 하는 것이 상속이다.
  • 부모 클래스의 다른 부분만을 추가해서 새로운 클래스를 쉽고 빠르게 만드는 방법을 차이에 의한 프로그래밍(programming by difference)라고 한다.

상속과 인터페이스

  • 부모 클래스를 상속한 자식 클래스는 부모 클래스가 수신할 수 있는 모든 메세지를 수신할 수 있기 때문에 외부 객체는 자식 클래스를 부모 클래스와 동일한 타입으로 간주할 수 있다.
  • 이처럼 자식 클래스가 부모 클래스를 대신하는 것을 업 캐스팅(upcasting)이라고 부른다.

다형성(polymorphism)

  • 어떤 클래스가 송신한 메세지에 대한 처리가 메세지를 수신하는 객체의 클래스에 따라 달라지는 것.
  • 부모 클래스를 업 캐스팅한 자식 클래스가 메세지 처리를 대신 하는 것.
  • 실행 시점에 메세지를 수신한 객체에게 요청을 바인딩 하기 때문에 이를 동적 바인딩(dynamic binding) 이라 함.
  • 컴파일 시점에 실행된 함수나 프로시저를 결정하는 것을 정적 바인딩(static binding) 이라 함.

구현 상속과 인터페이스 상속

  • 상속을 구현 상속(implementation inheritance)과 인터페이스 상속(interface inheritance)로 분류 할 수 있다. 전자를 흔히 서브클래싱(subclassing)이라 부르고 인터페이스 상속을 서브 타이핑(subtyping)이라 부른다.
  • 순수하게 코드를 재사용하기 위한 목적으로 상속을 사용하는 것을 구현 상속 혹은 서브 클래싱이라 부른다.
  • 다형적인 협력을 위해 부모 클래스와 자식 클래스가 인터페이스를 공유할 수 있도록 상속을 이용하는 것을 인터페이스 상속이라고 부른다.
  • 흔히 코드의 재사용성을 위해 상속을 사용하지만, 이는 변경에 취약한 코드를 낳게 될 확률이 높다.
  • 그래서 인터페이스를 재사용하기 위해 사용하는 것이 바람직하다.

추상화의 장점

  • 추상화의 계층만 따로 떼어 놓고 살펴보면 요구사항의 정책을 높은 수준에서 서술할 수 있다.
    • 추상화를 하면 세부적인 내용을 무시한 채 상위 정책을 쉽고 간단하게 표현할 수 있다.
    • 세부사항에 억눌리지 않고 상위 개념만으로도 도메인의 중요한 개념을 설명할 수 있게 한다.
  • 추상화를 이용하면 설계가 좀 더 유연해진다.
    • 추상화를 이용해 상위 정책을 표현하면 기존 구조를 수정하지 않고도 새로운 기능을 쉽게 추가하고 확장할 수 있다.

상속과 캡슐화, 그리고 합성

  • 상속의 경우 자연스럽게 부모 클래스의 내부 구조를 이해하게 하고 이는 최소한의 인터페이스만을 공개하는 캡슐화에 위반된다.
  • 그러므로 코드의 재사용을 위해서는 상속보다는 합성(composition)이 더 좋은 방법이다.
  • 인터페이스에 정의된 메세지를 통해서만 코드를 재사용하는 방법을 합성이라고 한다.
    • 합성은 정의된 메세지를 통해서만 재사용이 가능하기 떄문에 구현을 효과적으로 캡슐화한다.
    • 합성은 의존하는 인스턴스를 교체하는 것이 비교적 쉽기 때문에 설계를 유연하게 만든다.
  • 결과적으로 상속에 비해 합성은 느슨하게 결합(loosen coupling)한다.
  • 그러므로 인터페이스의 재사용을 위한게 아닌 단순히 코드의 재사용을 위한 것이면 합성을 사용하자.
반응형