2. 객체지향 분석과 디자인

프로세스가 있고 메소드와 지원하는 도구가 있는데 메소드에 따라서 방법론이 달라짐

제일 많이 쓰는 방법론이 객체지향 방법론이기 때문에 기준은 객체지향 방법론을 사용

cf. Head first objet -머시기를 참고해서 제작한 Ppt

  • 우리의 고객은 결국 사람(중요)

→ 고객들로부터 원하는 것이 무엇인지 찾아내는 것이 매우 중요

→ 고객이 원하는 것을 개발해야 한다

  • 당장의 문제를 해결하는 것 뿐만 아니라 고객이 미래에 원할 변경까지 우리는 미리 예견하고 있어야 한다

Ex) 릭의 기타 가게

  • 기타의 재고관리. 프로그램이고 기능은 고객이 원하는 기타를 검색하면 있는지 없는지 가격은 어느정도인지 알고 싶다!

Version 1

guitar와 inventory의 클래스 생성

각각 속성에 대한 Setter와 getter를 생성 -> getter만 있고 setter는 하나밖에 없음. 다른 정보는 바뀔 수 없고 가격만 바뀜

인벤토리는 기타를 배열로 가지고 있으므로 list로 가짐

인벤토리의 가장 중요한 일은 기타를 추가해줘야 하고, 시리얼 넘버를 검색하면 기타를 알려주고, 가장 중요한 기능인 기타를 주면 검색할 수 있도록 addGuitar, getGuitar, Search 기능 구현

좋은 소프트웨어

  • 고객을 만족시켜야 한다. 고객이 원하는 기능을 수행해야 한다
  • 고객이 이상하게 사용하더라도 소프트웨어가 멈추거나 예상치 못한 결과를 나타내지 않아야 한다
  • 잘 설계되어있고 잘 코딩되어있고 유지보수와 재사용, 확장이 쉬워야 한다.

좋은 소프트웨어를 만들기 3단계

1) 고객이 원하는 기능을 수행해야 한다

  • 요구사항을 잘 수집하고 분석하는 것이 필요

2) 객체지향 기본원리를 적용하여 sw를 유연하게 해야 한다

  • 중복코드를 찾고 객체지향방식대로 했는지 확인

3) 유지보수와 재사용이 쉽도록 디자인해야 한다

  • 디자인패턴과 원리를 적용하여 나중에 다시 사용할 수 있게 해야 함

1-1.문제점

  • 최소한 기타를 잘 찾아야 하는데 그 기능이 만족하지 못하므로 문제가 있음

    ex) fender ≠ Fender

    문자열을 잘못 넣게 되면 못찾게 됨 -> 첨에 누군가가 넣게 되는데 잘못넣으면 확인할 길이 없다

→고객의 요구사항을 잘 수집해서 원하는 걸 무조건 하게 해줘야 한다!

  • 새로운 요구사항

: 검색을 여러개 할 수 있도록 배열을 반환형으로 하게 한다

1-2. 해결방안

  • 문자열 비교를 최소화, 기준을 하나로 맞춘다. ignorecase 사용
  • 문자열보다는 상수(enumerated type, 열거형 타입)를 쓰는게 좋다.

    스펠링이 틀리거나 잘못 타이핑한 경우 컴파일러가 이를 찾아줌, 타입의 안전과 값의 안전을 보장

  • search 함수의 반환형이 배열로 되도록 변환

Version 2

2-1. 문제점

  • 시리얼 넘버와 가격은 고객은 모르는 정보
  • 기타마다 고유정보(앞판 소재, 뒷판 소재, 제조사 등등 )가 존재

ex) 삼국지 정보는 하나지만 출판사, 출판년월인 고유정보지만 낱낱을 구별하기 위한 일련번호가 다름

ex) 서점도 똑같은 책이 있지만 실제 책은 10권이 있으므로 그걸 구별하는 시리얼넘버가 있는데 파손된 정도에 대해서 가격이 다를 것

  • 물건들마다 변하지 않는 고유정보가 있고 낱낱의 것은 구별해야 하기 위한 정보가 존재
  • 고객들은 낱낱의 정보는 모름

ex) 시리얼넘버와 가격은 모름

⇒ 고유정보와 낱낱의 객체를 나타내는 정보가 같이 나타내어 고객은 고유정보만 가지고 찾는데 필요없는 것도 넣게 됨

2-2. 해결방안

  • 객체는 기본적으로 하나의 역할만 해야 하므로 분리해서 설계하는 것이 기본

ex) 고객은 고유정보만 나타내는 것만 찾는데 고유정보와 낱낱의 정보를 같이 가지게 기타 클래스를 만들었기에 null을 넣게 됨

기타 스펙 : 고유정보

실제로 존재하는 것은 기타

캡슐화 개념

: 관련있는 것을 묶어내는 것, 프로그램 일부 정보를 다른 부분으로 부터 보호

  • 프로그램 중에 변화 가능성이 높은 부분을 그렇지 않은 부분으로 부터 분리하여 캡슐화한다.
  • 기타의 일반적인 속성(고유 속성)을 기타객체로부터 분리함

    → 변하는 부분과 변하지 않는 부분을 분리하는 것

  • 기타 스펙은 실제 존재하는 기타를 설명

ex) 서점에 10권의 삼국지가 있다면 고유정보를 바꾸려면 10권 다 바꿔야 하는 것, 근데 나눠놓으면 스펙만 바꾸먼 된다

위임예제1

경찰이 범인을 만날 쓸 때 총 쏘는 것을 시뮬레이션 할 것

간단하게 하기 위해 경찰과 총으로 표현, 추상화해서 객체로 바꿈

총이 갖는 속성은 총알, 총을 쏘는 것은 메소드

  • 총기번호, 총종류, 총 가격 등이 있지만 우리가 하려는 것은 범인에게 총을 쏘는 것이기 때문에 총알을 갖고 있어야 한다.

도메인 : 주어진 환경

  • 경찰이 갖고 있는 속성에는 나이, 이름등등이 있지만 여기서 중요한 속성은 수갑의 수와 총이 필요

예시 1의 문제점

총은 경찰이 가지고 있고 총알은 총이 갖고 데이터이고 경찰은 피스톨을 가지고 있지만 총을 내보내는 것은 경찰임.

  • 경찰이 총알을 던지는 격, 경찰의 총의 역할을 하는 것
  • 총알의 수가 경찰의 메소드에 영향을 받게 됨

→ 총알의 책임은 건이 책임져야하고 수갑과 총만 책임져야 함

즉, 총한테 총알을 내보내라고 해야 한다

  • 위임한다 : 총에게 총알을 던져라고 해야 한다!

Q. 경찰이 총알을 왜 접근할 수 있었을까??

A. 접근자가 디폴트니까 같은 패키지면 접근가능하기 때문, 근데 경찰은 프라이빗

정보은닉 – 정보를 공개하면 안되는데 총은 지금 보여주게 되는 것

예시 1의 해결방안

  • 5라인을 private이라고 바꿔야 한다
  • 그리고 총의 기능을 할 수 있는 함수가 필요
  • Bullet—;로 경찰이 접근하는 것이 아닌 shoot()를 호출해야 한다.

자바에서 함수가 아닌 메소드라고 하는 이유는 객체의 데이터를 바꾸는 수단이기 때문

메소드로 할 수 있게, 니 데이터는 너가 처리해 : 위임

  • 객체는 기본적으로 한가지 역할만 하고 그 역할에 해당하는 데이터만 가지고 있고 외부에서 조작하기 위해서는 메소드가 필요
  • 외부에서 총알을 내고 싶으면 메소드가 만들어서 서비스를 해야 한다. 메소드는 서비스하는 개념
  • 객체지향에서는 위임이 중요

C는 자기의 일만 해야하므로 다른 일은 함수한테 대입하고 객체지향은 객체로 확장된 것

바뀐 예시1

  • 경찰의 건이 멤버변수에서 사라짐
  • 경찰은 총을 모른다.-> 총을 쏘려면 총을 받아서 쏜다.

이전은 맴버변수로 항상 알고 있다는 것이고 지금은 총을 쏘는 기능에는 건이 있어야 하니까 매개변수로 건을 받아서 슛하라고 위임시키고 있음

1) 피스톨객체에 총이 만들어지고 경찰이 만들어진 후에는 총을 맴버변수로 가지고 있고 경찰은 총의 존재를 이미 앎 -> 총을 바로 쏠 수 있고 수갑도 갖고 있으며 메인 메소드가 힙에서 사라질 것, 그 때 피스톨도 관계가 사라지게 될 것, 경찰은 건을 항상 알 고 있다

2) 경찰 객체 생성시 총이 있다는 것은 모름. P1과 pistol은 서로 모른다.

P1.shut()을 하게 되면 관계가 생기게 될 것 -> 매개변수인 pistol은 없어지고 그게 끝나면 P1과 Pistol은 모르게 된다.

  • 서로 알고 있는 시간이 다르다
  • 맴버변수로 알 고 있다면 시간대는 죽을 때까지 알고 있지만 후자는 shut안에서만 알게 됨
  • 맴버변수는 연관관계 매개변수로 갖고 있는 것은 dependency이지만 전자 자체는 관계가 깊어지는 것을 의미

cf. 이전의 예시같은 관계를 연관관계(맴버변수)라고 하고 후자는 매개변수(의존관계)라고 하며 상황마다 다르게 선택해서 사용하면 된다

위임예제 2

ex) 사과를 사는 상황을 시뮬레이션 할 것

  • 고객이 사과를 사는 상황인데 여기서 구성하는 객체를 구성하고 있는 과일을 파는 사람과 과일을 사는 구매자, 메인이 존재할 것
  • 판매자는 갖고 있는 속성으로 가지게 되는데 도메인에 따라서 맞는 속성만을 꺼낸다면 사과의 가격, 사과의 수, 내돈을 가지고 있음

saleApples : 사과를 사는 고객은 돈이 있어야 하니까 돈이 필요하고 사과를 사게 되면 사과를 갖게 되니까 갖고 있음.

buyApples : 사과는 판매자가 갖고 있고 판매자의 존재를 모르므로 맴버변수로 보내며

  • Buyer는 사과를 사는 기능이고 serller에게 달라고 위임해야 함

셀러를 만들고 바이어를 만들면 셀러와 바이어는 서로 모름 -> 바이어에게 과일 사와 -> 매개변수로 받아서 사과를 팔면 다시 관계가 없어짐

위임

: 한 객체가 어떤 일을 할 때 직접 다 하지 않고 다른 객체가 그 일을 하도록 하는 것

  • 보통 객체가 어떤 일을 하려면 위임하는 경우가 많음. 혼자 일하는 경우는 적음
  • 시퀀스를 그리면 위임이 엄청 많은 경우가 많음
  • 객체는 자신의 일만 해야하며 다른 객체가 일하게 하려면 위임해야 한다

위임의 장점🖐🏼

  • 코드의 재사용성이 좋아진다
  • 유지보수가 좋아진다
  • 각 객체가 자기 자신의 기능만 하면 되고 한 객체의 기능을 여러 곳에 분산할 필요가 없다.

Q.위임을 하지 않을 경우 문제점

A. 만약에 건 클래스에 numofbullet이라고 한다면 위임을 하지 않으면 메소드 헤더는 유지시키면서 기능을 바꿀 수 있는데 헤더를 잘 설계해야 한다 이게 api에 공개되는 부분 바디는 안보임

맴버변수로 접근하게 되면 타입이 바뀌면 다른 클래스도 바꿔야 한다. 근데 shoot기능이 따로 위임이 있따면 그 클래스만 보면 됨

Version 3

3-1. 문제점

  • 서치라는 기능은 인벤토리가 가지고 있는 기능, 기타스펙한테 getBuilder 위임한 것이라고 볼 수 있지만 근데 비교는 인벤토리 클래스 안에서 하고 있음
  • Get을 호출하는 이유는 단순히 자기자료가 아니기에

기타 스펙에 새로운 속성을 추가한다면??

  • 추가하게 되면 생성자도 바뀌고 getter도 필요함 근데 추가한 클래스 말고도 search에서도 numstring이 같은지 확인해야 한다, 기타의 생성자 또한 추가된 생성자를 포함하여 수정되어야 하며 인벤토리의 addguitar도 바뀌어야 한다.

(정리) 새로운 속성이 기타스펙에 추가되거나 메소드가 바뀔 때 마다 search 메소드도 같이 변경되어야 한다.

→ 위임을 쓰지 않아서 생긴 문제

3-2. 해결방안

새로운 속성이 추가 될 때마다 두개의 다른 클래스를 수정해야 하므로 재사용이 쉽지 않다

→ 새로운 속성을 추가해도 다른 부분에 영향을 끼치지 않도록 프로그램 구조를 재조정

기타스펙을 인벤토리에서 분리하여 캡슐화하여 비교 부분을 처리하여 위임해야 한다

  • 생성자에서도 기타 스펙을 받아서 초기화야해야 한다.
  • search함수에서 기타 스펙에게 객체를 비교하도록 위임

Data transfer object : 데이터를 전송하는 애들, 매개변수 시 낱개로 옮기지 말고 데이터를 옮겨야 한다.(DTO)

좋은 소프트웨어의 3단계(OOAD)

1) 고객이 원하는 기능을 수행

2) 객체 지향의 원리를 적용

  • 캡슐화 : 속성 추가가 쉬워진다
  • 위임 : 객체 간의 의존성을 낮춘다
  • SRP(single responseiblity principle) : 클래스는 하나의 책임만을 가져야 한다

3) 유지 보수와 재사용이 쉬운 디자인

첫번쨰는 사용자가 무조건 원하는 기능을 제공해줘야 하며 소프트웨어는 계속 변경이 일어나므로 변경에 유연하게 설계해야 한다.

C를 구조적으로 잘 짜도 유연하게 짤 수 있지만 재사용의 단위가 함수이므로 객체를 재사용하는 자바가 범위가 크다

유지보수하기 쉽게 작성해야 한다.

1->2에서 사용자의 요구가 바뀌고 고객도 자신이 원하는 게 먼지 모른다