[개체지향] 개체모델링
개체 모델링
- 정답이없음
- 여러 번 다시 고치기가 쉬움
클래스 다이어그램
- 어떤 시스템에 있는 클래스들을 보여주는 다이어그램(diagram)
- 상태 동작 접근 제어자
- 관계(상속 컴포지션)
- 시스템의 정적인 구조를 보여주기에 적합
- 데이터베이스 설계할때도 비슷한것 사용
- UML(Unified Modeling Language)의 일부
UML : 시스템 디자인을 시각화하기 위해 만든 표준
종류 구조 7가지 동작 7가지
UML 이제 거의 안 쓰임 디자인 패턴: 주니어가 패턴을 잘못 적용하는 경우가 빈번
- ’-‘ : private
- ’+’ : public
- ’~’ : default
- ’->’ : 의존관계
ex 꽃에 물주기
꽃에 물을 매일줘야 평생 살수있음 물뿌리는 도구는 분무기 하루라도 물을 못받으면 죽음 그뒤 물뿌려도 안살아남
객체 : 화분과 분무기
분무기 class 명 WaterSpray
상태 : 현재 남아있는 물의 양
처음 생성될때는 0
private int remainingWaterInMl = 0;
public void setRemainingWater(int amountInMl){
this.remainingWaterInMl = amountInMl;
}
이때
- ~까지 채워야지 : set~
- ~ 채워야지 -> addWater()란 메서드가 더 적합
두가지 경우가 생길 수 잇음
public void addWater(int amountInMl){
this.remainingWaterInMl += amountInMl;
}
물뿌리기
메서드 이름
동작에 초점을 맞출 경우
- pull()
- press()
용도에 초점을 맞출 경우
- spray()
public void spray(){
this.remainingWaterInMl -= Math.min(this.remainingWaterInMl, 5);
}
void vs int ?
- 분무한 양을 반환하지 않더라도 확인 가능
- 직접 반환 가능
정답은 없으나 두 번째 방법에는 다음의 문제가잇음
- 메서드 시그내처만으로는 정확히 뭘 반환하는지 알기 힘듦
- 해서드가 하는 일이 너무 많다고 볼수도 잇음
- 따라서 void가 좀 더 좋다고 생각하나
- 두 번째도 흔히 사용
- 메서드 이름을 좀 더 명확하게 사용하는 방법도 있음
- int sprayAndGetUsedAmount(){…}
- 메서드 이름을 좀 더 명확하게 사용하는 방법도 있음
분무기의 다양함을 반영
color
brand
shape
getColor()
getBrand()
getShape()
추가 할 수 있으나.
사용하지도 않는 멤버 변수 메서드는 쓸데없는 유지보수 비용의 증가로 이어짐
코드는 필요한 시점에 추가.
실제 분뭉기에는 최대 용량이 존재
최대 용량을 추가하자.
- 분무기의 최대용량이 모두 동일한 경우
public class WaterSpray{
private static final int CAPACITY = 200; // 매직넘버도 있지만 상수형 변수가 좀더 좋은 습관
...
public void addWater(int amountInMl){
this.remainingWaterInMl += amountInMl;
this.remainingWaterInMl = Math.min(this.remainingWaterInMl, CAPACITY);
}
...
}
클래스 다이어그램
상수는 표현하지 않음(멤버 변수에 속하지 않음)
- 분무기마다 용량이 달라질 수 있는 경우
공장에서 찍어 나오면 그 뒤에 용량이 바뀌지 않음 -> setter가 없어야함
private int capacity
public getCapacity()...
- 가득 채워야겠다 동작 추가
메서드명은 fillUp()으로
public void fillUp(){
this.remainingWaterInMl = capacity;
}
수도꼭지가 필요하지 않을까
문제점
- WaterSpary에 여전히 addWater()같은 public함수가 필요
public class Faucet{
...
public void addWaterTo(WaterSpray spray,int amount){
spray.addWater(100);
}
...
}
- 때에 따라서는 패키지 접근 제어자로도 가능.(단 같은 패키지 안에 있을때만)
진정으로 Faucet 클래스가 필요하진않다. 필요한것만 만들자.
화분
살았는지 죽었는지 기억할 변수가 필요
class FlowerPot{
boolean alive = true;
boolean isAlive()
}
boolean형의 getter는 is를 많이 씀 alive는 setter존재 X
minDailyWaterInMl : 매일 필요한 최소 물의 양 꽃마다 다른양이 필요하니 생성자를 통해 초기화 getter 추가 setter X
물을 주기위해
addWater(int amountInMl){
if(amountInMl < minDailyWaterInMl){
alive = false;
}
}
문제점
- 하루에 받은 총 분무량을 기억
- 하루가 지났음을 알아야함.
private int dailyWaterReceived = 0;
public void addWater(int amountInMl){
dailyWaterReceived += amountInMl;
}
public void liveAnotherDay(){
(dailyWaterReceived < minDailyWaterInMl){
alive = false;
}
dailyWaterReceived = 0;
}
두 클래스의 문제점
- 클래스 사이의 상호관계가 없음.
WaterSpray.spray() FlowerPot.addWaater(int)
- 두 메서드 사이의 자료형인 int를 사용
해결방법
- 분무기를 화분에 대고 뿌린다.
- sprayTo(FlowerPot)
-> 호출자 코드가 간편해짐
public void sprayTo(FlowerPot pot){
int amountToSpray = Math.min(this.remainingWaterInMl, 5);
pot.addWater(amountTospray);
this.remainingWaterInMl -= amountToSpray;
}
- 분무기를 줄테니 알아서 뿌리세요
FlowerPot의 addWater()를 변경
public void addWater(WaterSpray spray){
int water = spray.getRemainingWater();
spray.spray();
water -= spray.getRemainingWater();
dailyWaterReceived += water;
}
- 정답은 없음.
- 1번이 익숙하고 2번은 뭔가 어색
그러나 2번이 좀더 개체지향적임
OO세계의 물체는 어느 정도 자기 주관을 가진 주체 개체란 용어가 더욱 적합
Cup을 쓰고싶은데?
추상 클래스에서 다룸
분무기를 분리.
머리와 몸통으로 분리
유연성높은게 좋은게 아닌경우가있음
여러개 쪼개면 파일을 넘나들수잇음
코드 유연성은 양날의 검.
유연성이 높으면 성능 낮음 가독성 낮음 재사용성 높음
공부 가이드 라인
- 기본자세가 더 중요
- 읽기 명확한 코드가 가장중요
- 실수를 저지르기 어려운 코드 만들기
- 문제를 해결하는 코드 만들기
- 문제가 생기면 디버깅 하기
- 필요에 따라 유연성을 키우는 법을 배워 나가기
사용성 높이기
분리한것의 문제점
- 머리와 물통을 따로 만들어야함
해결점 : 규격 정하기
생성자 추가 두 열거형을 인자로 받음
- SprayHeadSpeed
- BottleSize
public enum SprayHeadSpeed{
SLOW,
MEDIUM,
FAST
}
public enum BottleSize{
SMALL,
MEDIUM,
LARGE
}
public WaterSpray(SprayHeadSpeed speed, BottleSize size){
switch (speed) {
case SLOW:
this.head = new SprayHead(1);
break;
case MEDIUM:
this.head = new SprayHead(5);
break;
case FAST:
this.head = new SprayHead(50);
break;
default:
assert (false) : "Unrecognized " + speed.getClass().getName()+ ": " + speed;
break;
}
switch (size) {
case SMALL:
this.head = new SprayBottle(10);
break;
case MEDIUM:
this.head = new SprayBottle(50);
break;
case LARGE:
this.head = new SprayBottle(150);
break;
default:
assert (false) : "Unrecognized " + speed.getClass().getName()+ ": " + size;
break;
}
}
//main
WaterSpray spray = new WaterSpray(SprayHeadSpeed FAST,BottleSize.SMALL);
spray.getBody().fillUp();
- 분무기에서 곧바로 분무를 못함
SprayBottel에 갔던 메서드들 WaterSpray로 복귀 head혹은 body로 호출 릴레이;