java 자바의 꽃, 객체2
객체 지향 프로그램이란
객체 지향 프로그램 | 현실 세계의 모든 사건(event)을 객체와 객체의 상호작용에 의해 일어난다는 세계관을 프로그램 만들 때 이용하여 새로운 세계를 창조하는 방법론이다. 그런데 객체를 설계하기 위해서는 복잡한 현실 세계를 그대로 반영하기에는 너무 방대하고 복잡하다 그래서 우리는 현실 세계에 프로그램의 목적에 맞게 단순화 하려고 추상화라는 기법을 적용하게 된다. |
객체의 재사용성이 증가하면 장점 | 1. 중복 작성되는 코드를 줄일 수 있으며 2.오류 발생 가능성을 감소시키고 유지보수성을 증가시킨다. |
추상화 |
유연성을 확보하기 위해 구체적인 것은 제거한다는 의미 프로그램에서 필요한 공통점을 추출하고, 불필요한 공통점을 제거하는 과정 |
Car | 차를 움직이는 사람 | 움직일 수 있는 프로그램 |
처음에 차를 만들어 보자
차는 시동을 켜거나 끄거나 앞으로 가거나 멈추거나 하는 행동이 걸려 있는지를 확인 해야 한다.
그래서 메소드 간에 서로 공유해야 하는 속성이 존재한다.
그 속성을 필드에 작성해 보자
private boolean isOn;
private int speed;
처음에는 시동이 꺼진 false 상태를 정해야 해서 boolean형태로 선언하였다.
그리고 초기에는 속도가 0인 상태를 염두해두고 선언해야 한다.
1. 시동을 켠다.
2. 간다.
3. 멈춘다.
4. 시동을 끈다.
로 할 수 있다.
1. 시동을 켠다
시동이 걸려있는 상태인 경우에는 할 일이 없고, 시동이 걸려있지 않은 경우에만 시동을 걸도록 한다.
public void startUp() {
if(isOn) {
System.out.println("이미 시동이 걸려있습니다.");
} else {
isOn = true;
System.out.println("시동을 걸었습니다. 이제 출발할 준비가 완료 되었습니다.");
}
}
2. 출발
밟을 때 마다 속도를 10km/h씩 증가시키도록 한다.
public void go() {
if(isOn) {
System.out.println("차가 앞으로 움직입니다.");
speed += 10;
System.out.println("현재 차의 시속은 " + speed + "km/h 입니다.");
} else {
System.out.println("차의 시동이 걸려있지 않았습니다. 시동을 먼저 걸어주세요.");
}
}
3. 차를 멈춘다. 차를 멈추고 시동을 꺼야 한다.
public void stop() {
if(isOn) {
if(speed > 0) {
speed = 0;
System.out.println("브레이크를 밟았습니다. 차를 멈춥니다.");
} else {
System.out.println("차는 이미 멈춰있는 상태입니다.");
}
} else {
System.out.println("차의 시동이 걸려있지 않았습니다. 시동을 먼저 걸어주세요.");
}
}
4. 차의 시동을 끈다. 달리는 상태에서 끌 수는 없으니
public void turnOff() {
if(isOn) {
if(speed > 0) {
System.out.println("달리는 상태에서 시동을 끌 수 없습니다. 차를 우선 멈춰주세요.");
} else {
isOn = false;
System.out.println("시동을 끕니다. 다시 운행하시려면 시동을 켜주세요.");
}
} else {
System.out.println("이미 시동이 꺼져있는 상태입니다. 시동 상태를 확인해주세요.");
}
}
이제 차에서 할 수 있는 행동은 다 했다. 그럼 이제 차를 운전하는 사람에게 집중을 해 보겠다.
차를 운전하는 사람은 간단하다. 상호 작용할 차의 클래스를 차를 운전하는 사람은 알고 있어야 한다.
알고 있다는 의미는 필드에 가지고 있다는 의미를 가진다.
차를 움직이는 사람은 간단하다.
사실상 우리도 실생활에서 쓸 때는 간단간단하게 만드는 것처럼 차운전자도 간단하게 작동해야 한당
1.차에 먼저 앉고(등록)
2.시동을 키는 버튼을 누르고
3.차를 엑셀을 밟아 출발하고
4.그리고 그냥 브레이크
밟아서 스탑 그리고 시동을 끄는 버튼을 누르기만 하면 된다.
제일 먼저 차를 등록한다.
Car car = new Car();
그리고 그 이후,
public 클래스에 운전자 설계도를 만들고 그 안에 멤버를 넣는다.
public class CarRacer {
Car car = new Car();
public void startUp() {
car.startUp();
}
public void stepAccelator() {
car.go();
}
public void stepBreak() {
car.stop();
}
public void turnOff() {
car.turnOff();
}
이렇게만 필드에 선언하면 가능하다.
이제는 운행할 수 있는 프로그램으로 가 보면 처음에는
카레이서를 등록해야 한다.
CarRacer racer = new CarRacer();
우리는 입출력 통해서 카레이서의 행동이 달라지는 프로그램을 만들어 볼 것이다.
while(true)문을 사용하여 무한반복 하도록 만들어 본다.
while문 안에 switch문을 넣어
case 1,2,3,4~쭉 가면서 실행되면 break가 되도록 설정 한다.
while(true) //무한 반복 루프 {
System.out.println("========== 카레이싱 프로그램 ==========");
System.out.println("1. 시동 걸기");
System.out.println("2. 전진");
System.out.println("3. 정지");
System.out.println("4. 시동 끄기");
System.out.println("9. 프로그램 종료");
System.out.print("메뉴 선택 : ");
int no = sc.nextInt(); //정수 자료형으로 입력받게 함.
switch를 통하여 각각 케이스들을 다 다르게 하여 실행하도록 만든다.
switch(no) {
case 1 : racer.startUp(); break;
case 2 : racer.stepAccelator(); break;
case 3 : racer.stepBreak(); break;
case 4 : racer.turnOff(); break;
case 9 : System.out.println("프로그램을 종료합니다."); return;
default : System.out.println("잘못 된 번호를 선택하셨습니다.");
}
이렇게 만들어 줘서 콘솔창에 찍고 계속하여 입력한다면 속도도 올라가고 사용자가 원하는대로 프로그램을 구동 시킬 수 있다.
이제는 캡슐화의 원칙에 일부 어긋나기는 하지만 매번 추상화를 하지 않아도 되는 객체도 존재한다.
행위 위주가 아닌 데이터를 하나로 뭉치기 위한 객체의 경우인데, 모든 필드를 private로 직접 접근을 막고, 각 필드 값을 변경하거나
반환하는 메소드를 세트로 작성하면 된다.
여기서 메소드는 설정자(setter)와 접근자(getter)들로 구성이 된다.
멤버
처음에는 취급하려고 하는 멤버들을 구상해서 필드를 작성한다.
private int number;
private String name;
private int age;
private double height;
private boolean isActivated;
설정자(setter) 작성 규칙
1.필드 값을 변경할 목적의 매개변수를 변경하려는 필드와 같은 자료형으로 선언
2.호출 당시 전달 되는 매개변수의 값을 이용하여 필드의 값을 변경
[표현식]
public void set필드명(매개변수) {
필드 = 매개변수;
}
public void setNumber(int number) {
this.number = number;
}
public void setName(String name) {
this.name = name;
}
...
접근자(getter) 작성 규칙
1.필드의 값을 반환 받을 목적의 메소드 집합을 의미한다.
2.각 접근자는 하나의 필드에만 접근하도록 한다.
3.필드에 접근해서 기록 된 값을 return을 이용하여 반환하며(void)쓰지 않음.
이 때 반환 타입은 반환하려는 값의 자료형과 일치시킨다.
[표현식]
public 반환형 get필드명() {
return 필드명;
}
public int getNumber() {
return number;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}...
그러나 하나 다른 것이 있는데 boolean의 접근자는 get으로 시작하는 것이 아니라 is로 시작하는 것이 관례적이다.
public boolean isActivated() {
return isActivated;
}
구동문
설정자 setter
MemberDTO member = new MemberDTO();
member.setNumber(1);
member.setName("유관순");
...
접근자 getter
System.out.println("회원번호 : " + member.getNumber());
System.out.println("회원명 : " + member.getName());
System.out.println("나이 : " + member.getAge());
...
캡슐화 원칙에 따라 작성했지만 실제로는 캡슐화가 의미 없을 정도로 필드명을 그대로 사용한 설정자와 접근자로 인해 캡슐화 효과가 없다. 그런데 데이터를 주로 다루는 객체의 경우 행위를 추상화하지 않고, 미리 모든 필드에 접근 가능성을 염두에 두고 작성해두는 관례로 인해 현재도 많이 사용되고 있다.