Java가 패키지 액세스를 기본으로 설정 한 이유는 무엇입니까?


26

나는 그들이 좋은 이유 때문에 그것을했고 대부분의 사람들이 지금까지 업계에서의 경험에서 잘 사용하지 못한다고 믿기 때문에이 질문을하고 있습니다. 그러나 내 이론이 사실이라면 왜 그들이 개인 액세스 수정자를 포함했는지 잘 모르겠습니다 ...?

기본 액세스가 올바르게 사용되면 캡슐화를 유지하면서 향상된 테스트 기능을 제공한다고 생각합니다. 또한 개인 액세스 수정자를 중복으로 렌더링합니다.

기본 액세스 수정자는 다른 세계에서 숨겨져 야하는 메소드에 고유 한 패키지를 사용하여 동일한 영향을 제공하는 데 사용될 수 있으며 테스트 폴더의 패키지는 동일하므로 테스트 가능성을 저하시키지 않고이를 수행합니다. 소스 폴더에 선언 된 모든 기본 메소드에 액세스 할 수 있습니다.

이것이 Java가 패키지 액세스를 'default'로 사용하는 이유라고 생각합니다. 그러나 왜 그들이 개인 액세스를 포함했는지 잘 모르겠습니다. 유효한 사용 사례가 있는지 확신합니다 ...



이전에 논의 된 단위 테스트 전용 메소드와 관련이 있습니다. how-do-you-unit-test-private-methods . 대답; 하지 말아야
Richard Tingle

답변:


25

나는 그들이 평균 프로그래머가 무엇을 할 것인지에 대한 좋은 생각을 가지고 있다고 생각합니다. 그리고 일반적으로 프로그래머는 프로그래밍에 능숙하지 않지만 어쨌든 직업이 충분하지 않고 비싸기 때문에 직업을 얻는 사람을 의미합니다.

"공용"액세스를 기본 액세스로 설정하면 대부분의 프로그래머는 다른 것을 사용하지 않아도됩니다. 그 결과 어디에서나 많은 스파게티 코드가 생겼습니다. (기술적으로 어느 곳에서나 전화를 걸 수 있다면 왜 메소드 내에서 일부 로직을 캡슐화해야합니까?)

"비공개"를 기본 액세스로 만드는 것이 약간 더 좋습니다. 대부분의 초보 프로그래머는 단순히 "모든 곳에서 '공개'를 작성해야합니다"라는 경험 법칙을 발명하고 블로그에 공유 한 다음 왜 Java가 그렇게 나빠서 어디서나 "공개"를 작성해야하는지 불평 할 것입니다. 그리고 그들은 또한 많은 스파게티 코드를 만들 것입니다.

패키지 액세스는 프로그래머가 하나의 패키지 내에서 코드를 작성하는 동안 조잡한 프로그래밍 기술을 사용할 수있게하지만 더 많은 패키지를 만들 때 다시 고려해야합니다. 좋은 비즈니스 관행과 추악한 현실 사이의 타협입니다. 같은 : 일부 스파게티 코드를 작성하십시오. 주장하면 패키지 내에 추악한 혼란을 남겨주세요. 최소한 패키지들 사이에 더 멋진 인터페이스를 만드십시오.

아마 다른 이유도 있지만, 나는 이것을 과소 평가하지 않을 것입니다.


14

기본 액세스는 개인용 액세스 수정자를 중복으로 렌더링하지 않습니다.

언어 디자이너의 입장은 공식 튜토리얼- 클래스 멤버에 대한 액세스 제어에 반영되며 매우 명확합니다 (편의를 위해 인용 부호로 굵게 표시 ).

액세스 레벨 선택에 대한 팁 :

다른 프로그래머가 클래스를 사용하는 경우 오용으로 인한 오류가 발생하지 않도록해야합니다. 액세스 수준이 도움이 될 수 있습니다.

  • 특정 회원에게 적합한 가장 제한적인 액세스 수준을 사용하십시오. 합당한 이유가없는 한 비공개로 사용하십시오.
  • 상수를 제외한 공용 필드는 피하십시오. (자습서의 많은 예제는 공개 필드를 사용합니다. 이는 간결하게 몇 가지 요점을 설명하는 데 도움이 될 수 있지만 프로덕션 코드에는 권장되지 않습니다.) 공개 필드는 특정 구현에 연결하고 코드 변경시 유연성을 제한하는 경향이 있습니다.

예를 들어 TDD에 대한 새로운 답변에서 알 수 있듯이 개인 수정자를 완전히 삭제한다는 정당화 로 인해 테스트 가능성에 대한 귀하의 호소 가 잘못되었습니다 . 지금 개인 메소드를 피해야합니까?

물론 개인 메소드를 가질 수 있으며 물론 테스트 할 수도 있습니다.

어느 쪽이 어떤 당신이 그런 식으로 그것을 테스트 할 수 있습니다, 또는이없는 경우에 실행에 민간 방법을 얻을 수있는 방법으로, 어떤 실행하는 개인 얻을 수있는 방법은, 경우에 왜 도대체 당신은 단지 그것을 테스트하기 위해 노력하고있다 빌어 먹을 물건을 삭제 ...


패키지 수준 액세스의 목적과 사용법에 대한 언어 디자이너의 입장은 다른 공식 자습서 인 패키지 만들기 및 사용에 설명되어 있으며 개인 수정자를 삭제한다는 아이디어와는 아무런 관련이 없습니다 (편의를 위해 굵은 글씨로 인용 ) :

다음을 포함하여 여러 가지 이유로 이러한 클래스와 인터페이스를 패키지로 묶어야합니다.

  • 귀하와 다른 프로그래머는 이러한 유형이 관련이 있는지 쉽게 확인할 수 있습니다 ...
  • 패키지 내의 유형이 서로 무제한으로 액세스하도록 허용하면서도 패키지 외부의 유형에 대한 액세스는 여전히 제한 할 수 있습니다 ...

<rant "충분한 소리가 들렸다 고 생각합니다. 크고 분명하게 말할 때가 왔다고 생각합니다 ...">

개인 방법은 단위 테스트에 유리합니다.

아래는 사용자가 코드 범위에 익숙하다고 가정합니다 . 그렇지 않다면 단위 테스트와 테스트에 관심이있는 사람들에게 매우 유용하기 때문에 배우는 데 시간이 걸립니다.

좋아, 그래서 그 개인 방법과 단위 테스트, 그리고 범위 분석이 있다는 커버리지 분석을 얻었고, 내 개인 방법은 테스트에 포함되지 않습니다. 지금...

비공개로 유지하면 무엇을 얻을 수 있습니까

메소드는 개인용이므로 진행하는 유일한 방법은 코드를 연구하여 비 개인용 API를 통해 사용되는 방법을 배우는 것입니다. 일반적으로 이러한 연구에 따르면 테스트에서 특정 사용 시나리오가 누락 된 것입니다.

    void nonPrivateMethod(boolean condition) {
        if (condition) {
            privateMethod();
        }
        // other code...
    }

    // unit tests don't invoke nonPrivateMethod(true)
    //   => privateMethod isn't covered.

완전성을 위해, 그러한 커버리지 갭에 대한 다른 (덜 빈번한) 이유는 사양 / 디자인의 버그 일 수 있습니다. 나는 여기에 깊이 들어 가지 않고 단순하게 유지합니다. "방법을 테스트 할 수 있도록"액세스 제한을 약화 시키면 이러한 버그가 존재한다는 사실을 알 수 없을 것입니다.

문제를 해결하기 위해 누락 된 시나리오에 대한 단위 테스트를 추가하고 적용 범위 분석을 반복하며 차이가 사라 졌는지 확인합니다. 지금 무엇을해야합니까? 비공개 API의 특정 사용법에 대한 새로운 단위 테스트를 받았습니다.

  1. 새로운 테스트를 통해이 사용에 대한 예상 동작이 변경되지 않으면 테스트가 실패하므로 예고없이 변경되지 않도록합니다.

  2. 외부 독자는이 테스트를 살펴보고 어떻게 사용하고 행동 해야하는지 배울 수 있습니다 (여기서 외부 독자는 미래의 자기 자신을 포함합니다.

  3. 새로운 테스트는 리팩토링에 대한 허용 (이렇게 나는 당신이 내기!? 개인 방법을 리팩토링) I가 무엇을 할 것입니다 privateMethod, 난 항상 테스트 할 수 있습니다 nonPrivateMethod(true). 내가하는 일에 관계없이 privateMethod메소드가 직접 호출되지 않으므로 테스트를 수정할 필요가 없습니다.

나쁘지 않다? 당신은 내기.

액세스 제한을 약화시키는 것에서 무엇을 풀 수 있습니까?

이제 위 대신에 액세스 제한을 약화한다고 상상해보십시오. 메서드를 사용하는 코드 연구를 건너 뛰고 my를 호출하는 테스트를 계속 진행합니다 exPrivateMethod. 큰? 아니!

  1. 위에서 언급 한 비공개 API의 특정 사용에 대한 테스트를 받습니까? 아니요 : nonPrivateMethod(true)이전 에는 테스트 가 없었으며 지금은 그러한 테스트가 없습니다.

  2. 외부 독자가 수업 사용법을 더 잘 이해할 수있는 기회를 얻습니까? 아니요 ? "- 잊어 버려, 그것은 내부 사용을 엄격입니다 - -. 이봐 방법의 목적은 여기에 테스트거야. 아차"

  3. 리팩토링에 내성이 있습니까? 안 돼요 :에서 변경 exPrivateMethod하면 테스트를 중단 할 수 있습니다. 이름 바꾸기, 다른 방법으로 병합, 인수 변경 및 테스트는 컴파일을 중지합니다. 두통? 내기!

요약하면 개인 방법을 고수하면 단위 테스트에서 유용하고 안정적인 기능을 향상시킬 수 있습니다. 대조적으로, "테스트 가능성"에 대한 접근 제한의 약화는 나에게 모호하고 이해하기 어려운 테스트 코드를 제공 할 뿐이다. 솔직히 내가 얻는 것은 기술 부채 처럼 보입니다 .

</ rant>


7
필자는 개인 메서드를 테스트하는 데 필요한 주장을 찾지 못했습니다. 클래스의 공개 API와 관련이없는 이유로 코드를 항상 메소드로 리팩터링하고 다른 코드를 사용하지 않고 해당 메소드를 독립적 으로 테스트 할 수있는 것이 좋습니다 . 그것이 리팩토링 한 이유입니다. 독립적 인 기능을 제공합니다. 이 기능은 독립적으로 테스트 할 수 있어야합니다.
Robert Harvey

@RobertHarvey 답변은이 문제를 해결하기 위해 폭 넓어졌습니다. "비공개 방법은 단위 테스트에 유리합니다 ..."
gnat

개인 메소드와 코드 적용 범위에 대해 어떻게 말하는지 알지만 실제로 메소드를 공개하여 테스트 할 수 있도록 옹호하지는 않았습니다. 나는 사적인 경우에도 독립적으로 테스트 할 수있는 방법을 주장했습니다. 원하는 경우 비공개 방법을 사용하는 공개 테스트를 계속받을 수 있습니다. 그리고 나는 내 개인 테스트를 할 수 있습니다.
Robert Harvey

@RobertHarvey 내가 본다. 코딩 스타일로 귀결됩니다. 필자가 일반적으로 생산하는 프라이빗 메소드의 양과 리팩터링 속도로 테스트를하는 것은 내가 감당할 수없는 사치입니다. 비공개 API는 또 다른 문제입니다. 수정이 매우 주저하고 느리게 진행되는 경향이 있습니다.
gnat

아마도 당신은 나보다 처음으로 작동하는 방법을 작성하는 것이 더 낫습니다. 나를 위해, 나는 그것이 진행하기 전에 먼저 작동하는지 확인하기 위해 방법을 테스트해야하며 일련의 다른 방법을 실행하여 간접적으로 테스트 해야하는 것은 어색하고 어색합니다.
Robert Harvey

9

가장 유력한 이유는 역사와 관련이 있습니다. Java의 조상 인 Oak는 개인, 보호, 공개의 세 가지 액세스 수준 만 가지고있었습니다.

Oak의 private은 Java의 private 패키지와 동일합니다. Oak 's Language Specification (강조 광산) 섹션 4.10을 읽을 수 있습니다 .

기본적으로 클래스의 모든 변수와 메소드 (생성자 포함)는 비공개입니다. 전용 변수와 메소드는 서브 클래스 나 다른 클래스 ( 동일한 패키지의 클래스 제외)가 아닌 클래스에서 선언 된 메소드 만 액세스 할 수 있습니다 .

따라서 Java에서 알려진 것처럼 개인 액세스는 원래 존재하지 않았습니다. 그러나 패키지에 클래스가 몇 개 이상인 경우 개인이 없으면 이름 충돌의 악몽이 발생할 수 있습니다 (예 : java.until.concurrent는 60 클래스에 가까움). 그것을 소개했다.

그러나 기본 패키지 액세스 (원래 개인) 시맨틱은 Oak와 Java간에 변경되지 않았습니다.


5

기본 액세스가 올바르게 사용되면 캡슐화를 유지하면서 향상된 테스트 기능을 제공한다고 생각합니다. 또한 개인 액세스 수정자를 중복으로 렌더링합니다.

모든 것을 공개적으로 공개하는 것보다 더 긴밀하게 묶인 두 개의 별도 클래스가 필요한 상황이 있습니다. 이것은 C ++에서 'friends'와 비슷한 아이디어를 가지고 있으며 다른 클래스의 'friend'로 선언 된 다른 클래스가 개인 멤버에게 액세스 할 수 있습니다.

BigInteger 와 같은 클래스의 내부를 살펴보면 필드와 메소드 (목록에서 파란색 삼각형 인 모든 것)에 대한 여러 패키지 기본 보호를 찾을 수 있습니다. 이것은 java.math의 패키지의 다른 클래스는 특정 작업에 대한 자신의 내장 (이러한 방법은 호출 찾을 수 있습니다 더 최적의 액세스를 가질 수 있습니다 BigDecimal를 - BigDecimal를이 BigInteger를 바탕으로하고 BigInteger를 구현 다시 저장합니다 다시를 .이 패키지 레벨 ISN되는 ' java.math는 봉인 된 패키지이므로 다른 클래스를 추가 할 수 없으므로 보호 문제가 없습니다.

반면에, 실제로는 사적인 것들이 많이 있습니다. 대부분의 패키지는 밀봉되어 있지 않습니다. 개인이 없으면 동료가 해당 패키지에 다른 클래스를 배치하고 더 이상 개인 필드에 액세스하지 않고 캡슐화를 중단 할 수 있습니다.

참고로, 단위 테스트는 보호 범위를 구성 할 때 생각했던 것이 아닙니다. JUnit (Java 용 XUnit 테스팅 프레임 워크)은 1997 년까지 고안되지 않았다 (이에 대한 이야기는 http://www.martinfowler.com/bliki/Xunit.html 에서 수있다 ). JDK의 알파 및 베타 버전은 1995 년에, JDK 1.0은 1996 년에 있었지만 JDK 1.0.2 ( private protected보호 수준을 갖기 전에)까지는 실제로 보호 수준이 떨어지지 않았습니다 .

어떤 사람들은 기본값이 패키지 수준이 아니라 개인 수준이어야한다고 주장합니다. 다른 사람들은 기본 보호 가 없어야 하지만 모든 것을 명시 적으로 언급 해야한다고 주장합니다. 이를 따르는 일부 사람들은 다음과 같은 코드를 작성합니다.

public class Foo {
    /* package */ int bar = 42;
    ...
}

거기에 의견을 적어 둡니다.

패키지 수준 보호가 기본값 인 실제 이유는 Java의 디자인 노트에서 잃어버린 것 같습니다. (파헤쳐 서 기사, 많은 사람들이 차이점을 설명하는 이유를 찾을 수 없지만 "이유가 이유입니다. ").

그래서 나는 추측을 할 것입니다. 그리고 그게 전부입니다-추측.

우선, 사람들은 여전히 ​​언어 디자인을 알아 내려고 노력했습니다. 그때부터 언어는 Java의 실수와 성공에서 배웠습니다. 이것은 모든 필드에 대해 정의해야 할 것이없는 실수로 나열 될 수 있습니다 .

  • 디자이너들은 가끔 C ++의 '친구'관계가 필요하다는 것을 알았습니다.
  • 디자이너는 명시 적 진술을 원 public하고, private이 같은 접근에 가장 큰 영향을 미칠.

따라서 개인은 기본이 아니며 잘 작동하지 않습니다. 기본 범위는 기본값으로 남아 있습니다. 그것은 되었습니다 처음 생성 된 이상 코드 엄격한 이전 버전과의 호환성의 이익, 그런 식으로 방치 범위.

내가 말했듯이, 이것들은 모두 추측 입니다.


아, 친구 기능 만 개별적으로 멤버에게 적용될 수 있다면 void someFunction ()은 클래스 X에서만 볼 수 있다고 말할 수 있습니다 ... 실제로 캡슐화를 강화합니다!
newlogic

오, 당신이 C ++에서 이것을 할 수 있기를 기다립니다. 우리는 이것을 Java로해야합니다!
newlogic

2
@ user1037729를 사용하면 두 클래스 사이를 더 밀접하게 연결할 수 있습니다. 이제 메소드가있는 클래스는 친구 인 다른 클래스를 알아야합니다. 이것은 Java가 제공하는 디자인 철학에 위배되는 경향이 있습니다. 친구와 함께 풀 수 있지만 수준의 보호를 포장하지 문제의 집합이 아닌 큽니다.

2

캡슐화는 "이것에 대해 생각할 필요가 없습니다"라고 말하는 방법입니다.

                 Access Levels
Modifier    Class   Package  Subclass   World
public        Y        Y        Y        Y
protected     Y        Y        Y        N
no modifier   Y        Y        N        N
private       Y        N        N        N

비 기술적 인 용어로 사용하십시오.

  1. 공개 : 모두가 그것에 대해 생각해야합니다.
  2. 보호됨 : 기본 클래스와 서브 클래스에 대해 알아야합니다.
  3. 기본적으로 패키지 작업을하고 있다면 패키지가 눈앞에 있음을 알 수 있습니다.
  4. 개인, 당신은이 수업에서 작업하는 경우에만 이것에 대해 알아야합니다.

개인 클래스 나 보호 클래스와 같은 것은 없다고 생각합니다 ..
Koray Tugay

@ KorayTugay : docs.oracle.com/javase/tutorial/java/javaOO/innerclasses.html을보십시오 . 내부 클래스는 비공개입니다. 마지막 단락을 읽으십시오.
jmoreno

0

테스트가 그다지 일반적이지 않았기 때문에 테스트에 중점을 두지 않았다고 생각합니다.

그들이 달성하고 싶었던 것은 패키지 수준의 캡슐화였습니다. 클래스는 내부 메소드와 필드를 가지고 있으며 공개 멤버를 통해서만 일부를 공개 할 수 있습니다. 같은 방식으로 패키지는 내부 클래스, 메소드 및 필드를 가질 수 있으며 일부만 노출 할 수 있습니다. 이런 식으로 생각하면 패키지에는 클래스, 메서드 및 필드 집합에 내부 구현이 있으며 다른 클래스, 메서드 및 필드 집합에 부분적으로 겹치는 공용 인터페이스가 있습니다.

내가 아는 가장 숙련 된 코더는 이런 식으로 생각합니다. 그것들은 캡슐화를 취하여 클래스보다 높은 추상화 레벨 (패키지 또는 원하는 경우 구성 요소)에 적용합니다. Java 디자이너가 Java를 얼마나 잘 유지하고 있는지를 고려할 때 Java 디자이너가 이미 디자인에서 성숙했음을 알 수 있습니다.


자동화 테스트는 그다지 일반적이지 않은 것이 맞습니다. 그러나 그것은 미성숙 한 디자인입니다.
Tom Hawtin-tackline
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.