Task 1 : 두 클래스와의 관계 : 두 클래스는 둘다 default package 가 아닌걸로 분류된다.

1. Fig.3.1을 다시 쓰고 "AccountPackage"라는 패키지를 추가해라

2. Fig 3.2를 다시 쓰고 "AccountTestPackage"라는 패키지를 추가해라

3. 너가 컴파일 했을때 에러가 발생한다. 에러 원인이 무엇인가? 어떻게 에러를 고칠것인가? 에러를 고치고 스크린샷을 붙여라

AccountTest 클래스에서 Account를 읽을 수 없다. 따라서 AccountTestPachage의 Account 를 불러와야 한다.

 

 

Task 2 : 클래스와의 관계 : 두 클래스는 non-default 패키지 이고 한 클래스는 default modifier이다. public이 아닌

 

1. 그림 3.1을 다시 써라

        패키지 이름을 "AccountPackage" 로 해라.

        클래스에서 public을 지우고 저장해라.

2. 그림 3.2를 다시 쓰고 패키지 이름을 "AccountTestPachage" 로 해라.

3. 컴파일 했을 때 에러가 뜰것이다. 이유가 뭔가? 어떻게 에러를 고쳐야 하는거. 에러를 고치고 스크린샷을 붙여라.

 

 

 

 

 

 


      -- 목차 --

  1. package
  2. import
  3. 제어자란?
  4. final
  5. 접근 제어자
  6. 접근자와 설정자

 

 

1. package

패키지는 클래스의 집합이라고 볼 수 있습니다. 프로그래밍을 하는데 한개의 클래스로 프로그래밍을 할 수 없는 건 당연합니다.

그렇기 때문에 필연적으로 여러개의 클래스를 사용하여 프로그래밍을 하게되지만

단순히 클래스를 여러개를 사용한다면 규모가 매우커질시에는 프로그램이 번잡해질것이며

그렇기 때문에 유지보수 및 관리에 큰 어려움을 겪게 될것입니다. 그걸 방지하기위해서 존재하는 것이 package입니다.

package는 클래스를 묶어두는 물리적인 단위입니다. 이때까지의 클래스 구조들은 논리적인 구조였다면

이는 물리적으로 프로그램을 분리시켜 놓는 것이지요.

패키지의 생성방법은 아래와 같습니다.

 

 

이때까지는 소스파일에 직접 class를 만들었습니다. 이번에는 먼저 package를 만들도록 해보겠습니다.

 

 

그러면 이렇게 소스폴더와 이름을 정하는 파일이 나옵니다. 소스 폴더는 사실 손대실 필요가 없습니다.

이름을 정해줍시다.

 

 

그러면 저렇게 패키지가 하나 만들어집니다. 그 다음 패키지에 우클릭을 해서 클래스를 만들어줍니다.

 

 

그러면 이렇게 패키지 내부에 클래스를 만들 수 있습니다. 패키지는 이러한 방식으로 만듭니다.

 

 

그러면 위에 package 표시가 자동으로 뜹니다. 이 패키지 표시를 절대 지우면 안됩니다.

애당초 패키지 표시를 지우면 컴파일러 에러인데 그 이유는

패키지 표시를 지우면 디폴트 패키지(어노니머스 패키지)에 들어있다 가정하기 때문이죠.

그러나 저희는 Main클래스는 디폴트패키지가 아니라 PackEx패키지에 실제 클래스파일이 존재하므로 반드시 넣어줍니다.

 

모든 소스파일은 기본적으로 패키지에 들어있습니다. 패키지에 들어있지 않는 클래스파일은 존재하지 않습니다.

그러나 저희는 이때까지 단한번도 패키지파일을 만든적없이 사용했습니다. 그러면 이때까지는 어떻게 만든 것일까요?

거기에 대한 해답입니다.

 

 

소스파일에 패키지를 선언하지 않았다면 자동으로 default package가 생기며 이 패키지는 이름이 없는 어노니머스 패키지입니다.

즉 만약 단 한개의 패키지도 선언하지 않았다면 자동으로 디폴트 패키지에 저장이됩니다.

만약 디폴트 패키지의 생성후 다른 패키지를 만들어도 디폴트 패키지가 사라지지 않습니다.

단 디폴트패키지 없위 위의 예제처럼 처음부터 PackEx처럼 패키지를 만든다면 디폴트 패키지는 자동으로 소멸하고

더 이상 디폴트패키지를 사용할 수 없습니다.

 

 

위의 그림을 예제로보시면 패키지는 OS상에서는 단순한 디렉토리, 즉 단순한 파일에 불과합니다.

패키지를 지정해주면 단순히 파일이 생기게 되고 그 파일에 클래스파일(.JAVA)가 존재하게 되는 것이죠.

디폴트 패키지의 경우에는 디렉토리가 아니라 그냥 src파일 내부에 존재하게 되며 패키지에 속하지 않는 모든 파일을

가상의 디렉토리 파일인 default package를 만들어 함께 관리하게 되는 것입니다.

 

여기서 중요한건 왠만하면 default package를 쓰지 않는 것이 좋습니다.

왜냐하면 앞으로 import문을 배우면 아시겠지만 default package 어노니머스, 즉 이름이 없는 패키지이므로

다른 패키지에서 디폴트 패키지를 import시킬 수 없습니다. 반대로 디폴트 패키지에서는 다른 패키지를 import 시킬 수 있습니다.

그렇기 때문에 왠만해선 default package를 쓰기보다는 다른 패키지를 쓰시는게 좋습니다.

 

 

아직 import문을 배우진 않았지만 크게 문제될것은 없습니다. 안의 그림을 보시면 여러가지 package가 존재하는 것을 알 수 있습니다.

그 중에서 java.applet 등... (.), 즉 온점으로 파일들이 구분되고 있습니다.

이는 패키지 역시 계층형태를 띄고 있는 경우입니다. 예를들어 java.awt.dnd.peer이라는 구문은

java라는 파일에 awt라는 폴더에 dnd라는 폴더의 peer폴더라는 뜻입니다.

 

무슨 말인지 이해가 안가신다면 예제를 통해 보여드리도록 하겠습니다.

위의 예제는 ABC.CDE.EFG로 패키지의 이름을 정했습니다. 그러면 실제 외부의 디렉토리는 어떻게 저장이 될까요?

 

보시면 자동으로 계층 구조를 형성하게 됩니다. ABC파일에 CDE파일의 EFG파일이 되는 것이지요.

이로써 패키지를 논리적인단위를 따라서 나뉘지만 이 나뉜 단위는 실제로 물리적으로 나뉘게 된것입니다.

이는 클래스의 상속 계층구조와는 또다른 계층구조를 가집니다.

클래스들을 좀더 내가 생각하기에 알맞게 나눠서 저장할 수 있는 것이지요.

 

 

기본적으로 이렇게 나뉜 패키지들은 특별한 일이 없이 다른 패키지에 영향을 미칠수 없습니다.

위의 그림을 예제로한다면 default package의 클래스들을 Good에서 사용할 수 없으며 또한 반대의 경우도 마찬가지 입니다.

Good의 클래스를 Good2에서 사용하는것 역시 불가능하며 반대역시 마찬가지 입니다.

이렇게 만들어진 패키지들은 서로만 내부에서 공유할 수 있으며 다른 패키지에서는 참고할 수 없습니다.

물론 이 패키지들끼리 협약을 맺는다면 못 사용하게 할 것도 없습니다.

이게 가능하게 하는것이 import입니다.


2. import

 

위의 그림은 다른 패키지에 있는 클래스를 사용하는예제입니다.

사용하는 방법은 위와같이 클래스가 존재하는 모든 경로를 포함한 주소를 몽땅 적어주는 겁니다.

가운데 public키워드는 아직 신경쓰지마시구요...

어쨋든 이렇게 하면 다른 패키지에 존재하는 클래스를 빼서 사용할 수 있습니다.

다만 코드가 굉장히 거지같다는 부작용이 따라옵니다.

왠지... 사용하고 싶어지지 않는 방법입니다. 그냥 포기하고 싶어지네.

 

이와같이 경로를 생략하는 방법이 있습니다. 그 방법은 바로 import문을 사용하는 것입니다.

import문의 사용은 아래와 같습니다.

 

import를 사용하고 경로를 적으면됩니다.

 

import 경로.*;

 

이 코드가 의미하는것은 다음 경로의 하위폴더는 모조리 경로를 생략해도 된다는 것이죠.

위의 코드는 import ABC.*;라고 적혀있는데 그러면 ABC를 생략해도 된다는겁니다.

그러나 여기서 한가지 문제가 있는데 ABC.CDE나 ABC.CDE.EFG에서 ABC를 지웠지만

에러구문이 없어지지 않습니다. 그렇습니다.

저기 경로를 적지 않는것은 다른 하위경로를 제외(그러니까 패키지는 제외)한 다른 요소들,

즉 클래스 애너테이션,애뉴머레이션만 사용가능하다는 겁니다.

그렇기 때문에 Train과 Car도 위와같이 해주고 싶다면 경로를 따로 import시켜줘야합니다.

 

 

이렇게 따로따로 import해줘야만 효과를 보실 수 있습니다.

그리고 아래의 다른 예제를 보실께요.

 

 

이렇게 ABC에 Auto라는 다른 클래스를 만든다고 가정하겠습니다.

이 때 만약 import ABC.*;를 쓴다면 Auto역시 패키지를 적지않고 사용할 수 있습니다.

그러나 위처럼 .*로 끝나는개 아니라 아예 클래스(혹은 애너테이션이나 애뉴머레이션) 하나를 지정했다면 그것만 영향을 줍니다.

그리고 다른 클래스들은 사용할 수 없습니다. 이런식으로 제한을 걸 수 있습니다.

 

중요성은 같은 이름의 클래스가 존재할 경우입니다. 보시면 아시겠지만 ABC.CDE.EFG패키지의 Car는 분명

import구문으로 선언되어 경로를 생략할 수 있지만 PackEx에도 Car는 존재합니다.

이경우에 Car는 두개존재하는 셈인데요, 이 경우에는 위의 그림과 같이 반드시 자신의 패키지를 우선해서 사용할 수 있습니다.

이 경우에 만약 ABC.CDE.EFG패키지의 Car을 사용하고싶다면 모든 경로를 다 적어주어야만합니다.

다행히 모호성이 발생해서 컴파일 거부하거나하는 일은 생기지 않습니다.

 

 

또한 클래스 메소드나 클래스 함수같이 정적인 자료에 대해서 import static 메소드를 지정해주면

그 메소드나 그 속성 혹은 특정 패키지의 모든 클래스 요소들을 전부 이름으로 접근할 수 있습니다.

위의 경우 Auto클래스 내부의 모든 static요소들을 이름으로 바로 접근해주는 방법입니다.

물론 요소를 직접 지정하는 방법도 가능은 합니다. 위의 public은... 곧 가르쳐드릴거니까 뭔지는 아직 모르셔도 됩니다.

단 위처럼 import static으로 지정해주면 나머지 요소들, 즉 static이 아닌 요소들은 바로접근할 수 없습니다.


3. 제어자(Modifier)란?

 

제어자(Modifier)는 클래스, 속성, 메소드, 지역변수의 선언과 함께 사용되며 각각의 클래스,속성,메소드,지역변수의 성질을

결정해주는 역활을 합니다. int,float등의 자료형은 제어자라고 부르지 않습니다. 제어자의 종류는 아래와 같습니다.

 

접근 제어자 - public,private,protected

CV 한정자 - final,volatile

그 외 - static,abstract,native,transient,synchronized,strictfp

 

그 외에도 더있지만 자주 쓰이는건 이정도 입니다.

이 제어자들중에서는 서로 함께 사용하는게 가능한것도 있고 불가능 한것도 있습니다.

예를들어 접근 제어자는 무조건 하나만 사용가능하며 static과 abstract는 함께 사용할 수 없는등.. 여러가지의 제약이 있습니다.

모두 다 굉장히 중요하지만 그렇다고 모두다 소개하기에는 너무 방대합니다. 그래서 중요한것 몇가지만 추려서 일단 급한불을 끕시다.


4.final

C++에서 사용되는 const와 그 맥락을 같이합니다. 아쉽게도 자바에서는 const가 없는대신 final이 존재합니다.

final 키워드는 클래스,속성,메소드,지역변수를 더 이상 변형 불가능 한 상태로 만들어 줍니다.

즉 수정이 불가능 한상태로 만든다는것인데 사실 이 4가지 경우의 사용법은 각각 다릅니다.

사실 꿈보다 해몽이라고 비슷한 효과를 가졌는지도 모르겠습니다. 그냥 끼워맞춘겆 같아요.

먼저 final예제를 보시기전에 요약붙어 볼께요.

 

final

 

클래스 - 다른 클래스에 상속해줄 수 없는 상속계층의 제일 아랫단계 클래스가 된다.

메소드 - 마지막 메소드가 된다. 즉 오버라이딩이 불가능해진다. 대신 오버로딩은 가능.

속성 - 상수가 된다. 상수가 되므로 변경 불가.

지역변수 - 상수가 된다. 상수가 되므로 변경 불가.

 

final은 대상으로 하는 4가지가 전부 두루두루 쓰입니다. 그래서 굉장히 자주볼 수 있는 키워드입니다.

 

좀 난잡해 보일수도있는데 하나하나 보시고 설명해드릴께요.

일단 상속계층도는 Unit을 Hero가 상속받고 UndeadHero가 Hero를 상속받는 구도입니다.

 

가장 먼저 눈에 띄는것은 PrintUnitName메소드의 final선언입니다. 이 메소드는 final이므로 이제 오버라이딩이 불가합니다.

그럼에도 불구하고 Hero클래스에서 오버라이딩을 시도하였고 이는 컴파일 에러로 이어집니다.

 

그다음은 String Info의 final선언입니다. Info 지역변수는 이제 바뀌지 않을거라고 판단, final로 선언했으므로 상수화되어서

더 이상 값을 변경하는것은 불가능합니다. 그러나 바로 밑의 경우 수정을 시도하였고 이는 final에 위배되어 에러가 뜹니다.

 

세번째는 class Hero에 정의한 final입니다. Hero는 final이 되므로 더이상 상속받을 수 없어야 합니다.

그러나 UndeadHero에서는 Hero의 상속을 시도합니다. 이는 final에 위배되어서 에러가 뜹니다.

 

마지막으로는 int serial의 final 지정입니다. serial은 고유숫자이므로 더 이상 수정되면 안되므로 final처리를 해줍니다.

그러나 생각해보니까 serial생성규칙이 틀린거같아서 수정하려고 합니다. 그러나 final처리가 되면 상수이므로

더이상 수정이 불가능합니다. 그래서 에러처리가 됩니다.

 

여기서 중요한건 속성과 지역변수의 final처리입니다. 이 둘은 일단 지정하면 상수화 되는데, 그 말은 변경 불가라는 이야기이죠.

따라서 사용하기전에 반드시 초기화를 해줘야합니다. 아래의 예제를 보시죠.

 

num은 final선언한 속성입니다. num을 사용하려고 했지만 초기화가 되지 않아서 사용이 불가능 합니다.

초기화 방법은 생성자에서 초기화를 하거나 선언과 함께 직접 붙혀주면됩니다. 어떤방식을 쓰던 자유입니다.


5. 접근 제어자

사실 굉장히 중요한내용인데 더 중요한 내용을 다루다보니 이 파트가 무려 10장이나 걸려서 간신히 왔네요.

사실 객체지향의 꽃과도 같은 부분이기때문에 반드시 알아둘 필요가 있습니다.

이때까지의 객체모델에서는 저희가 접근제어자를 한번도 명시하지 않고 사용했습니다.

사실 사람이 조심한다면 이 접근 제어자는 없어도 되는 부분이긴 합니다.

 

프로그래밍을 하다보면 특정한 객체가 다른 객체에 의존적이게 되는 상황이 빈번하게 발생할 수 있습니다.

예를 들면 아래같은 상황에서 말이죠.

 

상황을 가정해 보도록하죠. 저는 지금 대출업을 하고 있고 프로그램은 대출프로그램입니다.

매 고객에게 이율30%를 받는데요 유태인 뺨치는 고리대금

기성룡의 이율을 보니까 30%보다는 많이 필요한거 같아요.

그래서 500만원 이하인 애들한테는 50%를 받기로 합니다.

그래서 직접적으로 Customer에 접근해서 그 값을 50%로 수정합니다.

문제는 여기서 발생합니다. 잠시만 수정하고 원래대로 돌아놓았으면 좋으련만 그걸 까먹고 말아버렸습니다.

그 다음 이청룡은 돈을 800만원이나 빌렸으니 다시 30%를 받아야 하지만 실수로 가격을 수정하여서 50%를 받아버리고맙니다.

 

이처럼 돈이걸린 문제에서 전산오류가 나버리면 고객에게 심대한 타격이고 고객의 타격은 나아가서 회사의 타격이죠.

아무리 헬조선이라지만 30%받아야되는 사람에게 50%를 받고 말았으니 고소각이라고 할 수 있습니다.

이렇게 rate는 굉장히 중요한 변수임에도 main함수에 접근을 허락한 결과 rate의 값을 바꿔놓았고

그 결과 의도치않은 상황에서 당장의 편리를 위해서 rate를 꺼내써버리고 말았습니다.

다행이 코드가 짧다면 오류라도 빨리 찾아내겠지만, 코드가 천줄이라면?? 만줄이라면?? 오류를 못찾고 허덕일겁니다.

왜냐하면 논리적인 프로그래밍 설계의 미스인거지 문법이 틀린건 아니기 때문이죠.

 

이렇게 내부의 속성에 마구잡이로 값을 변경하게 되는 것은 굉장히 위험한 발상이라고 할 수 있습니다.

여기서 설계의 미스는 Customer 클래스지만 실제로 수정해야하는것은 Main클래스입니다.

그러면 누구의 잘못일까요? 이 문제 역시 굉장히 애매한 문제이죠.

이렇게 남의 속성을 함부러 쓰게된다면, 어떠한 클래스가 다른 클래스에 구조적으로 의존적이게 되며

이러한 코드가 늘어날수록 논리적인 설계의 결함을 찾는건 더더욱 힘들어집니다.

 

그래서 객체지향 프로그래밍이 존재합니다. 객체지향 프로그래밍에서 가장중요한것중 하나인게 은닉화와 캡슐화이며,

이것을 가능하게 해주는 것이 접근 제어자입니다. 즉 Customer의 잘못은 Customer가 짊어질것이며

Main은 자기가 잘못한것만 짊어지게 됩니다.

 

캡슐화라는 것은 특정한 객체를 캡슐처럼 싸게되어서 내부의 정보를 공개하지 않고 한다리를 무조건 걸치게 하는것입니다.

일종의 추상화를 하나 얹지는 과정인것이죠. 아직 말씀드려봐야 안와닫겠지만 아래 예시를 보면서 설명드리겠습니다.

 

비슷한 맥락으로 은닉화라는 것이 있습니다. 사실 거의 동의어나 다름없는데 은닉화는 중요한 데이터(속성)을

숨겨서 드러내지 않는 것을 의미합니다.

 

예를 들면 우리가 자동차를 몰면서 차의 설계도 면까지, 구동 원리까지 알 필요는 없습니다.

물론 알면은 더 좋겠지만 오히려 역효과가 날 수도있죠. 저희는 그냥 운전만 알면 되는 것이죠.

캡슐화와 은닉화는 여기에 기반한다고 보시면됩니다.

 

 

여기서 rate에 private지시자를 사용하자마자 Main에서 Customer.rate에서 에러가납니다.

에러가 난 부분을 읽어보면 rate가 존재하지 않는다고합니다.

 

이것이 접근 제어자중 private의 힘입니다. 속성이나 메소드에 private를 걸어주면

그 속성이나 메소드는 다른 클래스에서 사용할 수 없게 됩니다.

아예 접근을 못하게 됩니다.

더 자세히 말하면 존재하는지 안하는지도 모릅니다. 철저히 은닉화 되는것이죠.

 

Main클래스 입장에서 Customer클래스의 rate속성이 존재하는지도 모릅니다.

따라서 rate를 호출해봐야 Customer에서는 안 보여주니까 Main에서 볼 수 있는 방법은 아예 존재하지 않습니다.

 

이런 것이 접근제어자입니다. 이때까지는 접근제어자를 사용하지 않았지만 접근제어자를 사용하지 않는것도 일종의 접근제어자입니다.

이러한 접근 제어자를 package, 혹은 default라고 부릅니다.

이렇게 하나씩 말하기 보다 모든 접근제어자들에 대해서 통채로 설명하는 것이 좋을거 같습니다.

 

 

 

접근제어자(속성 및 메소드에 사용시)

 

public - 어떠한 접근제한도 없는 상태. 모든 클래스에서 접근이 가능하다.

protected - 같은 패키지내에서는 public과 같은 효과. 단 다른 패키지에서는 상속받은 개체만 사용가능.

package(default) - 같은 패키지내에서는 public과 같은효과. 단 다른 패키지에서는 사용 불가능.

private - 자기 자신 클래스만 사용가능. 그 외에는 어떠한 경우에도 사용 불가능.

또한 접근제어자는 메소드와 속성에도 달 수 있지만 클래스에도 달 수 있습니다.

속성 과 메소드에서 사용하는것을 먼저예시로 만들고 싶지만 클래스모델이 잇어야하니까 이 부분을

설명을 먼저해야할 것 같습니다.

 

 

접근제어자(클래스)

 

public - 한 클래스 파일에 단 한개의 public클래스만 존재가능하다. 단 존재치 않을 수도 있다.

다른 패키지에서 사용시에는 public클래스만 사용 가능하다.

 

package(default) - 한 클래스파일에 여러개도 존재가능하다. 다른 패키지에서는 사용할 수 없다.

클래스의 접근제어자는 private와 protected를 지정할 수 없습니다.

중요한건 public은 한 클래스파일에 하나만 존재가능하다는거죠.

 

이 창은 클래스를 만드는 창입니다. 이제 Modifiers부분이 이해되실겁니다.

이 때까지 저희는 이걸 단 한번도 손댄적이 없습니다. 항상 public으로 만들었는데요,

여기서 public클래스는 모든 같은 패키지 내에서 뿐만이 아니라 다른 패키지에서도 사용할 수 있습니다.

아래 예제를 보시죠.

 

 

여기서 Unit클래스는 public클래스이고, Hero클래스는 package클래스입니다.

 

보시다시피 package 클래스는 같은 패키지 내에서만 사용가능한데

Unit과 Hero는 같은 Unit패키지지만 Main은 Main패키지이므로 Unit패키지를 import시켜도

Hero클래스는 package클래스라 사용할 수 없습니다.

 

그러면 이제 나머지 접근 제어자를 살표보도록 하겠습니다.

 

보시다시피 unit의 클래스의 모든 속성은 default속성, 즉 package속성입니다.

이때까지 패키지속성은 같은 패키지에서는 마음대로 사용가능했지만 위의 사진을 보시면 아시겟지만

Main과 Unit은 서로 다른 패키지이므로 내부가 공개되지 않습니다.

따라서 사용이 불가능합니다. 그러면 여기서 String name에만 public을 걸어보도록하겠습니다.

 

 

갑자기 무슨 바람이 불었는지 자신의 이름을 흔쾌히 내어줍니다.

public의 효과는 이와같습니다. 다른 클래스에서도 public이라고 지정된 속성및 메소드를

다른 패키지에 존재하는 클래스에서도 사용할 수 있게 해줍니다.

만약에 모든 패키지에서 공통으로 사용하게 하고싶다면 속성이나 메소드를 반드시 public을 적어줘야합니다.

이번에는 String name에 private을 걸어보도록하겠습니다.

 

 

name에 private를 걸었더니 같은 패키지에 존재하는 Hero클래스조차 (심지어 상속관계인데도!!) name을 사용할 수 없습니다.

이렇게 private를 걸게되면 자기자신 클래스에서 밖에 name을 사용할 수 박에 없습니다.

 

 

마지막으로 protected입니다. 사실 자바의 protected는 C++의 protected와는 좀 다릅니다.

protected를 선언하면 같은 패키지끼리는 public효과나 다름없습니다.

다만 다른 패키지의 클래스에서는 private로 작용합니다.

그러나 다른 패키지라도 그게 상속받은 클래스라면 사용가능합니다.

위처럼 다른 패키지지만 Unit을 상속받은 Creep은 protected로 지정한 name에 접근할 수 있습니다.

혹시라도 C++을 하시던 분들을 위해서 설명을 드리자면 C++의 protected는

설사 같은 코드일지라도 그런거 상관없이 무조건 상속받은 애한테는 public,

아닌 애들한테는 private로 적용되는 중간정도되는 효과였지만,

JAVA에서는 신기하게도 같은 패키지내에서 열람이 가능하다는 것이죠.

이는 객체모델을 구현할때 차이점으로 다가올 수 있습니다.

물론 객체모델을 구현할때 protected의 사용은 조금 지양되는 면이 있는게 그나마 다행이지만...

사실 그런거랑 별개로 실제 코드보면 protected가 사용된게 너무 많습니다...

 

일반적인 클래스 모델을 예제를 보도록하겠습니다.

 

일반적으로 모든 속성은 private처리를 하고 나머지 모든 메소드는 public처리를 해주는게 보통입니다.

즉 다른건 몰라도 이건 기본사양이라는 것이죠. 여기서 말하는 메소드는 생성자를 포함합니다.

여기서 내부 속성을 private 처리하는 이유는 내부를 보호하기 위해서 이구요, 이렇게 private를 걸지않으면

외부에서 함부로 속성값을 바꿀수 있기 때문이죠.

그러나 메소드는 public 처리를 함으로써 외부와의 소통은 오로지 메소드만으로 하는 것이죠.

 

그러나 이 방법에는 한가지 문제점이 존재하는데 만약에 name을 도중에 바꾸고싶다.

그러나 위의 설계단계에서는 절대 name을 바꿀 수 없습니다.

그리고 name의 값만 출력하고 싶어도 그러질 못합니다.

내부의 name에 접근할 방법이 아예 없다는 것이죠.

그러면 너무 답답하기 그지없습니다.

애당초 저렇게 설계했다는거 자체가 "우리는 너희한테 name을 공개할 의도가 1도 없어"라는 뜻입니다.

정말 짜증나기 그지없죠. 그런데 만약에 name이 정말정말 외부에 드러나야한다면,

그리고 그계 설계 의도라면 위에서 어떻게 해야할까요?

가장 편한 방법으로는 name을 package나 public으로 수정하면됩니다.

그러나 이 방법은 객체지향설계적이지 않습니다.

객체지향의 모든 객체끼리의 대화는 메소드끼리의 대화로 한정됩니다.

속성에 직접접근하지 못하게 해야합니다.

따라서 저희는 이를 위한 다른 방법을 모색해야한다는 것을 알 수 있습니다.

 

6. 접근자와 설정자

위의 문제점을 해결하기 위해서 만든 개념이 접근자와 설정자입니다.

중요한건 모든 속성에 접근자와 설정자가 있을 필요는 없습니다.

예를들어 Unit클래스의 경우 name만 변경할수 있게 설계한다면 name만 접근자와 설정자가 존재하면됩니다.

 

Unit 클래스에서 getNmae과 setName을 보시면됩니다.

이는 전형적인 접근자와 설정자의 모델입니다. 이는 문법적으로 제공하는 키워드는 아닙니다.

다만 오랜 기간동안 프로그래머들 끼리 사용한 약속입니다.

 

 

접근자와 설정자

 

접근자

void 자료형 get변수명(){

return 변수명;

}

 

설정자

void set변수명(자료형 변수명){

this.변수명 = 변수명;

}

특이한 일이 없다면 반드시 위의 규칙을 지킵니다. 먼저 접근자를 보시면 name을 알고싶을때

name을 반환해주는 것입니다. 그러면 외부에서는 u.getName() 메소드를 호출하면 name을 알 수 있습니다.

name비록 private지만 getName은 public이기 때문이죠.

name을 수정하는 일 역시 같은 맥락으로 해석이 가능합니다.

이 방법은 비록 돌아가지만 오로지 메소드로만 대화한다는 대명제를 지키기 때문에 반드시 이렇게 해줘야합니다.

이 방식이 객체지향에서 하도 많이쓰이다보니 다른 객체지향언어에서는 문법적으로 지원을 해줍니다.

'📌 java > Object-oriented Programming' 카테고리의 다른 글

java - txt.file  (0) 2020.03.26
java.util.Arrays - Arrays 클래스  (0) 2020.03.26
java.util.Scanner  (0) 2020.03.25
Homework_02  (0) 2020.03.20
Homework_01  (0) 2020.03.17
복사했습니다!