메시지와 인터페이스 (chapter6)


  • 객체지향적 프로그램 을지향 ->
    • 클래스가 아니라 객체에 초점 ->
      • 구체적으로 객체의 책임에 초점

중요한 것은 책임이 객체가 수신할 메시지의 기반이 된다는 것


협력과 메시지

  • 객체는 서로 협력의 관계에 있고 메세지를 주고 받는다!! (Chapter3)
  • 메시지는 객체 사이의 매개체이다
    • 즉 유일한 접근 방법은 메세지

클라이언트 - 서버 모델

  • 두 객체 사이의 협력 관계를 설명하기 위한 전통적인 방법 클라이언트-서버모델
  • 협력안에서 메세지 전송쪽을 클라이언트라 지칭
  • 협력안에서 메세지 수신쪽을 서버라 지칭
    협력은 클라이언트가 서버의 서비스를 요청하는 단방향 상호작용

  • Screening은 메시지를 전송하는 클라이언트, Movie는 메시지를 수신하는 서버

  • Movie은 메시지를 전송하는 클라이언트, DiscountPolicy는 메시지를 수신하는 서버

  • 이처럼 객체는 클라이언트와 서버 모두의 역할을 수행할 수 있다

메세지 구조

메시지와 메서드

  • 메시지 전송자는 어떤 메시지를 전송할지, 메시지 수신자는 어떤 메시지를 수신할지만 알면 된다. (즉, 어떠한 클래스가 전송하는지, 어떠한 클래스가 수신하는지 몰라도 된다)

condition의 경우 PeriodCondition, SequenceCondition 인스턴스가 올 수 있다. 컴파일시점과 실행시점의 인스턴스가 다르기 때문에, 이러한 구조의 메커니즘은 두 객체 사이의 결합도를 낮춤으로써 유연하고 확장 가능한 코드를 작성할 수 있게 만든다.

용어 정리

  • 메시지
    • 객체간 협력을 위해 사용하는 의사소통 메커니즘
  • 오퍼레이션
    • 객체가 다른 객체에게 제공하는 추상적인 서비스
  • 메서드
    • 메시지에 응답하기 위해 실행되는 코드 블록. 즉, 메서드는 오퍼레이션의 구현이다
  • 퍼블릭 인터페이스
    • 객체가 협력에 참여하기 위해 외부에서 수힌할 수 있는 메시지의 묶음, 집합이다
  • 시그니처
    • 시그니처는 오퍼레이션의 이름과 파라미터를 합쳐 부르는 말이다

인터페이스와 설계 품질

인터페이스 설계 품질을 위해 다음과 같은 원칙을 고려해보자

  • 디미터 법칙
  • 묻지 말고 시켜라
  • 의도를 드러내는 인터페이스

디미터 법칙

“낯선 자에게 말하지 말라” - [Larman]
“오직 인접한 이웃하고만 말하라” - [Metz]

  • 객체 내부 구조에 강하게 결합되지 않도록 협력 경로를 제한하라
  • ‘오직 하나의 .(도트)를 이용하라’ 라고 요약 되기도 한다. 아래는 위반되는 코드이다.
    screening.getMovie().getDiscountCondition();

즉, 디미터 법칙은 객체가 객체 자신이 자율적 존재가 되어야 함을 강조한다

묻지 말고 시켜라

  • 객체의 상태에 관해 묻지 말고 원하는 것을 시켜라. 이런 스타일의 메시지 작성을 장려하는 원칙이다.
  • 메시지 전송자는 메시지 수신자의 상태를 기반으로 결정을 내린 후 메신지 수신자의 상태를 바꿔서는 안된다.
  • 이 원칙을 따르면, 자연스럽게 정보 전문가에게 책임을 할당하게 되고 높은 응집도를 가진 클래스를 얻을수 있다.

의도를 드러내는 인터페이스

  • 메서드를 명명하는 두가지 방법
    첫번째, 메서드가 작업을 어떻게 수행할지 나타내도록 이름을 지어라

다만 이런 스타일은 좋지 않다

public class PeriodCondition {
    public boolean isSatisfiedByPeriod(Screening screeing) {}
}

public class SequenceCondition {
    public boolean isSatisfiedBySequence(Screening screeing) {}
}
  • 메서드에 대해 제대로된 커뮤니케이션이 안된다. 두가지 모두 할인 조건을 판단하는 작업을 수행하지만, 두 메서드의 이름이 다르기 때문에 내부 구현을 잘 모른다면 두 메서드가 동일한 작업을 수행한다는 사실을 알기 어렵다
  • 더 큰 문제는 메서드 수준에서 캡슐화를 위반한다. 할인 여부를 판단하는 방법이 변경된다면 메서더의 이름 역시 바뀌어야 할 것이다.

두번째, ‘어떻게’가 아니라 ‘무엇’을 하는지를 드러내라

public class PeriodCondition implements DiscountCondition {
    public boolean isSatisfied(Screening screeing) {}
}

public class SequenceCondition implements DiscountCondition {
    public boolean isSatisfied(Screening screeing) {}
}
  • 동일한 목적을 수행한다는 것을 명시하기 위해 메서드 이름을 통일하였다
  • 다만, 동일한 계층의 타입으로 묶어 주어야 한다. 인터페이스를 이용하자

이처럼, 어떻게 하느냐가 아니라 무엇을 하느냐에 초점을 맞추어 보자. 이런식으로 메서드의 이름을 통일하면 의도를 드러낼 수 있고, 인터페이스를 이용해 유연한 설계가 가능해진다.


원칙의 함정

디미터법칙, 묻지 말고 시켜라 법칙 등의 법칙이 깔끔하게 유연한 설계를 도와주지만 절대적인 것은 아니다. 잊지 말아야 할 것은 설계는 트레이드오프의 산물이라는 점이다.

디미터 법칙은 하나의 도트(.)를 강제하는 규칙이 아니다

IntStream.of(1,2,3).filter(x -> x >10).distinct().count();

dot을 한줄에 여러개 사용하였다.
디미터 법칙은 결합도와 관련된 것이다. 결합도는 객체의 내부 구조가 외부로 노출되는 경우를 한정하기 때문에 디미터법칙을 위반하지 않는다.

public class PeriodCondition implements DiscountCondition {
    public boolean isSatisfiedBy(Screening screening) {
        return screening.getStartTime().getDayOfWeek().equals(dayOfWeek) && startTime.compareTo(screeing.getStartTime().toLocalTime()) <= 0 && endTime.compareTo(screeing.getStartTime().toLocalTime()) >= 0;
    }
}

해당 로직을 묻지도 말고 시켜라 원칙을 적용해, Screening으로 옮겨 보자

public class Screeing {
    public boolean isDiscountable(DayOfWeek dayOfWeek, LocalTime startTime, LocalTime endTime) {
        return whenScreened.getDayOfWeek().equals(dayOfWeek) && startTime.compareTo(whenScreened.toLocalTime()) <= 0 && endTime.compareTo(whenScreened.toLocalTime()) >= 0;
    }
}

public class PeriodCondition implements DiscountCondition {
    public boolean isSatisfiedBy(Screening screening) {
        return screening. isDiscountable(dayOfWeek, startTime, endTime);
    }
}

묻지도 말고 시켜라 원칙을 지켰다. 그러나, Screening이 할인 조건을 떠맡게 되었다. 하지만 Screening 객체가 할인 조건을 책임 지는게 맞는 것일까? 당연히 그렇지 않다. 객체의 응집도가 낮아지게 되었다.

소프트웨어는 트레이드오프의 산물이기에 설계에 있어서 절대적인 법칙은 존재하지 않는다.


명령-쿼리 분리 원칙

명령 쿼리 분리 원칙은 퍼블릭 인터페이스에 오퍼레이션을 정의할 떄 참고할 지침을 제공한다.

  • 루틴

    • 어떤 절차를 묶어 호출 가능하도록 이름을 부여한 것
    • 프로시저와 함수로 구분된다
    • 프로시저
      • 부수효과를 발생시키지만 값을 반환할 수 없다
    • 함수
      • 값을 반환할 수 있지만 부수효과를 발생시킬 수 없다
  • 명령

    • 객체의 상태를 수정하는 오퍼레이션
  • 쿼리

    • 객체와 관련된 정보를 반환하는 오퍼레이션

중요한 것은 어떤 오퍼레이션도 명령이거나 동시에 쿼리여서는 안된다. 따라서 명령과 쿼리를 분리하기 위해서 다음의 두가지 규칙을 준수해야 한다

  1. 객체의 상태를 변경하는 명령은 반환값을 가질 수 없다
  2. 객체의 정보를 반환하는 쿼리는 상태를 변경할 수 없다

아래의 예시를 살펴보자

public class Event {
    public boolean isSatisFied(RecurringSchedule schedule) {
        if (...) {
            reschedule(schedule);
            return false;
        }
        return true;
    }
}

boolean이라는 상태값을 반환하지만, 중간에 reschedule을 호출한다, 그리고 schedule을 바꾸어 버린다 … 이 코드를 다음과 같이 분리해보자

public class Event {
    public boolean isSatisFied(RecurringSchedule schedule) {
        if (...) {
            return false;
        }
        return true;
    }
}

if (!event.isSatisfied(schedule)) {
    event.reschedule(schedule);
}    

명령과 쿼리를 분리함으로써 내부적인 버그를 해결할 수 있다.


참조

오브젝트 - 코드로 이해하는 객체지향 설계, 6장 메시지와 인터페이스

'Books > Object' 카테고리의 다른 글

[Object] 의존성 관리하기  (0) 2021.06.10
[Object] 객체 분해  (0) 2021.05.29
[Object] 메시지와 인터페이스  (0) 2021.05.25
[Object] 책임 할당하기  (0) 2021.05.16
[Object] 설계 품질과 트레이드오프  (0) 2021.05.08
[Object] 역할, 책임, 협력  (0) 2021.05.03
블로그 이미지

사용자 yhmane

댓글을 달아 주세요

설계 품질과 트레이드오프 (chapter4)


객체지향 설계
“올바른 객체에게 올바른 책임을 할당하면서
낮은 결합도와 높은 응집도를 가진 구조를 창조하는 활동이다”

더 좋은 객체설계를 위해

  • 객체가 가지는 데이터보다 책임에 초점을 맞추어 설계를 하자
    • 퍼블릭 인터페이스를 제공하여 객체의 자유도를 높이자
    • 메세지를 통해 상호작용하여 결합도 낮은 설계를 하자

설계 트레이드오프

객체지향 설계에 3가지 품질 척도

  • 캡슐화
  • 응집도
  • 결합도

캡슐화

변경 가능성이 높은 부분을 객체 내부로 숨기는 추상화 기법

  • 객체 내부에 무엇을 캡슐화 해야 하는가?
    • 경될 수 있는 어떤 대상이라도 캡슐화 해야 한다!

응집도

모듈 내부에 포함된 내부 요소들이 연관돼 있는 정도를 나타낸다
모듈 내의 요소들이 하나의 목적을 위해 협력한다면 높은 응집도를 가진다.
서로 다른 목적을 추구한다면 그 모듈은 낮은 응집도를 가진다.
객체지향 관점에서 응집도는 객체 또는 클래스에 얼마나 관련 있는 책임을 할당했는지를 나타낸다.

  • 응집도 변경의 관점에서 - 변경이 발생할때 모듈 내부에서 발생하는 변경의 정도
  • 응집도가 높을 경우 변경이 발생하면, 오직 하나의 모듈만 수정하면 된다. 반면, 응집도가 낮을 경우 변경이 발생하면 여로 모듈을 수정하게 된다.

결합도

의존성의 정도를 나타낸다. 다른 모듈에 얼마나 많은 지식을 갖고 있는지를 나타내는 척도이다.
객체지향 관점에서 결합도는 객체 또는 클래스가 협력에 필요한 적절한 수준의 관계만을 유지하고 있는지를 나타낸다

  • 결합도 변경의 관점에서 - 한 모듈이 변경되기 위해서 다른 모듈의 변경을 요구하는 정도
  • 결합도가 낮을 경우 수정해야 하는 모듈이 적지만, 결합도가 높을 경우 변경이 발생하게 되면 다른 모듈까지 같이 수정하게 된다.

데이터 중심 설계의 문제점

캡슐화 위반

오직 메서드만을 통해 내부 상태에 접근한다. 어떠한 점이 캡슐화를 위반한 것일까?

public class Movie {
    private Money fee;
    public Money getFee() { 
        return fee; 
    } 

    public void setFee(Money fee) {
        this.fee = fee; 
    } 
}
  • 접근자와 수정자를 통해 Money타입의 fee라는 상태가 존재한다는 것을 알 수 있다
    • 캡슐화를 위반하는 이유는 객체가 수행할 책임이 아니라 내부에 저장할 데이터에 초점을 맞췄기 때문이다

높은 결합도

public class ReservationAgency {
    ... if (discountable) { 
        fee = movie.getFee().minus(discountAmount).times(audienceCount); 
    } else { 
        fee = movie.getFee().times(audienceCount); 
    } 
}
  • Movie의 fee는 private한 상태이지만, 구현 로직을 보면 전혀 private하지 않다.

결국 데이터 중심의 설계로, ReservationAgency는 높은 결합도를 가지게 되었다. 따라서, 이 모듈을 변경하게 되면 다른 모듈까지 많은 변경을 요구하게 된다.

낮은 응집도

ReservationAgency에는 할인 가격을 계산한다는 이유로 변경 이유가 서로 다른 코드를 전부 뭉쳐놓는다. 따라서 하나의 요구사항을 반영하기 위해서는 여러 모듈을 수정해야한다. 응집도가 낮은것이다.


자율적인 객체

  • 접근자, 수정자를 통해 객체의 내부상태에 접근을 허용하였다. get/set 메서드를 제거하고 클래스 내부에서 책임를 지도록 변경하자

데이터 중심 설계의 문제점

  • 데이터 중심 설계는 너무 이른 시기에 데이터에 관해 결정하도록 강요한다
  • 협력이라는 문맥을 고려하지 않고 객체를 고립시킨 채 operation을 결정한다

정리

  • 객체 설계시 캡슐화를 먼저 고려해보자. 그러면 낮은 결합도를 가지며, 높은 결합도있는 모듈로 설계할 수 있다
  • 우리가 알고 있는 캡슐화와 저자가 말하고 있는 캡슐화는 다른 조금 다른 영역이다
    • private로 클래스 변수를 지정한다고 캡슐화는 아니다
    • 접근자(get), 수정자(set)이 꼭 필요할까 의심해보자
    • 접근자와 수정자를 제공한다는 것은 결국 public interface로 접근 가능하다는 뜻이다
  • 결국 객체의 자율화란, 내부로 감추는 것인데 srp 원칙을 고려하여 책임을 할당해보자. 클래스 변수는 내부구현으로 감추도록!!

참조

Object 코드로 이해하는 객체지향 설계 chapter4

'Books > Object' 카테고리의 다른 글

[Object] 메시지와 인터페이스  (0) 2021.05.25
[Object] 책임 할당하기  (0) 2021.05.16
[Object] 설계 품질과 트레이드오프  (0) 2021.05.08
[Object] 역할, 책임, 협력  (0) 2021.05.03
[Object] 객체지향 프로그래밍  (0) 2021.04.25
[Object] 객체 설계  (0) 2021.04.22
블로그 이미지

사용자 yhmane

댓글을 달아 주세요

역할, 책임, 협력

객체지향의 본질이란 무엇일까?

객체지향의 본질은 ”협력하는 객체들의 공동체” 를 창조하는 것이다

객체지향 설계의 핵심

  • 협력을 구성하기 위해 적절한 객체를 찾고 적절한 책임을 할당하는 과정이다
    즉, 객체지향 패러다임 관점에서 핵심은 역할, 책임, 협력이다

영화예매 시스템

  • 다양한 객체들이 상호작용을 하고 있다

  • 제어흐름은 한 객체에 의한 통제가 아닌 다양한 객체들 사에이 균형있게 분배되어 있다

  • 이처럼 객체들이 기능 구현을 위해 수행하는 상호작용을 협력 이라고 한다

  • 객체가 협력에 참여하기 위해 수행하는 로직을 책임 이라고 한다

  • 객체들이 협력 안에서 수행하는 책임들이 모여 객체가 수행하는 역할을 구성한다


협력

협력

객체들이 기능 구현을 위해 수행하는 상호작용

  • 메세지 전송은 객체 사이의 협력을 위해 사용하는 유일한 커뮤니케이션 수단
  • 외부의 객체는 오직 메세지만 전송할 수 있다
  • 메세지를 수신한 객체는 어떻게 처리할지 스스로 결정한다
    • ‘객체가 자신의 일을 스스로 처리할 수 있는 자율적인 존재’


상영객체는 메세지를 전송하고, 영화 객체는 메서드를 수행한다. 상영객체는 영화 객체 내부의 구현을 알 수 없다. -> 자율적인 객체를 만드는 가장 기본적인 방법은 “캡슐화”


책임

책임

객체가 협력에 참여하기 위해 수행하는 로직 또는 행동
객체의 책임은 ‘무엇을 알고 있는가?’ / ‘무엇을 할 수 있는가’로 구분된다

  • 하는것

    • 객체를 생성하거나 계산을 수행
    • 다른 객체의 행동을 시작시키는 것
    • 다른 객체의 활동을 제어하고 조절
  • 아는것

    • 사적인 정보에 관해 아는것
    • 관련된 객체에 관해 아는것
    • 자신이 유도하거나 계산할 수 있는것에 대해 아는것

책임은 하는것 & 아는것과 구분된다. 또한 협력할 객체를 상태값으로 가지고 있다.

책임 할당

  • 협력에 필요한 지식과 방법을 가장 잘 아는 객체에게 도움을 요청 - ‘정보 전문가’


영화를 예약하기 위해서는, 영화 회차/시간 정보를 알아야한다. 이 정보를 가장 잘 아는 것은 상영 객체이다. 또한 요금을 계산 -> 상영은 요금 정보가 없기에 Movie에게 책임을 위임한다

책임 할당시 고려해야 할 요소

  • 메세지가 객체를 결정

    • 객체에게 책임을 할당시 필요한 메세지를 먼저 식별
    • 메시지를 처리할 객체를 나중에 선택
      • 객체가 메시지를 선택하는 것이 아니라, 메시지가 객체를 선택한다
  • 행동이 상태를 결정

    • 객체의 행동은 객체가 협력에 참여할 수 있는 유일한 방법
    • 협력이 객체의 행동을 결정하고 행동이 객체의 상태를 결정한다. 그 행동이 바로 객체의 책임

역할

역할

객체가 어떤 특정한 협력 안에서 수행하는 책임의 집합

유연하고 재사용 가능한 협력

  • 역할을 통해 유연하고 재사용 가능한 협력을 얻을 수 있다


할인 요금을 계산하는 두개의 객체가 있다. 두 객체를 같이 사용하는 대신 하나의 슬롯으로 구성하여 교대로 바꿔뀔수 있게 구성한다. 이 슬롯이 ‘역할’

  • 역할을 구현하는 가장 일반적인 방법은 추상 클래스와 인터페이스 사용

참조

  • 오브젝트 코드로 이해하는 객체지향 설계 chapter3

'Books > Object' 카테고리의 다른 글

[Object] 메시지와 인터페이스  (0) 2021.05.25
[Object] 책임 할당하기  (0) 2021.05.16
[Object] 설계 품질과 트레이드오프  (0) 2021.05.08
[Object] 역할, 책임, 협력  (0) 2021.05.03
[Object] 객체지향 프로그래밍  (0) 2021.04.25
[Object] 객체 설계  (0) 2021.04.22
블로그 이미지

사용자 yhmane

댓글을 달아 주세요

객체지향 프로그래밍 (OOP)

오브젝트 - [조영호님 저]


객체 설계 (chapter1)

좋은 설계란 무엇일까?
역할과 책임에 대하여 많은 얘기가 오가지만 결국 중요한 것은 객체간의 의존성이다

  • 설계의 핵심은 의존성 이다
  • 좋은 설계는 의존성을 어떻게 하는지에 달려있다.
  • 의존성에 따라 설계가 바뀐다

의존성

객체가 의존 관계에 있을때, 객체가 변하면 의존하는 객체도 변경될 수 있다.
* 양방향을 피해라
* 다중성이 적은 방향을 선택하라
* 의존성의 사이클을 제거하라 (triangle)
* 의존하는 필요없다면 제거하라


객체 관계

  • 연관 관계 (Association)
    class A {
      private B b;
    }
  • 의존관계 (Dependency)
    파라미터에 또는 return 타입, 메서드 내부에서 인스턴스를 생성할 경우

    class A {
      public B method(B b) {
          return new B();
      }
    }

  • 상속관계 (Inheritance)

    class A extends B {
    }

  • 실체화 관계 (Realization)

    class A implements B {
    }


문제가 되는 설계

‘로버트 마틴’ - 소프트웨어 모듈이 가져야 하는 세가지 원칙


“모든 모듈은 제대로 실행 되어야 하고,
변경이 용이해야 하며,
이해하기 쉬워야 한다”

책의 저자는 "로버트 마틴"이 말한 소프트웨어가 가져야 하는 3가지 원칙에 대하여 말한다.
아래 예제는 위에서 말한 첫번째 원칙만 해당한다. 아래 예제를 살펴보자.

Theater가 enter() 통해 4개의 객체에 의존하고 있다. 로직이 너무 복잡한다

public void enter(Audience audience) {
    if (audience.getBag().hasInvitation()) {
        Ticket ticket = ticketSeller.getTicketOffice().getTicket();
        audience.getBag().setTicket(ticket);
    } else {
        Ticket ticket = ticketSeller.getTicketOffice().getTicket();
        audience.getBag().minusAmount(ticket.getFee());
        ticketSeller.getTicketOffice().plusAmount(ticket.getFee());
        audience.getBag().setTicket(ticket);
    }
}
  • 1) enter()에서 파라미터로 관람객에 의존한다.
  • 2) 관람객의 가방에 접근하여 초대권이 있는지 확인한다 (초대권이 있을경우)
    • 2-1) 판매원이 매표소에가서 티켓을 가져온다
    • 2-2) 관람객에 가방에 티켓을 넣어준다
  • 3) (초대권이 없을경우)
    • 3-1) 판매원이 매표소에가서 티켓을 가져온다
    • 3-2) 관람객에 가방에서 티켓가격만큼 금액을 차감한다
    • 3-3) 판매원이 매표소로 가서 티켓가격만금 금액을 합산한다
    • 3-4) 관람객에 가방에 티켓을 넣어준다

예제는 너무 복잡하여 변경에 취약하다.

  • 변경에 취약한 코드
    • 결합도가 높은 코드 -> 의존성이 강하다
    • 결합도가 낮은 코드 -> 합리적인 수준으로 의존한다

객체 사이의 결합도를 낮춰 변경이 용이한 설계를 해야 한다


개선된 설계

Theater가 가지고 있던 많은 책임들을 각 클래스에 전이 시켰다

  • 변경에 유연한 코드
    • 자율적인 존재가 되도록 설계를 변경
      • 캡슐화(encapsulation)
        • 개념적이나 물리적으로 객체 내부의 세부적인 사항을 감춘다
        • 내부로의 접근을 제한하여 객체들간의 결합도를 낮출 수 있다
    • 자기 자신의 문제는 스스로 해결
      • 객체 내부의 상태를 캡슐화한다
      • 객체는 오직 메시지를 통해서만 상호작용하도록 만든다
      • 연관성 없는 작업은 다른 객체에게 위임하여 응집도를 높인다

객체지향적 설계

객체지향적 설계를 위해서는 객체간의 의존 관계를 적절하게 서술하고,
각 객체가 자율적이며 응집도 높은 코드를 작성해야 한다.

참고 자료

YouTube - 우아한 객체지향 [조영호님]
수정본 우아한 객체지향

'Books > Object' 카테고리의 다른 글

[Object] 메시지와 인터페이스  (0) 2021.05.25
[Object] 책임 할당하기  (0) 2021.05.16
[Object] 설계 품질과 트레이드오프  (0) 2021.05.08
[Object] 역할, 책임, 협력  (0) 2021.05.03
[Object] 객체지향 프로그래밍  (0) 2021.04.25
[Object] 객체 설계  (0) 2021.04.22
블로그 이미지

사용자 yhmane

댓글을 달아 주세요

들어가며


 이전 포스팅까지는 자바의 기초문법에 대하여 정의하였습니다. 기본적인 문법구조나 변수 선언등에 대해서 알아보았고, 이번 포스팅에선 자바의 가장 두드러지는 특징인 객체지향의 대하여 알아보도록 하겠습니다.


객체지향의 개념


 객체지향이란 컴퓨터 프로그래밍 패러다임중의 한 종류입니다. 기존 명령어를 중심으로 나열하는 프로그래밍기법에서 벗어나, 객체 모델을 바탕으로 프로그램을 구체화하고 개발하는 프로그래밍 기법을 의미합니다. 객체지향의 특징에는 상속, 추상화, 다형, 추상화 이라는 특징이 있습니다.

 위에 언급된 특성은 객체지향의 핵심적인 특징으로 꼭 이해하시고 가야 합니다. 객체지향의 특징을 설명하기 전에 클래스, 객체, 인스턴스를 짚고 넘어가도록 하겠습니다.


  • 클래스

멤버변수와 함수로 구성된 논리적인 설계도


class Student {

private String name;

private int age;

}


  • 객체

클래스에 선언된 모응 그대로 생성된 실체


public class Main {

public static void main(String[] args) {

Student student;

}

}


  • 인스턴스

생성되어진 객체가 메모리에 올려진 것


public class Main {

public static void main(String[] args) {

Student student = new Student();

}

}


객체와 인스턴스는 일반적으로는 통용하여 표현하나, 메모리에 올려진 여부로 객체와 인스턴스를 판단합니다.



객체지향의 특징


 객체지향에는 다음과 같은 특징이 있습니다. 캡슐화, 상속, 다형성, 추상화 모두 중요한 개념입니다. 


  • 캡슐화

 캡슐화는 생성한 객체를 어떤 메서드와 필드로 어떻게 일을 수행할지 외부에 숨기는 특성을 말합니다. 캡슐화 은닉화 라고 하며 보호하고자 하는 데이터의 값을 외부에서 직접 접근하는 것을 방지하기 위해 나온 개념입니다. 접근제어자를 이용하여 값을 은닉하고, public method로 값을 통제합니다.


캡슐화 예제

 class Student {
private String name;
private int age;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge() {
this.age = age;
}
}


public class Main {

public static void main(String[] args) {

Student student = new Student();


student.setName("윤호");

student.setAge(20);


System.out.println("학생의 이름 : " + student.getName());

System.out.println("학생의 나이 : " + student.getAge());

}

}


  • 상속

 클래스는 추상화된 슈퍼클래스와 구체화된 서브 클래스로 구성됩니다. 예를 들면 사람(슈퍼클래스)와 학생(서브클래스)
 지정 예약어 extends를 이용하여 상속을 이용합니다. 하나의 부모클래스는 여러 자식을 가질 수 있지만, 반대는 성립하지 않습니다.
 자식은 부모의 값이나 행위를 상속받아 사용할 수 있습니다. 

상속 예제

class Person {
private String name;
private int age;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge() {
this.age = age;
}

public void run() {
System.out.println("달리기를 합니다");
}
}

class Student extends Person() {
public void study() {
System.out.println("공부를 합니다");
}
}


public class Main {

public static void main(String[] args) {

Student student = new Student();


student.setName("윤호");

student.setAge(20);


System.out.println("학생의 이름 : " + student.getName());

System.out.println("학생의 나이 : " + student.getAge());


student.run();

student.study();

}

}


  • 다형성

 클래스의 상속 관계를 이용하여 슈퍼클래스가 같은 서브 클래스의 동일한 요청을 다르게 처리할 수 있는 특징을 말합니다. 예를 들어, 사람이라는 클래스가 있고 아침에 이동하다는 행위를 합니다. 사람을 상속받은 학생클래스는 아침에 학교로 이동하고, 사람을 상속박은 직장인 클래스는 아침에 회사로 이동합니다. 아래 예제를 보도록 하겠습니다.

다형성 예제


class Person {
public void move() {
System.out.println("이동합니다");
}
}

class Student extends Person() {
@Override
public void move() {
System.out.println("학교로 이동합니다");
}
}

class Student extends Worker() {
@Override
public void move() {
System.out.println("일터로 이동합니다");
}
}

public class Main {

public static void main(String[] args) {

Student student = new Student();

Worker worker = new Worker();


student.move();

worker.move();

}

}


  • 추상화

 매우 중요한 개념입니다. 객체의 공통된 특징을 묶어서 추출한다는 개념인데, 다음 포스팅에서 클래스에 대하여 설명하며 추상클래스, 인터페이스와 함께 덧붙이도록 하겠습니다.


정리

 

 이번 포스팅에선 자바의 핵심 개념인 객체지향에 대하여 글을 작성하였습니다. 자바는 프로그램을 구조화하는 특징을 가졌으며 추상화, 상속, 캡슐화, 다형성라는 중요한 특성이 있습니다. 이러한 기능으로 구조적으로 재활용성이 높아져 생산성이나 유지보수 효율성을 높인 프로그래밍 언어입니다!!


출처


- 자바의 정석

- just 자바

블로그 이미지

사용자 yhmane

댓글을 달아 주세요