4. 객체 지향 개념

실질적인 구현 분석 전에 객체지향 개념을 정리하는 것

객체지향 개념

-해결하고자 문제는 실세계에 돌아가는 문제인데 다른 방법론에서는 자연스럽지 않은 편, c언어나 정보공학방법, 구조론적 방법으로 본다면 컴퓨터가 보는 방식으로 바꿔야 한다.

→ 객체지향 방법론자체가 어린 아이도 프로그래밍 하자라는 모토에서 시작된 것이기 때문에 아이들도 할 수 있을 정도로 사람이 생각하는 대로 고대로 코딩하게 하자

  • 사람이 생각하는 방식으로 그대로 모델링하는 것
  • 객체 모델은 실세계 문제를 더 자연스럽게 표현할 수 있기 떄문에 개발자가 설계를 이해하고 작성하기 쉽다
  • 자료와 함수를 함께 추상화함으로써 변화의 영향을 적게 받는다
  • 사용자 중심, 대화식 프로그램의 개발에 적합하다
  • 프로그램을 뚜렷하게 구별되는 단위(object)로 분할이 가능하다

객체지향과 절차적 방법의 비교

Untitled

절차적 방법

C언어는 프로그램이라는 것은 데이터와 그것을 이용해서 일을 하는 함수로 구성되어있다.

자료구조를 구조체로 만들고 함수를 만든다. 지역변수로 잘 넘겨서 쓰고 자료를 함수들이 공유하고 있는 형태, 전역변수로 하는 게 아니라 함수의 매개변수로 넘겨준다. 모든 함수가 자료를 공유하는 형태

  • 데이터가 있고 먼가 바뀌게 되면 함수를 찾아서 다 바꿔줘야한다.

    하지만 변경은 불가피함 -> 프로그램이 점점 커지게 되면 함수를 찾아 고치기가 쉽지 않다 -> 오류 발생

객체 지향 방법

객체지향 방법론은 객체라는 거 자체가 자신의 데이터와 그 데이터가 사용하는 함수를 따로 묶음. 부분 데이터만 사용하는 함수만을 묶은 것을 객체라고 하고 프로그램은 객체와 객체가 연결되어있다(+가 매우 중요)즉, 객체는 상호작용을 한다

객체지향에서는 관련 데이터와 그 데이터를 사용하는 함수를 묶는다.

객체

: 실세계 영역에 있는 정보,물건, 사물, 개체, 개념 등을 표현, 인식할 수 있는 대상

데이터와 이 데이터를 처리하는 함수가 한 곳에 뭉쳐 있는 것

  • 속성과 기능을 함께 가지고 있음

존재하지 않는 추상화된 것도 만들 수 있으며 객체는 데이터와 자신의 데이터를 처리하는 함수가 존재

Ex) 조정석은 남자이고 나이가 몇살이고 대한민국 사람이고 혈액형은 a형이고 등등… 근데 조정석의 몸무게가 60kg이야 근데 기능 중에 운동하고 먹고 자는 함수가 있는데 조정석의 몸무게는 먹으면 늘고 운동하면 줄게 된다. 이게 기능, 먹는 기능을 많이 하면 운동하는 기능을 적게 호출하면 몸무게가 늘게 된다. 이 속성은 대부분 기능에 의해서 바뀌게 된다.

Ex) 시계, 손목시계가 갖고 있는 속성은 브랜드, 가격, 시계의 종류 등등 중 가장 중요한 데이터는 시간이고 이게 상태, 상태가 계속 바뀌는데 이 말은 데이터가 바뀐다는 의미, 여러가지 속성 중인 시간이 계속 바뀌는데 시계가 하는 일은 시간을 구하는 기능이다. 이 기능으로 현재 시간의 속성을 바꿔주고 있음.

객체의 조건

  • 상태(state)를 가져야 한다 : 자신의 데이터는 상태를 나타낸다
  • 행위(behavior)를 가져야 한다 : 상태를 바꿔주는 행위, 기능이 필요
  • 고유의 식별자(identity)를 가져야 한다 : 다른 객체와 구별
  • 자신의 속성과 데이터를 바꿔주는 기능을 가지고 있고 이것을 프로그램으로 그대로 가져옴

    ex) 내 자동차와 친구 자동차가 사양과 옵션이 모두 같아도 다른 자동차!

    데이터가 모두 같다 하더라도 다른 자동차!

    자바는 레퍼런스, c++는 객체 주소값이 된다.

객체는 자신의 데이터와 함수를 가지고 있고 데이터는 자신의 상태를 나타낸다.

각각이 구별될 수 있는 identity를 가지고 있어야 한다.

캡슐화(Encapsulation)

다른것과 구별해서 관련된 속성과 그것과 관련된 operation을 클래스 안에 묶어서 하나로 취급하는 것

캡슐화의 장점

  • 특정 기능을 모듈화 할 수 있다
  • 관련성을 정확히 규정할 수 있다
  • 프로그램 수정이 용이하다.
  • 추상화의 수단이 된다.

-자바로는 클래스로 만드는 것을 의미

캡슐화의 효과

정보은닉(information hiding)

캡슐 속에 있는 항목에 대한 정보를 외부에 감추는 것

외부의 직접적 접근이 불가, 일종의 블랙박스

장점 - 객체의 세부사항을 다른 객체에 숨김으로써 다른 객체가 해당 객체에 함부로 접근하는 것을 막는다.

데이터가 감춰져 있고 외부에 보이는 부분(메소드, 인터페이스) 외부에서 데이터에 접근하고 싶을 경우에는 공개되어있는 인터페이스를 통해서만 접근해야 한다. 그래야 캡슐화의 효과를 가진다!

  • 자바 정보 은닉 장치는 접근 제어자로 설정
  • 맴버변수는 기본적으로 private이고 c++는 기본이 private

Ex) 조정석 몸무게를 public이면 다른 사람이 맘대로 바꿀 수 있는데 데이터는 반드시 외부에서 쓸 수 있는 메소드에 의해서 바뀌게 된다.

일을 시키는 수단 – 메소드

클래스

: 객체의 타입

유사한 객체들이 갖는 공통된 데이터와 함수들을 정의한 객체의 기본 규격(specification)이다.

  • 사용자 정의 데이터 타입이라고도 함(c++)
  • 유사한 기능들을 갖는 객체들의 모임
  • 객체는 클래스의 인스턴스임

객체들을 찾아내고 관련된 객체들을 묶어서 추상화해서 클래스로 만들어낸다

✅객체간의 의사소통 : 메세지패싱

  • 객체는 객체끼리 의사소통을 한다,서로 커뮤니케이션한다. 메세지를 주고 받는다
  • 객체가 혼자 있는게 아니라 여러 객체가 모여서 일을 한다.
  • 객체 간의 의사소통을 해야 한다.
  • 객체지향 프로그램 = 객체 + 객체
  • 객체간의 의사소통이 필요 : 메시지패싱 방법을 사용

→ 객체간 메세지 패싱을 위해 메소드를 통해서 의사소통을 한다.

ex) car class

각가 자신의 기능만 열심히 하다가 특정한 시점이 되면 다른 객체에게 위임시킨다.

  • 어떤 일을 하기 위해서는 자신 일만 하다가 특정 시점이 되면 다른 객체에게 위임시켜야 한다.

ex 1)

  • 각각의 멤버변수는 정보를 은닉하며 다른 객체의 정보를 바꿀 떄에는 위임한다
    • 경찰은 총을 안다(연관관계)
    • 총을 쏠 때만 잠깐 안다(의존관계)

Ex 2)

식당에서 주문하는 상황을 시뮬레이션

  • 맴버변수는 정보은닉하고 객체는 자신의 일만 하며 다른 객체에게 위임해야 한다.

DTO : 객체로 넘겨야 한다

(제일 중요)객체는 혼자 일하지 않는다.

Ex) 고객이 계좌 출금하는 시뮬레이션

Untitled

sequence diagram(순차도)

일의 순서를 순차적으로 나타낸다

얘는 객체 안에서 혼자서 일어나는 것이 아니라 객체 간의 상호작용을 보기 위해 그리는 것

콜론 뒤에는 타입이 오며 앞에는 실제 이름이 온다

  • 실제 일은 클래스가 아닌 객체가 한다, 클래스는 객체의 타입이므로 일을 하는 것이 아님. 그냥 개념
  • 0원이고 키값은 이름이 될 거기에 홍길동만 적어서 메세지로 보냄 -> 은행직원은 무조건 일을 해야 함, 박스는 일을 의미 -> 그 일을 하다보면 계좌타입의 계좌가 만들어질 것
  • 원래는 시나리오마다 sequence를 따로 그려야 하지만 지금은 4개 같이 그림

은행에는 많은 정보가 있는데 은행직원은 홍길동 계좌에 1000원을 넣어줘야 하고 이 일을 위해 홍길동 계좌를 찾아야 한다. 모든 고객의 정보 중에서 홍길동을 찾아야 하는 것 키값으로 찾은 후 홍길동 계좌 타입인 계좌에 1000원을 넣어줘야 한다.

  • 은행직원 클래스가 필요하며 해야하는 기능을 찾을 수 있다
    • 들어오는 화살표는 직원이 해야 하는 일,메소드 : 새계좌 만들고 입금하고 출금하고 조회하는 기능을 함
    • 최소한 고객에게 4가지 서비스를 해야 하기 때문에 메소드로 반드시 4가지 기능을 가지고 있어야 한다.
  • 계좌 역시 4가지와 매개변수 찾을 수 있고 메소드 찾을 수 있다
  • 더 중요한 것 ! : 은행직원은 새 계좌를 만들다보면 나가는 화살표가 존재 -> 특정 시점에서 위임을 해줘야 함

⇒ 클래스의 구조 + 어떤 일을 할 때 다른 객체와 어떻게 일을 하는지 : 클래스 다이어그램을 그릴 수 있다

  • 액터는 개발 바운더리가 아님, 사용자나 사용하는 외부 시스템 boundary가 아니다.

액터는 개발하는 게 아님

다른 객체의 데이터를 쓰려면 위임시켜야 한다

ex 3) 은행 시스템

객체는 서로 상호작용하며 각자 자신의 데이터만 조작하고 다른 객체의 데이터를 조작할 경우 위임시킨다.

상속(inheritance)

  • 인터페이스와 구분해야 한다
  • 상속은 is-a, isa kind of이다
  • 한 클래스가 다른 클래스의 일반화된 개념인 경우 성립
  • superclass-subclass

다 만들 필요 없이 코드를 재사용해서 상속받아 추가되는 기능과 속성만 추가하면 된다

프리젠테이션 1)

Untitled

upcasting은 is a 관점이기에 가능

컴파일 타임에는 동물이라서 호출가능하지만 런타임에서는 사람이라서 오버라이딩된 사람의 함수가 호출됨

하지만, 사람만이 가지는 함수는 호출 불가 → downcasting으로 실제로 사람을 가리킬 수 있을 때만 사용

Q. 사람 객체를 굳이 안맞는 타입에 넣는 이유?

여러 타입을 하나의 타입으로 볼 수 있기 때문 : 다형성

객체지향이 아닌라면 if else가 계속 들어가야 한다.

즉, 메세지를 하나만 보내도 알아서 오버라이딩된 게 불려 객체들이 다양하게 반응할 수 있다

✅다형성(polymorphism)

: 여러 형태를 가지고 있다(여러 형태를 받아들일 수 있다)

동일한 요청에 대해서 서로 다른 방식으로 응답할 수 있는 능력

  • 현재 코드를 변경하지 않고 새로운 클래스를 쉽게 추가할 수 있음

→ 유지보수할 수 있어 변경에 강한 설계를 할 수 있다

upcasting downcasting 중요!!

ex 4)

Untitled

추상클래스(abstract class)

new를 이용하여 객체를 생성하지 못하고 concrete class가 아니다

추상적인 개념만을 가지고 있는 클래스(바디가 없음)

추상메소드를 가지는 클래스

Q. 왜 추상클래스를 만드는가?

A. 추상메소드를 구현할 경우 그 클래스는 무조건 오버라이딩을 해야하므로 모두 구현을 안했다면 오류가 생기므로 구현했는지 확인이 가능하다. 즉, 강제력이 가능하다

개념 자체가 추상적일 경우 메소드 정의를 내릴 수 없기에 추상메소드로 두기도 한다.

Q. abstract을 안만들고 그냥 {}만 넣어서 빈 메소드로 만들어도 되지 않을까??

A. 구현했는지 확인하기 위해, 구현을 하게끔 강제력을 행세할 수 있다, 구현 안하면 컴파일 에러남

  • superclass이지만 개념이 추상적이면서 메소드를 반드시 구현해주고 싶다면 추상클래스로 만들면 된다.

ex5)

shape- triangle, square 예시

  • triangle,square은 shape이라는 추상클래스를 구현해야 하며 즉, calcArea와 getName을 오버라이딩해야 한다.

✅인터페이스(Interface)

다형성의 일종으로 인터페이스가 나왔는데 인터페이스는 하드웨어 모방에서부터 나오게 됨

→ 갈아끼워도 다른건 영향을 받지 않는 것

하드웨어는 나오면 무조건 인터페이스를 정함. 규칙을 정한 후 그 인터페이스에 맞춰서 돌아가고 싶으면 그 인터페이스만 지키고 나머지는 공개안해도 됨!

단지 본체와 돌아가려면 서비스를 사용하는 본체에서도 구현은 알 필요가 없고 인터페이스만 있으면 된다!

개념적인 인터페이스가 있어야 한다

  • 인터페이스는 계약(contract)이다
  • 인터페이스는 사양(specification)이다
  • 서비스를 명시하는데 사용되는 행위의 집합이다.

ex 5)

Untitled

Untitled

문법적으로는 superclass와 동일

cf. 추상클래스은 문법과 개념적인 부분을 빼놓고는 부모클래스와 같으므로 is a 관계이다.

  • 인터페이스는 경계면, 접촉면

    ex) 컴퓨터는 복잡하지만 사용자가 사용하고 싶다 → 사용자가 접촉할 수 있는 경계면을 인터페이스라고 한다

    → 일일히 건들 필요없이 경계면을 이용해서 접속한다

    ex) 헨들과 브레이커도 인터페이스의 일종

cf.소프트웨어를 하드웨어처럼 해보자!

인터페이스 기준으로 하드웨어는 구현하는 축이 있고 사용하는 축이 존재, 구현하는 측은 마음대로 하지만 약속은 지켜야 한다. 서비스를 하는 구멍(인터페이스)을 만들어야 한다. ex) 메인 보드에 있는 포트들이 다 인터페이스임, 마우스를 사용하는 측이 컴퓨터 본체, 버튼이나 휠감지를 구멍이 있어서 만드는 축에서는 그 약속만 지키고 어떤식으로 만드는지는 상관 없음

  • 인터페이스는 구체적인 사용방법이나 구현방법 알 필요 없이 그때의 약속, 니가 쓰고 싶으면 이 약속 지키면 돼 나는 이 서비스를 제공해줄건데 이런 함수를 호출하면 돼, 함수의 api를 공개. 이게 인터페이스, 함수의 본체를 보지는 않음, 시그니처(헤더)만 보여줌
  • 구현했는데 서비스 쓰고 싶으면 내가 제공해주는 헤더에 맞춰서 써 그럼 제공해줄게!

ex) printf함수, 우리는 시그니처만 본 것. 구현하는 본체는 상관없이 사용하는 것, 구현은 알아서 화면에 보여줄 것

  • 인터페이스는 서비스를 제공하겠다는 스펙, 약속 - 이런 서비스를 제공할 떄는 이런 인터페이스를 제공할게, 니가 약속을 지킨다면 내가 무조건 구현해줄게
  • 문법적으로는 부모클래스 역할을 하지만 사용할 때에는 이런 개념으로 써야 함 서비스를 제공하는 입장에서는 나는 이런 인터페이스를 제공할꺼야 니가 이걸 호출하면 나는 구현해줄꺼야
  • 인터페이스는 be able to 관계일 때 쓰는 것(나는 할 수 있어)
  • 자바에서는 추상클래스이든 인터페이스든 부모클래스이기에 모두 상속과 다형성이 적용됨. 하지만 설계 시 객체지향에서는 인터페이스와 추상클래스의 개념이 따로 존재

상속 vs 인터페이스

상속(추상클래스 포함)은 is a 관계이고 인터페이스는 be able to(can) 관계이다.

하지만 문법적으로는 부모 클래스 역할을 하기에 upcasting,downcasting,다형성 모두 적용된다.

호출한 쪽에서는 인터페이스만 보인다. 구현은 안보임

인터페이스 실현(interface realization)

인터페이스에 정의된 서비스 즉, 행위를 구현하는 것

Oop.example 6)

음식점을 만드는 도메인을 만들거임

Untitled

음식점에서는 요리를 주문하고 머 이런걸 할건데 우리 도메인에서 요리하고 싶으면 icook을 지켜!

고용해서 일을 시키는 측에서는 makeRice이런걸 호출해서 쓸 것

첫 번째 방법

중국요리사로 바꿀려면 코드를 수정하여 다시 컴파일해야 한다.

올바른 구현은 구체적인 구현체를 몰라야 한다.

문법적인 인터페이스가 아닌 개념적인 인터페이스를 사용해야 한다!!

두 번째 방법

객체를 생성하지는 않고 선언만 해서 사용→ ICook인 정보만 알기 때문에 koreanCook과 ChineeseCook모두를 받을 수 있다

결합도와 응집도

  • C언어에서는 하나를 바꾸면 다른 것도 바뀌니까 결합도가 높음. 하지만 응집도도 높은 편. 하나의 일만 하는 것
  • 객체지향으로 응집도는 클래스로 묶으면서 높으면서도 다른 클래스 끼리의 결합도는 떨어짐

서비스를 사용하고 싶은 축에서는 구체적인 클래스말고 항상 추상적인 것만 알아야 한다

인터페이스가 아니라 추상클래스 써도 되는데 개념을 써야 한다는 것!

결합도 높다 -> 다른 것에 영향이 높다! ->no

다른 말론는 명세(스펙)와 구현을 분리해야한다- 이게 소웨공의 기본

명세- 인터페이스

구현 – 구체적인 클래스