본문 바로가기
비전공자의 코딩 일지/학원 수업 정리

코딩 학원 12일차 ( Java 객체 지향, Pattern)

by Hoder2 2022. 6. 22.

오늘 수업 도중 갑자기 Java의 역사 얘기를 해주셨다.

Java는 사실 커피 이름이라는데 Java 만든 애들이 커피 마시면서 만들다가 오우 자바~! 해서 자바랬던가..?

여튼 그래서 우리가 여태 만들던 이 클래스를 Java Bean이라고도 부른단다.

Eclipse에는 이렇게 귀여운 커피콩 아이콘도 있다.

또 Java spring이 왜 spring(봄)이 되었냐면

Java - JSP - EJB - spring 순으로 나왔는데 EJB가 더럽게 어려워서 겨울이 지나고 봄이 왔다 하여 spring이 되었다는 말이 있단다. 잡담은 여기까지 하고 복습을 해야겠다.

 

강사님이 실제로 받은 생일 선물이 있는데 이걸 객체지향으로 정리하고 싶으시단다.

 

부드랩플러스고기, 부위 부채살, 700g, 종로에 있는 강사한테 받음 - 고기

코코도르 디퓨저, 리프레싱에어 향, 강사지망생1에게 받음 - 디퓨저

이 정도는 이제 지겨울 정도다.

근데 이 강사지망생 1은 잘 모르는 사람이라면서 그의 해당하는 객체 d를 잘 모르는 사람으로 바꿔보라 하셨다.

이게 강사님 화면에선 Main 클래스를 다른 패키지에 만들어서 오류가 나는데 내껀 그냥 한 패키지에 다 때려 넣었더니 오류가 안 난다. 원래는 빨간줄이 그어져 있는게 정상이다.

 

-접근제어자/접근지정자[access modifier]

 

객체 클래스 안에 있는 것들을 외부에서 가져갈 수 있게 할 것이냐 없게 할 것이냐를 정하는 것이다.

종류는 아래 처럼 4가지고 책에 나온 기능에 의하면 아래와 같다.

 

public : 접근 제한이 전혀 없다. 어디서든 접근 가능.
protected : 같은 패키지 or 패키지는 다르지만 상속관계가 있는 하위클래스인 경우
friendly/default : 같은 패키지에서만 가능. (아예 안 쓰면 이게 default다.)
private : 외부 접근 불가.

이렇게 다른 패키지 다른 클래스 상속관계가 전혀 없는 2개의 클래스를 만든다.

Test를 Test2에서 객체로 생성하고 위의 것들로 변수를 쓰면 public을 붙힌 a 빼고는 오류가 발생한다.

Test 3를 같은 패키지에 생성 해주고 위의 예시와 같이 만들면 같은 패키지이기에 외부 접근이 불가한 private 빼고는 다 가능하다.

Test4를 Test2에 있던 패키지에 만들고 Test를 import한 뒤 상속관계로 만든다.

c, d는 다른 패키지이기에 안 되는게 맞지만 b 같은 경우 책 내용에 의하면 상속관계이기에 Test의 멤버변수 b를 가져올 수 있어야 한다. Java로 직접 개발 해본 사람들만 알 수 있는 유명한 버그란다. 

결론은 책 갖다 버리란다. "물론 이론적으로는 맞지만 과연 책을 쓴 사람들이 전문가가 맞는가?" 라고 하셨다.

아무튼 결국 protected는 default와 다를게 없다. 그리고 멤버변수 앞에도 public 등을 상황에 따라 쓸 수 있다.

 

이번엔 홍길동 나이 20인 사람을 만들고 나이를 입력 받아서 변경 가능하게 만들어보라 하셨다.

scanner를 넣고 값을 받을 변수 선언 후 h 객체의 값을 입력 받은 값으로 저장한 뒤 정보 출력인데 패키지가 다르기 때문에 h.age를 불러 올 때 오류가 난다. 그렇기에 Human 객체의 멤버변수 age 앞에 public을 붙혀주어야 한다.

어 그럼 어차피 멤버변수 만드는 이유가 여기저기서 써먹으려고 하는건데 왠만하면  public을 먹이면 되겠다라고 생각하면 잘못된 거란다. (필자도 '어? public이 개꿀이잖아?' 라고 생각하긴 했다.)

냅다 콘솔창에 -11 음수를 입력하시더라.. 나이가 음수인 사람이 어디있냐면서 말이다.

 

지금처럼 public을 써서 외부에서 직접 접근 가능하게 해놓으면 잘못된 정보가 들어갈 수 있다. 그래서 public을 아무 때나 남발하면 회사가서 혼난단다.

아무튼 위와 같은 상황을 방지하기 위해(데이터를 안전하게 취급하기 위해) 캡슐화(encapsulation)라는 것을 한다.

 

-encapsulation(캡슐화)

 

1. 멤버변수는 private로 무조건 잠궈서 외부에서의 직접 접근을 차단한다.

2. 그 변수에 접근 가능한 통로를 하나 파준다.

3. if로 원치 않는 수를 입력 하는 것을 방지하기 위한 안전장치를 만든다.

4. 이렇게 적으면 오류 없이 만들어놓은 안전장치를 통해 나이 변경이 가능하다.

그러니까 이제 클래스에 들어가는 멤버변수는 private를 그냥 무조건 붙히라 하셨다.

그리고 통로 시리즈는
setName = 값 바꿀 때 쓸 거
getName = 값 가져올 때 쓸 거
이 두가지가 있는데 setter getter라고 불린단다.


이 둘도 마우스 우클릭 후 source에 보면 generate setter getter가 있다.
이것도 오버로딩 생성자 단축키 처럼 직접 단축키 셋팅을 해준다. (강사님은 ctrl + shift + s로 하신단다.)

이것이 최종적인 클래스의 기본형태이다.

객체 생성 후 값을 바꿀 때는 set(Address)

(전체 값이 아닌 단일 값만) 가져오고 싶을 때는 get

 

이번엔 식당으로 해보자고 하셨다. (클래스 부분은 너무 뻔하고 길이만 겁나 길어져서 캡처를 포기했다.)

식당이라는 상위 클래스를 만들고 라멘집과 우동집을 하위 클래스로 상속 시켜서 소스를 적었다.

근데 이 객체들의 정보가 출력되는 순서를 바꾸고 싶어서 super는 지워서 포기하고 하나하나 다시 쓰려는데

오류가 발생한다.

상위 클래스의 멤버변수 name이 private라서 그런 것일 텐데 그럼 왜 super는 됬냐고..

접근제어자 판정기준이 상속상황을 고려 하지 않는다. 강사님도 이건 이해가 안 간다 하셨다.

(이상한 판정들을 어떻게 해서든 이해해보려고 하는 사람이 강사님이시다.)

 

그럼 순서 바꾸는걸 포기해야하나?

그냥 getter로 가져오면 된다.

 

이번엔 자기 자신의 객체를 만들어서 소개를 해보란다.

신나게 멤버 변수를 냅다 여러개 썼더니 밑에 소스가 왕창 길어졌다.

우리가 하는 것을 보고 하시는 말씀이 "본인이 한명이니까 멤버변수에 static을 먹여야 되는거 아니에요?"

'오.. 그런가..?' 할 때 쯤 아니란다.

 

static은 객체가 여러개고 그것들의 속성이 동일 할 때 그 속성을 같이 공유할 때 쓰는 것이기에 쓰면 안 된다.

나라는 객체는 only one이기 때문이다. 이렇게 세상에 유일한 객체가 딱 하나일 때 쓰는 것이 singleton 패턴이다.

 

-Pattern Programming

 

-Singleton Pattern

1. 생성자를 모두 private로 잠군다.

2. 내부에서 객체 생성 후 static영역에 털 끝 하나 수정도 못하게 final 까지 건다.
(사실 final을 먹여놔서 값을 못 바꾸기에 public을 써도 되지만 다들 private를 쓴단다.)

3. 그 하나있는 객체 외부에서 쓸 수 있도록 getter를 만든다.

4. 이제 이 나라는 객체는 필요할 때 마다 새로 만들어내는게 아니고 불러서만 쓸 수 있는 존재이다.

 

그리고 이 사람의 존재 자체를 못 바꾼다는 것이지 안에 들어간 속성(주소 등 멤버변수)는 변경이 가능하다.

 

오랜만에 문제를 내주셨다.

 

전화걸기 기능 (010-xxxx-xxxx)를 입력하면 010-xxxx-xxxx로 연결합니다.
라고 나오게 만들라 하셔서 객체 만들고 어떻게 해야하나 하고 있었다.

 

그런데 여러분은 속고 있다면서 꼭 방금 배운 것이 singleton 패턴이라 그걸 써야되는게 아니고 생각해봤을 때 멤버변수가 없으면 객체는 만들지 않고 static method 기반으로 하면 되고 있으면 객체로 만들어야 되는 것 아니냐고 하셨다.

그냥 이렇게 말이다. 약간 충격요법 같은 건가 싶기도 하다.

이런식으로 뭔가를 만들려면 뭐가 필요하고 그게 왜 필요한지 아는 능력을 기르라는 것을 항상 강조하시는 것 같다.

 

다음은 (학급 번호)1번 홍길동 수원 사는 학생을 만들라 하셨다.

학생은 여러명일테고 객체가 필요하니 우리가 원래 쓰던 기본형으로 만들었다.

그런데 학생이 겁나게 많아버리면? 한 345612명 쯤 있다고 하면?

Student s345612 = new Student(345612번, "홍동길", "경남");

뭐 이러고 있을 건 아니니까 필요한 것이.factory pattern이다.

 

-factory pattern

 

위 처럼 빌드업 하신 것의 요점은 아까 하나만 관리하는 것은 singleton pattern으로 여러개를 자동으로 관리 하는 것은 factory pattern으로 별일 없으면 그냥 하던대로 하라는 의미였단다.(위에는 내가 과장해서 적긴 했다. 좋으신 분이다.)

그리고 우리 입장에선 singleton pattern이 더 중요하고 factory pattern은 잘 쓸일 없을 거란다.

 

1. 기본에서 좀 덜 잠군다. (같은 패키지에서만 생성 가능하게) 위는 접근제어자를 다 지워서 default를 이용했다.

2. 공장 역할을 할 클래스를 같은 패키지에 만든다.

3. 객체를 만들어 낼 메소드를 만든다.(학원에 학생이 생기려면(되려면) 학원으로 문의를 해야된다. 대충 이런 뜻이었다.)

4. 학원이 관리하는 학생 이름, 주소 값을 재료로 쓰고 생성될 때마다 1번 2번 번호가 높아지게 studentCount 멤버변수를 만들고 ++ 증가를 걸어놨다.

5. 메인에서는 이렇게 불러낸다. (음.. 지금 보니 막 혁신적인 느낌은 아니다.)

 

이번엔 몬스터를 만들거다. 몬스터 이름만 입력하면 level, mp, hp 랜덤으로 몬스터가 만들어지게 말이다.

 

방금 배운거라 factory pattern 틀 자체는 어렵지 않게 만들겠는데 응용하는 방법을 전혀 모르겠었다.

랜덤을 공장 클래스에서 만드는건 감이 왔었는데 너무 어렵게 생각했나보다.
소스를 보니 굉장히 간단해보인다.

 

이번엔 마블 히어로다.

Hero 상위 클래스를 만들고 아이언맨과 헐크 클래스에게 상속을 해줬다. 그런데

이렇게 쓰시더니 Java는 제껴두고 감상이 어떠냐 하신다.

변수가 값을 담는 그릇이였는데 무슨 느낌이 드냐고 하셨다.

16번줄은 우리가 원래 하던거고 17, 18, 20번은 말이 안 되고 19번줄은 논리적으로 말이 될 것이다.

말씀의 핵심은 상위클래스타입 변수에 하위클래스타입 객체를 만들어 넣을 수 있다는 것이다.
그렇다면 d의 정체는 뭘까? d의 자료형은 Hero일까? Ironman일까? 프린트하면 아이언맨이 나온다.

 

갑자기 아래에 대한 내용을 말씀하셨다.

정적로딩(static loading) : 변수 만들 때 최종 자료형 정해지는거
동적로딩(dynamic loading) : 실제 객체 만들 때 최종 자료형 정해지는거

그런데 Java는 이 중에서 동적로딩이다.

 

-polymorphism(다형성)

 

1. 동적로딩이 지원되는 언어에서만 가능
2. 상위클래스타입 변수에 하위클래스타입 객체 만들어 넣을 수 있음.

 

오랜만에 배열을 해보자 하셨다.

이런식으로 배열을 만들 때 배열 안쪽 Hero 위치에 헐크나 아이언맨은 들어올 수 없지만 이 상위 클래스 Hero가 들어왔기에 전체 하위 클래스의 배열을 형성할 수 있다.

마찬가지로 메소드의 파라메터에도 상위 클래스를 담는다면 다른 클래스에서 method를 불러올 때 하위 클래스 전부를 불러올 수 있다.

 

팩토리패턴 3차전으로 가자며 이번 팩토리는 진짜 공장스럽게 자동차로 가자 하셨다.

세단, 버스, 트럭을 만들어 낼 것인데 차 번호와 종류를 정해서 만들기.

메인, 차라는 상위 클래스, 세단, 버스, 트럭 세개의 하위클래스를 만들고 차에는 번호가 다 있으니까 상위 클래스 Car에 num 멤버변수를 만들어 준다.

 

그런데 이 번호가 자동으로 올라가게 만들 때 트럭쓰면 트럭 객체 생성, 세단 쓰면 세단 객체 생성하게 해보란다.

아까 학생 이름 주소 넣으면 객체 새로 생성 해주는 방식대로 해봤는데 안 된다.

이렇게 하는 거였다. 내가 말을 잘못 이해 한 것 같기도 하다.

 

팩토리랑 다형성은 이렇게 찰떡이다. 근데 쓸만한 날이 올지는 모르겠다 하셨다.