비공개 대 보호됨-가시성 실용성 문제 [닫기]


145

나는 찾고 있었고 이론적 인 차이점을 알고 있습니다.

  • 공공의 모든 클래스 / 함수가 메소드 / 프로퍼티에 액세스 할 수 있습니다.
  • 보호 이 클래스와 하위 클래스 만 메소드 / 속성에 액세스 할 수 있습니다.
  • 개인 - 만이 클래스는 메소드 / 속성에 액세스 할 수 있습니다. 심지어 상속되지도 않습니다.

그게 다 괜찮습니다. 문제는 그들 사이 의 실제 차이점은 무엇입니까? 언제 사용 private하고 언제 사용 protected하시겠습니까? 이 표준에 대해 표준 또는 수용 가능한 모범 사례가 있습니까?

지금까지 상속과 다형성의 개념을 유지하기 public위해 외부에서 액세스 해야하는 모든 것 (생성자 및 기본 클래스 기능과 같은)과 protected내부 메서드 (논리, ​​도우미 메서드 등)에 사용합니다. 내가 올바른 길을 가고 있습니까?

(이 질문은 저를위한 것이므로이 질문과 같은 질문을 보지 못했기 때문에 나중에 참조 할 수 있습니다).


33
그게 그렇게 중요한 건가? OOP를 지원하는 모든 언어에는이 문제가 있습니다. PHP로 프로그램을 작성했지만 질문이 OOP 지원 언어에 적용된다고 생각합니다.
Madara의 유령

2
당신이 태그를 잊었는지 궁금해 할 정도로 충분합니다. 이제 oop 태그가 보입니다.
Paul Bellora

클래스의 모든 속성에 대한 가시성 (비공개 / 공개 / 보호)을 설정해야합니까? 아니면 그들 중 일부만 가시성 유형이 필요합니까? 그렇다면, 클래스 상단에 가시성을 설정해야하는 속성을 결정하는 방법은 무엇입니까?
user4271704

1
한편, 보호와 개인의 차이는 분명해 보인다. 서브 클래스가 메소드 / 변수를 사용하는 경우 protected를 사용하고 그렇지 않으면 private을 사용하십시오. 특히, 서브 클래스가 부모에서 매우 유사한 개인 변수를 재정의해야하는 경우 보호하십시오.
iPherian

internalC # 언어에는 물리적 어셈블리 내에서 클래스 또는 해당 멤버의 액세스 수준을 제한하는 다른 액세스 지정자가 있습니다. 그래도 지원이나 다른 언어로 비슷한 것이 확실하지 않습니다.
RBT

답변:


128

아니요, 당신은 올바른 길을 가고 있지 않습니다. 경험상 가장 좋은 방법은 모든 것을 가능한 한 비밀로 만드는 것입니다. 이를 통해 클래스를보다 캡슐화 할 수 있으며 클래스를 사용하는 코드에 영향을주지 않고 클래스 내부를 변경할 수 있습니다.

클래스를 상속 가능하도록 디자인하는 경우 서브 클래스에서 재정의하고 액세스 할 수있는 항목을 신중하게 선택하고 보호되도록합니다 (및 액세스 가능하지만 재정의 할 수 없도록하려면 Java에 대해 이야기하십시오). 그러나 클래스의 서브 클래스를 갖도록 허용하고 보호 된 필드 또는 메소드가있는 경우이 필드 또는 메소드는 클래스의 공용 API의 일부이므로 서브 클래스를 중단하지 않고 나중에 변경할 수 없습니다.

상속되지 않는 클래스는 최종적으로 작성해야합니다 (Java). 단위 테스트를 위해 일부 액세스 규칙 (비공개, 최종, 비 최종)을 완화 할 수 있지만 문서화 한 다음 방법이 보호 되어도 무시되지 않아야한다는 점을 분명히해야합니다.


1
여기에 대한 실제 질문은 privatevs protected속성에 대한 상속을 언제 원합니까? 미래에 때때로 사용자가 내 수업을 수강하고 싶어하는지 알 수 없습니다 ...
Madara 's Ghost

16
음, 문제는 사용자가 무엇을하지 원하는 대체 할, 질문은 당신이 원하는 무엇을 할 수 오버라이드 (override) 할 수 있습니다. 일반적으로 측면을 전환하고 생각하려고 시도하는 데 도움이됩니다. 해당 클래스를 사용하고 서브 클래스를 만들면 무엇을 무시하고 싶습니까? 때때로 다른 사용자들은 여전히
잃어

3
보호 된 필드는 상속에있어 나쁜 습관입니다! . 조심하십시오. 이유는 다음과 같습니다
RBT

4
사유지는 상속 상 실제로 나쁘다!. (과장해서) 내 대답을 읽으십시오.
Larry

6
전형적인 통제 괴물 의견.
bruno desthuilliers

58

여기서는 주로 메소드 액세스에 대해 이야기하고 있으며 클래스 멤버 액세스가 아닌 최종 클래스로 표시되는 정도는 조금 적습니다 .

오래된 지혜

"좋은 이유가없는 한 비공개로 표시하십시오."

오픈 소스가 개발자 라이브러리 공간과 VCS / 종속성 관리 시스템을 지배하기 전까지는 며칠 만에 이해가되었습니다. Github, Maven 등 덕분에 하이퍼 콜라보레이션이되었습니다. 그 당시에는 라이브러리를 활용할 수있는 방법을 제한하여 돈을 벌었습니다. 나는 아마도이 "모범 사례"를 엄격히 고수하면서 경력의 처음 8 년 또는 9 년을 보냈다.

오늘 나는 그것이 나쁜 조언이라고 믿습니다. 때로는 메소드를 private 또는 class final로 표시하는 데 합리적인 주장이 있지만, 매우 드물고 심지어 개선되지 않는 경우가 있습니다.

넌 해본 적 있니:

  • 상속 및 몇 줄의 코드로 해결할 수있는 버그가있는 라이브러리 등에 실망하거나 놀랐거나 상처를 받았지만 비공개 / 최종 방법과 클래스로 인해 절대로 올 수없는 공식 패치를 기다려야합니까? 나는 가지고있다.
  • 저자가 상상 한 것과 약간 다른 유스 케이스에 라이브러리를 사용하고 싶었지만 개인 / 최종 방법 및 클래스로 인해 라이브러리를 사용할 수 없었습니까? 나는 가지고있다.
  • 확장성에 과도하게 허용되는 라이브러리 등으로 인해 실망하거나 놀랐거나 다쳤습니까? 나는하지 않았다.

다음은 기본적으로 비공개 메소드 표시에 대해 들어 본 3 가지 합리화입니다.

합리화 # 1 : 안전하지 않으며 특정 방법을 무시할 이유가 없습니다.

필자가 작성한 특정 방법을 재정의해야하는지 여부에 대해 내가 틀린 횟수를 셀 수 없습니다. 몇 가지 인기있는 오픈 소스 라이브러리에서 작업 한 후, 사물을 표시하는 실제 비용을 어려운 방법으로 배웠습니다. 예상치 못한 문제 나 사용 사례에 대한 실질적인 해결책을 종종 제거합니다. 반대로, 나는 결코 16 년 이상 전문 개발에 API 안전과 관련된 이유로 개인이 아닌 보호 된 방법을 표시하는 것을 후회 . 개발자가 클래스를 확장하고 메서드를 재정의하기로 선택하면 의식적으로 "내가하는 일을 알고 있습니다"라고 말합니다. 생산성을 위해 충분해야합니다. 기간. 위험한 경우, 클래스 / 메소드 Javadocs에서주의하십시오. 맹목적으로 문을 닫지 마십시오.

기본적으로 보호되는 마킹 방법은 현대 SW 개발의 주요 문제 중 하나 인 상상력 상실의 완화입니다.

합리화 # 2 : 공용 API / Javadoc을 깨끗하게 유지

이것은 더 합리적이며 대상 고객에 따라 올바른 일이 될 수도 있지만 API를 "깨끗하게"유지하는 비용이 실제로 무엇인지 고려할 가치가 있습니다. 위에서 언급 한 이유로, 경우에 따라 기본적으로 보호되는 항목을 표시하는 것이 더 합리적입니다.

합리화 # 3 : 내 소프트웨어는 상용이므로 사용을 제한해야합니다.

이것은 합리적이지만 소비자는 매번 품질에 차이가 거의 없다고 가정하면서 덜 제한적인 경쟁자와 함께 갈 것입니다.

절대 말하지 마

나는 결코 메소드를 비공개로 표시하지 않는다고 말하고 있지 않다. 더 나은 경험 법칙은 "좋은 이유가 없다면 방법을 보호하는 것"입니다.

이 조언은 모듈로 나뉘어 진 라이브러리 또는 대규모 프로젝트에서 작업하는 사람들에게 가장 적합합니다. 더 작거나 더 많은 모 놀리 식 프로젝트의 경우 어쨌든 모든 코드를 제어하기 때문에 그다지 중요하지 않으며 필요할 때 / 필요할 때 코드의 액세스 수준을 쉽게 변경할 수 있습니다. 그럼에도 불구하고, 나는 여전히 똑같은 조언을 줄 것입니다 :-)


Wrt your- Rationalization # 1내가 보호 된 것으로 표시하면이 행동이 최종적이 아니며 내 자녀 클래스가 그것을 무시하고 싶을 수도 있다고 생각하여 명시 적으로 선택합니다. 확실하지 않으면 기본적으로 비공개로 설정하고 싶습니다. 특히 C #과 같은 언어에서는 기본적으로 메소드를 비 가상적으로 유지하므로 보호 된 액세스 지정자를 추가하는 것은 의미가 없습니다 . 의도를 명확하게 나타내 려면 키워드 virtualprotected키워드를 모두 추가해야합니다 . 또한, 사람들은 protected
RBT

4
메서드를 재정의하는 데 필요한 키워드 조합은 언어 세부 정보 IMHO입니다. 내가 합리화 # 1에 제시 한 반론은 "내가 확실하지 않다면 ..."이라고 언급 한 경우를위한 것이다. 실제로, 그것이 왜 위험한지 생각할 수 없다면 확장 성을 선택함으로써 더 많은 것을 얻을 수 있습니다. 당신이 'association'이라고 말할 때 나는 그것을 작곡의 동의어로 생각하고 있습니다.이 경우 나는 그것이 어느 쪽이든 중요하지 않다고 생각합니다.
Nick

3
1 또는 2 또는 메서드를 재정의하고 싶었 기 때문에 기본 클래스를 "복제"해야하는 횟수가 기억 나지 않습니다. 그리고 당신이 말한 것처럼, 우리가 그 어느 때보 다 더 많은 코드를 공유한다는 사회적 추세에 따라 기본적으로 개인보다 보호를 사용하는 것이 훨씬 더 좋습니다. 즉, 자신의 논리에 더 개방적입니다.
shinkou

1
동의하다. 사용자 정의 라인 구분 기호를 처리하기 위해 Java의 BufferedReader를 조정하고 싶었습니다. 개인 필드 덕분에 단순히 클래스를 확장하고 readLine ()을 재정의하는 대신 전체 클래스를 복제해야합니다.
Ron Dunn

21

개인 필드 학대 중지!

여기의 의견은 개인 필드 사용에 대해 압도적으로지지적인 것으로 보입니다. 글쎄, 다른 말이 있습니다.

사적인 분야는 원칙적으로 좋은가? 예. 그러나 황금률 이라는 말 은 확실 하지 않을 때 모든 것을 비공개로 만드는 것입니다 . 문제가 발생할 때까지 문제가 표시되지 않습니다. 내 의견으로 는 확실하지 않은 경우 필드를 보호 된 것으로 표시해야 합니다.

클래스를 확장하려는 두 가지 경우가 있습니다.

  • 기본 클래스에 추가 기능을 추가하려고합니다
  • 현재 패키지 외부에있는 기존 클래스를 수정하려고합니다 (일부 라이브러리에서)

첫 번째 경우 개인 필드에는 아무런 문제가 없습니다. 사람들이 사적 으로 학대한다는 사실 필드를 똥을 수정할 수 없다는 것을 알게되면 너무 실망 스럽습니다.

자동차를 모델링하는 간단한 라이브러리를 고려하십시오.

class Car {
    private screw;
    public assembleCar() {
       screw.install();
    };
    private putScrewsTogether() {
       ...
    };
}

도서관 저자는 내 도서관의 사용자가 assembleCar()올바른 구현 세부 사항에 액세스해야 할 이유가 없다고 생각 했습니다. 나사를 비공개로 표시합시다.

글쎄, 저자는 틀렸다. assembleCar()전체 클래스를 패키지에 복사하지 않고 메소드 만 수정하려면 운이 좋지 않습니다. 자신의 screw필드 를 다시 작성해야 합니다. 이 자동차는 12 개의 나사를 사용하고 각각의 다른 개인 방법으로 사소한 초기화 코드가 포함되어 있으며이 나사는 모두 비공개로 표시되어 있다고 가정 해 봅시다. 이 시점에서 빨기 시작합니다.

예, 라이브러리 작성자가 더 나은 코드를 작성했을 수 있으므로 개인 필드에는 아무런 문제가 없습니다 . 개인 필드가 OOP 의 문제 라고 주장하지 않습니다. . 사람들이 사용할 때 문제가됩니다.

이야기의 교훈은 라이브러리를 작성하는 경우 사용자가 특정 필드에 액세스하려고하는지 알 수 없다는 것입니다. 확실하지 않으면 protected나중에 모두 더 행복해질 수 있도록 표시하십시오 . 최소한 개인 필드를 남용하지 마십시오 .

나는 Nick의 대답을 매우지지합니다.


2
개인 필드를 사용하는 것은 대부분 상속이 클래스 / 객체의 특정 행동을 (의식적으로 사용하는 경우) 변경하는 잘못된 추상화라고 말합니다. API를 변경하지 않고 동작이 변경되면 변경하면 일반적으로 LSP를 자동으로 위반합니다. 좋은 대답, +1
Madara의 유령

설교! 비공개는 Minecraft 모드를 작성하려고 할 때의 존재의 허무입니다. Reflection 또는 ASM을 사용하여 문제를 해결하는 것보다 더 성가신 것은 없습니다.
RecursiveExceptionException

Nick의 대답을 이해하면서 그는 주로 속성이 아닌 메소드를 언급했습니다. 매번 메소드를 private으로 선언해서는 안되며, 그 사용법을 신중히 고려해야한다고 동의하지만 cmon은 클래스를 쉽게 "다시 작성"하기를 원하기 때문에 private으로 보호 된 속성을 선언하는 것이 좋습니다. 매일 3rd p와 함께 일하면서 좌절감을 완전히 공유하지만, 사람들이 "코드가 엉망이되어 처음부터 보호하여 쉽게 다시 작성할 수 있도록하자"고 말하지 않고 견고한 아키텍처를 만들도록 권장 해 보겠습니다. 나는 당신의 좌절감을 공유하지만.
sean662

16

나는 모든 클래스를 가능한 한 많이 잠그는 것에 대해 이야기 한 기사를 읽었습니다. 일부 데이터 또는 기능을 외부에 즉시 노출시킬 필요 가없는 한 모든 것을 최종적이고 비공개로 만드십시오 . 나중에 범위를 더 허용하기 쉽게 확장 할 수 있지만 다른 방법으로는 그렇지 않습니다. 우선 가능한 한 여러 가지로 만드는 것을 고려 final사이의 선택 만들 것입니다 privateprotected훨씬 쉽게.

  1. 즉시 서브 클래스를 작성하지 않으면 모든 클래스를 최종 클래스로 만듭니다.
  2. 서브 클래 싱하고 즉시 재정의 할 필요가없는 한 모든 메소드를 최종으로 만드십시오.
  3. 메소드 본문 내에서 변경하지 않는 한 모든 메소드 매개 변수를 최종으로 지정하십시오.

이제 마지막 수업을 듣게되면 세상에 절대적으로 필요한 것이 없다면 모든 것을 비공개로 만드십시오.

서브 클래스가있는 클래스가 남아 있다면 모든 속성과 메소드를주의 깊게 검사하십시오. 먼저 해당 속성 / 메소드를 서브 클래스에 노출시키고 싶은지 고려하십시오. 그렇다면, 서브 클래스가 재정의 프로세스에서 특성 값 또는 메소드 구현을 엉망으로 만들면 오브젝트를 혼란스럽게 만들 수 있는지 고려하십시오. 가능하다면 클래스의 속성 / 메소드를 서브 클래스 (아이러니 한 소리)로부터 보호 하고 싶다면 비공개로 만드십시오. 그렇지 않으면 보호하십시오.

면책 조항 : Java로 프로그래밍하지 않았습니다. :)


2
명확히하기 위해 : final classJava의 A 는 상속 할 수없는 클래스입니다. A final method는 비 가상적입니다. 즉 서브 클래스로 대체 할 수 없습니다 (기본적으로 Java 메소드는 가상 임). A final field/parameter/variable는 불변 변수 참조입니다 (초기화 한 후에는 수정할 수 없다는 의미에서).
M.Stramm

1
재미있게도, 나는 그 반대되는 충고를 보았습니다. 문제를 무시하는 것이 불변성을 깰 가능성이 확실하지 않은 한 최종적인 것이 아니라는 정확한 조언을 보았습니다. 그렇게하면 누구나 필요에 따라 수업을 자유롭게 확장 할 수 있습니다.
GordonM

분석법 매개 변수를 "최종"으로 표시하면 이해도가 달라지는 프로그래밍 경력에서 사례 하나를 말할 수 있습니까? (컴파일러가 요구하는 경우 제외)
user949300

7

언제 사용 private하고 언제 사용 protected하시겠습니까?

개인 상속IS-A 관계가 아닌 관계 측면에서 구현 된 것으로 생각할 수 있습니다 . 간단히 말해서 상속 클래스의 외부 인터페이스는 상속 클래스와 (보이는) 관계가 없으며,private 상속을 하여 Base 클래스가 제공하는 유사한 기능을 구현합니다.

Private Inheritance와 달리 Protected 상속제한된 상속 형태로, 파생 클래스 IS-A 종류의 기본 클래스이며 파생 멤버의 액세스를 파생 클래스로만 제한하려고합니다.


2
"관계 측면에서 구현되었다"는 HAS-A 관계입니다. 모든 속성이 개인 속성 인 경우 액세스 할 수있는 유일한 방법은 메서드를 통하는 것입니다. 이것은 서브 클래스가 수퍼 클래스의 객체를 포함하는 것과 동일합니다. 구체적인 클래스에서 모든 보호 된 속성을 제거하면 모든 상속 속성도 제거됩니다.
shawnhcorey 2016 년

2
흥미로운 사고 과정 – 개인 상속 . @shawnhcorey는 HAS-A 관계 일명 연결 (집계 또는 구성 일 수 있음 )을 가리키고 있음을 명시 적으로 알려 주셔서 감사합니다 . 이 게시물도 동일하게 명확하게 업데이트해야한다고 생각합니다.
RBT

1

Paybill 클래스가 지불 청구를 처리하는 경우 캡슐화에 관한 모든 것입니다. 그렇다면 제품 클래스에서 청구 프로세스의 전체 프로세스, 즉 지불 방법을 지불하는 방법을 지불하는 방법이 필요한 이유는 무엇입니까? 다른 클래스들도 사용하는 사람들을 위해 공개하는 것 외에는 클래스를 확장하기위한 한계로만 보호됩니다. 당신이 madara uchiha이기 때문에 개인은 "limboo"당신이 그것을 볼 수있는 것처럼 (단일 클래스 만 수업합니다).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.