개인 필드가있는 이유는 무엇입니까?


265

private클래스 필드 / 속성 / 속성 의 가시성 이 유용합니까? OOP에서 조만간 클래스의 서브 클래스를 만들게되며이 경우 구현을 완전히 이해하고 수정하는 것이 좋습니다.

클래스를 서브 클래 싱 할 때 가장 먼저하는 일 중 하나는 private메서드를 로 변경하는 것 protected입니다. 그러나,에서 세부 사항을 숨기고 외부 세계하는 것은 중요합니다 - 그래서이다 우리가해야 할 protected뿐 아니라 public.

내 질문은 : 당신 은 좋은 도구 private대신 protected두 가지 옵션 " protected& public"이 OOP 언어에 충분할 중요한 유스 케이스에 대해 알고 있습니까?



236
downvoters : 나는 또한 OP의 전제에 동의하지 않지만이 질문은 완벽하게 일관되고 대답 할 가치가 있기 때문에이 질문을 반대합니다. 그렇습니다. OP는 왜 이것이 잘못되었는지 알려줘야하지만 그렇게하는 방법 은 답쓰거나 (또는 기존 답변에 대한 수정을 제안하는 것), 아직 스스로 이해하지 못했기 때문에 공감하지 않는 것입니다.
Ixrec

18
파생 클래스는 외부 세계의 일부입니다.
코드 InChaos

20
protected가 항상 상속 계층 구조에 대한 액세스 권한을 의미하는 것은 아닙니다. Java에서는 패키지 레벨 액세스도 허용합니다.
berry120

8
교수님은 "아이들에게 말하지 않을 것이 있습니다. 저의 개인 분야는 있습니다."라고 말했었습니다.
SáT

답변:


225

말했듯이 protected여전히 "구현을 완전히 수정"할 수있는 능력이 남아 있기 때문 입니다. 수업 내부의 모든 것을 진정으로 보호하지는 않습니다.

우리는 왜 교실 안에있는 물건들을“진정하게 보호”해야합니까? 그렇지 않으면 클라이언트 코드를 손상시키지 않고 구현 세부 사항을 변경할 수 없기 때문입니다 . 다시 말해, 서브 클래스를 쓰는 사람들은 원래의 기본 클래스를 쓴 사람에게 "외부 세계"이기도합니다.

실제로, protected멤버는 본질적으로 클래스의 "하위 클래스에 대한 공용 API"이며 public멤버 와 마찬가지로 안정적으로 호환성을 유지해야합니다 . 우리가 진정한 private멤버 를 생성 할 능력이 없다면 , 구현에서 악성이 아닌 클라이언트 코드가 어떻게 든 의존 할 가능성을 배제 할 수 없기 때문에 구현에서 변경하는 것이 안전하지 않습니다. 그것.

또한 "OOP에서는 조만간 클래스의 서브 클래스를 만들게됩니다"라는 말이 기술적으로 사실이지만, 당신의 주장은 "더 조만간, 서브 클래스를 모든 클래스 "는 거의 사실이 아닙니다.


11
내가 처음 private으로 이해 가 되었기 때문에 가능하다면 +1 이상을 던져 줄 것이다 . lib 퍼스펙티브는 더 자주 사용해야합니다. 그렇지 않으면 (C와 같은) "절대 제어, 절대 책임"코딩 정신을 좋아하는 사람은 "나를 자신으로부터 보호합니다"라고 표시 할 수 있습니다. 나는 여전히 private이전에 사용했지만 항상 좋은 문서를 느꼈고 이름을 _foo바꾸지 않아야한다고 말하면서 이름 이 엉망이되어서는 안된다는 것을 알았습니다 . "아무것도 깨지지 않을 것"이라고 결정적으로 말할 수있는 것은 합법적이고 private유일한 기능입니다.
abluejelly

나는 원래 공공 도서관과 프레임 워크의 코드를 무시하고 "클라이언트 코드"의 관점에서만 생각했다. 내부 구현을 최적화하는 것은 내 질문에 대한 좋은 예입니다. 실제로 이런 일이 실제로 발생한다면 (특히 많은 사람들이 클래스를 1000 줄 이하의 코드로 추천해야 할 때) 스스로에게 묻습니다. 일반적으로 루비의 접근 방식을 좋아합니다. 비공개는 일종의 추천입니다.
Adam Libuša

9
@ AdamLibuša 이것은 코드가 공개되면 훨씬 더 큰 거래이지만 모든 클래스의 클라이언트 작성자 인 경우에도 적용됩니다. 문제는 단순히 특정 리팩터링이 불가능 하고 지루하고 오류가 발생하기 쉬운 특정 리 팩터로 변경됩니다 . 최적화는 실제로 내 경험에서 이러한 리 팩터의 가장 일반적인 이유입니다 (주로 Javascript를 사용하지만). 일반적으로 다양한 내부 비트의 종속성 / 호출 그래프를 재구성 해야하는 기본 구현 결함을 노출시키는 버그와 비슷합니다. 진정으로 강력한 수정.
Ixrec

5
"조만간에, 당신은 모든 클래스의 서브 클래스를 만들 것"은 거의 사실이 아닙니다. " 그리고 요점까지는 거의 확실하지 않으며 클래스의 모든 함수를 재정의하고 클래스의 모든 데이터 요소의 사용법을 변경해서는 안됩니다. 클래스가 의미를 가지려면 논리적으로 돌로 작성해야합니다.
Jay

1
내가 할 수있는 경우에 나는 당신에게 이상 일을 던져 줄 => 즉, 우리가 @abluejelly 현상금을 부르는
토마스 아 유브

256

OOP에서는 조만간 클래스의 서브 클래스를 만들 것입니다

이것은 잘못이다. 모든 클래스가 서브 클래스로 만들어지는 것은 아니며 정적으로 유형이 지정된 OOP 언어에는 final(Java 및 C ++) 또는 sealed(C #) 과 같이 이를 방지하는 기능도 있습니다 .

구현을 완전히 이해하고 수정하는 것이 좋습니다.

아뇨. 클래스가 공용 인터페이스를 명확하게 정의하고 상속 된 경우에도 변하지 않는 것을 유지하는 것이 좋습니다.

일반적으로 액세스 제어는 구획화에 관한 것입니다. 코드의 나머지 부분과 상호 작용하는 방식을 자세히 이해하지 않고도 코드의 개별 부분을 이해하려고합니다. 개인 액세스가 가능합니다. 모든 것이 최소한 보호된다면 기본 클래스의 작동 방식을 이해하기 위해 모든 하위 클래스의 기능을 이해해야합니다.

또는 Scott Meyers의 용어로 말하자면 : 클래스의 개인 부분은 클래스 자체의 코드와 같은 유한 한 코드의 영향을받습니다.

공용 부분은 존재하는 모든 코드 비트 및 아직 작성되지 않은 모든 코드 비트에 의해 잠재적으로 영향을받습니다. 이는 무한한 코드입니다.

보호 된 부분은 기존의 모든 서브 클래스와 아직 작성되지 않은 모든 서브 클래스에 의해 잠재적으로 영향을받습니다.

결론은 보호는 공개보다 훨씬 적은 것을 제공하는 반면 개인은 실제 개선을 제공한다는 것입니다. 개인용이 아닌 의심스러운 보호 된 액세스 지정자의 존재입니다.


34
"무한한 코드의 영향을받는"이론 시나리오의 경우 +1
Broken_Window

13
아마도 C # 디자이너 virtual가이 답변에 요약 된 이유로 명시 적으로 표시되지 않는 한 상속 된 메소드를 재정의하지 않기로 결정했다는 점도 주목할 가치가 있습니다.
Will Vousden

11
간단히 말해서 : protected데이터 멤버가 아닌 메소드 용입니다.
Matthieu M.

7
지금은 찾을 수 없지만 @EricLippert sealed에서 .net 라이브러리의 MS 부분이 큰 이유와 IIRC가 왜 나머지 부분을 잠그고 싶었 는지에 대한 잘 작성된 답변을 읽은 것을 기억 합니다. 타사 상속자가 내부 값을 만지기 시작한 순간 객체 내부 상태에 대한 디자인 불변을 더 이상 신뢰할 수 없기 때문에 모든 방법에 대해 방대한 양의 유효성 검사 / 위생성 검사를 추가해야합니다.
Dan Neely

4
@ ThorbjørnRavnAndersen "개발 중이지만 풀리지 않을 때"-어떻게 지구상에서 클래스를 알아야합니까? 릴리스 버전을 테스트 할 수 없을 때 릴리스 된 버전과 다른 테스트 버전을 실제로 컴파일 하시겠습니까? 어쨌든 테스트는 개인 정보에 액세스 할 필요가 없습니다.
Sebastian Redl

33

그렇습니다, 개인 분야는 절대적으로 필요합니다. 이번 주에 나는 사전에 넣은 것을 제어하는 ​​사용자 정의 사전 구현을 작성해야했습니다. 사전 필드를 보호하거나 공개해야한다면, 내가주의 깊게 작성한 컨트롤을 쉽게 우회 할 수 있었을 것입니다.

개인 필드는 일반적으로 데이터가 원래 코더가 예상 한대로 보호를 제공하는 것에 관한 것입니다. 모든 것을 보호 / 공개하고 그 절차와 검증을 통해 코치와 말을 타십시오.


2
"코치와 말을 타십시오"+1. 더 많이 들었 으면 좋겠다는 좋은 문구입니다.
Nic Hartley

2
누군가 당신의 클래스를 서브 클래 싱해야한다면, 아마도 당신의 보호자에게 접근해야합니까? 누군가 목표를 달성하기 위해 보호 수단을 변경하지 않으려면 코드를 공유하지 않습니까? Ruby에서 이와 같이 작동합니다. 비공개는 권장 사항입니다.
Adam Libuša

3
@ AdamLibuša "코드를 공유하지 마십시오"? DLL을 게시하자마자 코드를 공유하게됩니다. 모든 구조와 방법, 그리고 전 세계가 볼 수있는 모든 것, 특히 기본적으로 리플렉션을 지원하는 언어가 있습니다. 누구나 "자신의 코드"로 원하는 것을 할 수 있습니다. private"만지지 마십시오"라는 말을하는 방식 일 뿐이며, 컴파일러 계약 내에서 시행됩니다. .NET과 같은 시스템에서는 보안에 중요한 영향을 미칩니다. 완전히 신뢰할 수있는 경우 (기본적으로 관리자 / 루트 액세스와 동일) 다른 사람의 개인 만 만질 수 있습니다.
Luaan

2
@ AdamLibuša 혼란은 주로 다른 언어가 취한 다른 OOP 접근 방식에서 비롯된 것 같습니다. OOP (원래 정의 된)의 근본은 메시징 입니다. 즉 , 응답하는 메시지를 제외한 모든 것이 비공개입니다. 대부분의 OOPish 언어에서 이는 공용 인터페이스를 가능한 한 작게 만드는 방법 인 "데이터를 비공개로 유지"로 노출됩니다. 사용자 (서브 클래스 또는 다른 클래스)가 클래스를 조작하는 유일한 방법은 사용자가 정의한 공개 인터페이스를 통해서만 가능합니다. 일반적으로 스티어링 휠과 페달을 사용하여 자동차를 운전하는 방법과 유사합니다. :
Luaan

3
@Luaan +1은 다른 사람의 개인을 만지는 것이 괜찮을 때입니다!
Nigel Touch

12

객체 지향 프로그램의 정확성에 대해 공식적으로 추론하려고 할 때 객체 불변이 포함 된 모듈 방식을 사용하는 것이 일반적 입니다. 이 접근법에서

  1. 방법은 사전 및 사후 조건 (계약)과 관련이 있습니다.
  2. 객체는 불변과 관련이 있습니다.

객체에 대한 모듈 식 추론은 다음과 같이 진행됩니다 (최소한 근사치까지).

  1. 객체의 생성자가 불변을 설정한다는 것을 증명
  2. 각각의 비 개인용 메소드에 대해, 객체 불변 및 메소드 전제 조건이 입력 보류 상태라고 가정 한 후 코드 본문이 사후 조건 및 불변이 메소드 종료를 보유 함을 암시 함을 증명하십시오.

object A위의 접근 방식을 사용하여 확인한다고 상상해보십시오 . 그리고 지금 확인 할 method gobject B호출하는 method fobject A. 모듈 식 추론을 통해 method g구현을 다시 고려할 필요없이 추론 할 수 있습니다 method f. 콜 사이트에서 의 불변 object A및 전제 조건을 설정할 수 있다면 메소드 호출의 동작에 대한 요약으로 사후 조건을 취할 수 있습니다 . 또한 우리는 호출이 반환 된 후에도 여전히 고정 유지 의 불변성을 알 수 있습니다.method fmethod g,method fA

이러한 추론의 모듈성은 우리가 큰 프로그램에 대해 공식적으로 생각할 수있게 해줍니다. 각 방법을 개별적으로 추론 한 다음이 추론의 결과를 프로그램의 더 큰 부분에 대한 추론으로 구성 할 수 있습니다.

개인 필드 는이 프로세스에서 매우 유용합니다. 객체의 불변이 해당 객체에 대한 두 개의 메소드 호출 사이에서 계속 유지됨을 알기 위해 일반적으로 중간에 객체가 수정되지 않았다는 사실에 의존합니다.

개체에 개인 필드가없는 상황에서 모듈 식 추론이 작동하려면 다른 개체가 필드를 설정 한 경우 불변이 항상 다시 설정되도록 (필드 뒤에) 확인하는 방법이 있어야합니다. 세트). 객체 필드의 가치가 무엇이든 관계없이 객체 불변을 상상하기 어렵고 프로그램의 정확성에 대한 추론에 유용합니다. 우리는 아마도 현장 접근에 관한 복잡한 규칙을 고안해야 할 것입니다. 그리고 아마도 모듈 식으로 추론 할 수있는 우리의 능력 중 일부 (최악의 경우에도)를 잃을 수도 있습니다.

보호 필드

보호 필드는 모듈 식으로 추론 할 수있는 일부 기능을 복원합니다. 언어에 따라 protected필드를 모든 서브 클래스 또는 모든 서브 클래스 및 동일한 패키지 클래스로 설정하는 기능이 제한 될 수 있습니다. 우리가 작성하는 객체의 정확성에 대해 추론 할 때 모든 서브 클래스에 액세스 할 수없는 경우가 종종 있습니다. 예를 들어, 나중에 더 큰 프로그램 (또는 여러 개의 더 큰 프로그램)에서 사용될 구성 요소 나 라이브러리를 작성 중일 수 있습니다. 일부는 아직 작성되지 않았을 수도 있습니다. 일반적으로 서브 클래 싱 될 수있는 방법과 방법을 알 수 없습니다.

그러나 일반적으로 서브 클래스에서는 확장 된 클래스와 불변의 오브젝트를 유지 보수해야합니다. 따라서 protect가 "하위 클래스"만을 의미하고 하위 클래스가 항상 수퍼 클래스의 불변성을 유지하도록 훈련 된 언어의 경우 개인 대신 보호를 사용하는 선택은 최소한의 모듈성을 잃을 수 있다고 주장 할 수 있습니다 .

공식적인 추론에 대해 이야기했지만, 프로그래머가 코드의 정확성에 대해 비공식적 인 이유를 말할 때 종종 비슷한 유형의 인수에 의존 한다고 생각 합니다.


8

private클래스의 변수 는 블록 내부의 명령문이 명령문 보다 낫다 protected는 동일한 이유 보다 낫습니다 . 즉, 인간 프로그래머 는 오류가 발생하기 쉽다는 것입니다. breakswitchgoto label

protected변수가 goto성명서가 스파게티 코드를 만드는 것과 마찬가지로 의도 치 않은 남용 (프로그래머 실수)에 적합합니다.

protected클래스 변수를 사용하여 버그가없는 작동하는 코드를 작성할 수 있습니까? 네 물론 이죠! goto;을 사용하여 버그없는 코드를 작성할 수있는 것처럼 ; 그러나 진부한 상황이 "그냥 할 수 있다고 해서 꼭 그래야하는 것은 아닙니다!"

실수, 오류가 발생하기 쉬운 인간 프로그래머가 실수를 저 지르지 않도록 클래스와 실제 OO 패러다임이 존재합니다. 인간의 실수에 대한 방어는 계급에 구축 된 방어 조치만큼이나 좋습니다. 클래스를 구현 protected하는 것은 요새 벽에 거대한 구멍을내는 것과 같습니다.

기본 클래스에는 파생 클래스에 대한 지식이 전혀 없습니다. 기본 클래스와 관련 하여 파생 클래스 가 백도어처럼 동작 하는 게터 / 세터를 만드는 것을 막을 수는 없기 때문에 protected실제로보다 더 많은 보호 기능을 제공하지 않습니다 .publicpublic

기본 클래스가 내부 구현 세부 사항에 대한 방해받지 않은 액세스를 허용하면 클래스 자체가 실수로부터 방어하는 것이 불가능 해집니다. 기본 클래스에는 파생 클래스에 대한 지식이 없으므로 파생 클래스에서 실수를 막을 방법이 없습니다.

기본 클래스가 할 수있는 최선의 방법은 가능한 한 많은 구현을 숨기고 private파생 클래스 또는 클래스 외부의 다른 항목에서 변경 사항을 방지하기 위해 충분한 제한을 설정하는 것입니다.

궁극적으로 인적 오류를 최소화하기 위해 고급 언어가 존재합니다. 인적 오류를 최소화하기위한 좋은 프로그래밍 방법 (예 : SOLID 원칙 )도 있습니다.

좋은 프로그래밍 방식을 무시하는 소프트웨어 개발자는 실패 가능성이 훨씬 높으며 유지 관리 할 수없는 깨진 솔루션을 생성 할 가능성이 높습니다. 모범 사례를 따르는 사람들은 실패 가능성이 훨씬 낮으며 유지 관리 가능한 작업 솔루션을 생산할 가능성이 높습니다.


downvoter에게-이 답변에 대해 무엇을 변경 / 향상시킬 수 있습니까?
Ben Cottrell

나는 투표하지 않았지만 액세스 레벨을 break / goto와 비교합니까?
imel96

@ imel96 아니오, 피해야하는 이유를 비교하고 "최상의 실천"(특히 코드 작성 )에 의해 권장되지 않습니다 . 즉, 유능한 프로그래머는 public구현할 수없는 코드에 적합하기 때문에 구현 세부 사항을 피할 수 있습니다. 유능한 프로그래머는 goto유지할 수없는 코드에 적합하기 때문에 피할 수 있습니다. 그러나 실제 세계는 때로는 레거시 코드의 엉망으로 길을 잃고 사용할 수밖에 없으며 goto, 같은 이유로 때로는 공개 / 보호 구현 세부 사항을 사용할 수밖에 없습니다.
Ben Cottrell

심각도는 크기가 다르며 비교할 수 없습니다. 나는 단지이 코드로 살 수 public뿐만 아니라 사용하는 코드로, 속성 / 인터페이스를 goto.
imel96

2
@ imel96 실제로 goto기사를 읽었 기 때문에 사용하는 코드에서 실제로 작업 한 적이 있습니까? 나는 그것을 사용하는 고대 코드에서 2 년을 보냈기 때문에 goto 악한 이해 한다. 그리고 "클래스"에서 구현 세부 정보가 어디에서나 유출 public되고 friend지정자가 빠르거나 쉬운 / 더러운 해킹으로 사용되는 코드에서 더 오래 작업했습니다 . "구현 세부 사항을 공개적으로 공개" goto한다고해서 절대적으로 할 수 있기 때문에 같은 수준의 심각도에서 얽힌 스파게티 엉망을 유발할 수 없다는 주장을 받아들이지 않습니다 .
Ben Cottrell

4

상속 가능한 클래스에는 두 개의 계약이 있습니다. 하나는 객체 참조 보유자와 파생 클래스입니다. 공개 멤버는 참조 보유자와의 계약에 구속되며 보호 멤버는 파생 클래스와의 계약에 구속됩니다.

멤버를 protected만들면보다 다양한 기본 클래스가되지만, 이후 버전의 클래스가 변경 될 수있는 방법이 제한되는 경우가 많습니다. 멤버를 만들면 private클래스 작성자는 클래스의 내부 작업을 변경할 수있는 다양한 기능을 사용할 수 있지만 클래스 클래스에서 유용하게 파생 될 수있는 클래스의 종류는 제한됩니다.

예를 들어, List<T>.NET에서는 백업 저장소를 개인용으로 만듭니다. 만약 그것이 보호된다면, 파생 된 타입은 다른 방법으로는 불가능한 몇 가지 유용한 일을 할 수 있지만, 미래 버전의 버전은 List<T>수백만 개의 아이템을 보유한 목록에도 영리한 모 놀리 식 백업 스토어를 영원히 사용해야합니다. 백킹 스토어를 비공개로 만들면 향후 버전의 List<T>파생 클래스를 파생시키지 않고보다 효율적인 백킹 스토어를 사용할 수 있습니다.


4

나는 누군가가 수업작성할 때 누가 그 수업을 그 길로 확장시킬 수 있는지 그리고 어떤 이유로 알지 못한다고 주장하는 주요 가정이 있다고 생각합니다 . 이러한 가정을 감안할 때 여러분이 주장하는 모든 변수는 잠재적으로 개발 과정을 중단시킬 수 있기 때문에 완벽하게 이해 될 것입니다. 그러나 나는 그 가정을 거부 할 것입니다.

그 가정이 기각되면 두 가지 경우 만 고려해야합니다.

  1. 원래 클래스의 저자는 왜 확장 될 수 있는지에 대한 명확한 아이디어를 가지고있었습니다 (예 : BaseFoo이고 여러 구체적인 Foo 구현이 진행될 것입니다).

이 경우, 저자는 누군가가 수업을 확장 할 것임을 알며, 왜 보호해야하는지, 무엇을 비공개로해야하는지 정확히 알 것입니다. 이들은 개인 / 보호 된 구별을 사용하여 서브 클래스를 작성하는 사용자에게 일종의 인터페이스를 전달합니다.

  1. 자식 클래스의 작성자는 일부 동작을 부모 클래스로 해킹하려고합니다.

이 경우는 드 물어야하며 (합법적이지 않다고 주장 할 수 있음) 원래 코드 기반에서 원래 클래스를 수정하는 것만으로는 바람직하지 않습니다. 나쁜 디자인의 증상 일 수도 있습니다. 이 경우 행동에서 해킹하는 사람이 친구 (C / C ++) 및 setAccessible(true)(Java) 와 같은 다른 해킹을 사용하는 것을 선호합니다 .

나는 그 가정을 거부하는 것이 안전하다고 생각합니다.

이것은 일반적으로 상속보다 구성 에 대한 아이디어로 되돌아갑니다 . 상속은 종종 코드 재사용을 줄이는 이상적인 방법으로 가르쳐 지지만 코드 재사용을위한 첫 번째 선택은 거의 없습니다. 나는 간단한 넉다운 주장이 없으며 이해하기가 상당히 어렵고 논쟁의 여지가 있습니다. 그러나 도메인 모델링에 대한 경험에서 클래스를 상속받을 사람과 이유를 명확하게 이해하지 않고 상속을 거의 사용하지 않는다는 것을 알았습니다.


2

세 가지 액세스 수준 모두 유스 케이스가 있으며 OOP에는 그 중 어느 것도 부족합니다. 보통은

  • 모든 변수 / 데이터 멤버를 비공개로 설정하십시오 . 외부의 누군가가 내부 데이터를 망칠 필요는 없습니다. 또한 공용 또는 보호 된 인터페이스 에 보조 기능 (여러 멤버 변수를 기반으로 계산)을 제공하는 방법 은 내부 용이며 향후 변경 / 개선 할 수 있습니다.
  • 수업의 일반적인 인터페이스를 공개하십시오 . 그것이 원래 클래스의 사용자와 함께해야 할 일이며 파생 클래스도 어떻게 보일지에 대한 생각입니다. 적절한 캡슐화를 제공하기 위해 이들은 일반적으로 변수가 아닌 메서드 (및 사용자가 메서드로 작업 해야하는 도우미 클래스 / 구조체, 열거 형, typedef)입니다.
  • 클래스의 기능을 확장 / 특수화하고 싶지만 공개 인터페이스의 일부가되어서는 안되는 사람이 사용할 수있는 보호 된 메소드를 선언하십시오 . 실제로는 필요할 때 개인 멤버를 보호 할 수 있습니다. 의심이가는 경우, 알 때까지
    1. 수업은 서브 클래 싱 될 수 있고 /하거나 /
    2. 서브 클래 싱의 사용 사례가 무엇인지 명확하게 알 수 있습니다.

그리고 당신은 good reason ™ 이있는 경우에만이 일반적인 계획에서 벗어납니다 . "이것은 외부에서 자유롭게 액세스 할 수있을 때 내 인생을 더 쉽게 만들어 줄 것입니다."( 여기서 외부 에도 서브 클래스가 포함됨)에주의하십시오. 클래스 계층을 구현할 때 서브 클래 싱 / 확장 / 전문화를 통해 프레임 워크 / 툴킷의 기본 클래스가되고 때로는 원래 기능의 일부를 한 수준 위로 이동하기 전까지는 멤버를 보호하지 않는 클래스로 시작하는 경우가 많습니다.


1

아마도 더 흥미로운 질문은 개인이 아닌 다른 유형의 필드가 필요한 이유 일 것입니다. 서브 클래스가 수퍼 클래스의 데이터와 상호 작용해야하는 경우, 그렇게하면 서브 클래스간에 직접 결합이 이루어 지지만 두 클래스 사이의 상호 작용을 제공하는 메소드를 사용하면 그렇지 않으면 매우 어려운 수퍼 클래스.

여러 언어 (예 : Ruby 및 Smalltalk)는 공개 필드를 제공하지 않으므로 개발자가 클래스 구현에 직접 연결하는 것을 권장하지는 않지만 더 나아가 개인 필드 만있는 이유는 무엇입니까? 수퍼 클래스는 항상 서브 클래스에 보호 된 접근자를 제공 할 수 있기 때문에 일반성이 손실되지 않지만 클래스는 항상 서브 클래스로부터 최소한의 격리 수준을 유지해야합니다. 이것이 더 일반적인 디자인이 아닌 이유는 무엇입니까?


1

여기에 많은 좋은 답변이 있지만 어쨌든 나는 2 센트를 넣을 것입니다. :-)

글로벌 데이터가 나쁜 것과 같은 이유로 개인이 좋습니다.

클래스가 개인 데이터를 선언하면이 데이터를 혼란스럽게하는 유일한 코드는 클래스의 코드라는 것을 알고 있습니다. 버그가있는 경우이 데이터를 변경할 수있는 모든 장소를 찾기 위해 모든 생성을 검색 할 필요는 없습니다. 수업 중이라는 것을 알고 있습니다. 코드를 변경하고이 필드가 사용되는 방식에 대해 무언가를 변경하면이 필드를 사용할 수있는 모든 잠재적 위치를 추적하고 계획된 변경으로 인해 문제가 발생하는지 여부를 연구 할 필요가 없습니다. 당신은 유일한 장소가 수업 안에 있다는 것을 알고 있습니다.

라이브러리에 있고 여러 앱에서 사용하는 클래스를 변경해야하는 횟수가 여러 번 있었으며, 내가 알지 못하는 일부 앱이 중단되지 않도록주의해서 밟아야합니다. 공개적이고 보호 된 데이터가 많을수록 문제가 발생할 가능성이 높습니다.


1

나는 의견이 맞지 않는 의견을 언급 할 가치가 있다고 생각합니다.

이론적으로는 다른 답변에서 언급 한 모든 이유로 액세스 수준을 제어하는 ​​것이 좋습니다.

실제로 코드를 검토 할 때 개인을 사용하는 사람들이 개인-> 보호 및 보호-> 공개에서 액세스 수준을 변경하는 것을 보았습니다. 거의 항상 클래스 속성을 변경하면 setter / getter를 수정해야합니다. 이것들은 내 시간 (코드 검토)과 그들의 시간 (코드 변경)을 낭비했습니다.

또한 클래스가 수정을 위해 닫히지 않았 음을 의미합니다.

필요한 경우 언제든지 변경할 수있는 내부 코드가 있습니다. 코드를 변경하기가 쉽지 않은 타사 코드의 경우 상황이 더 나쁩니다.

얼마나 많은 프로그래머들이 번거 롭다고 생각합니까? 개인이없는 프로그래밍 언어를 사용하는 사람은 몇 명입니까? 물론 사람들은 개인 지정자가 없기 때문에 해당 언어를 사용하는 것이 아니라 언어를 단순화하는 데 도움이되며 단순성이 중요합니다.

Imo 동적 / 정적 입력과 매우 유사합니다. 이론적으로 정적 타이핑은 매우 좋습니다. 실제로 는 동적 입력의 불합리한 효과의 2 % 만 방지 합니다. private을 사용하면 그보다 적은 오류를 방지 할 수 있습니다.

저는 SOLID 원칙이 좋다고 생각합니다. 사람들이 공개, 보호 및 개인으로 수업을 만드는 것보다 더 많은 관심을 갖기를 바랍니다.


1
타사 코드를 사용할 때 변경해야하는 경우 잘 설계되지 않았거나 재사용하지 않는 것입니다. 비 추상적 인 클래스는 항상 캡슐화하여 재사용 할 수 있지만 실제로는 서브 클래스를 만들 필요가 없습니다.
Little Santi

0

또한 왜 protected충분하지 않은지에 대한 또 다른 실용적인 예를 추가하고 싶습니다 . 우리 대학에서는 첫 해에 보드 게임의 데스크톱 버전을 개발해야하는 프로젝트를 수행했습니다 (나중에 AI가 개발되어 네트워크를 통해 다른 플레이어와 연결됨). 테스트 프레임 워크를 포함하여 시작하기 위해 일부 부분 코드가 제공됩니다. 메인 게임 클래스의 속성 중 일부는이 protected클래스를 확장하는 테스트 클래스가 액세스 할 수 있도록 노출됩니다 . 그러나 이러한 필드는 민감한 정보가 아닙니다.

장치에 대한 TA로서 나는 종종 학생들이 단순히 모든 추가 된 코드 만들기 참조 protected또는 public(그들은 다른보고 아마도 때문에 protected하고 public물건을 그들이 소송을 따라야 가정). 나는 그들의 보호 수준이 부적절한 이유를 묻습니다. 많은 사람들이 이유를 모릅니다. 대답은 그들이 서브 클래스에 노출하는 민감한 정보는 다른 플레이어가 단순히 그 클래스를 확장하고 게임에 대한 매우 민감한 정보에 접근함으로써 속임수를 사용할 수 있다는 것입니다. 일부 클래스를 확장하여 전함 보드에서 상대편을 볼 수 있습니다). 게임의 맥락에서 코드를 매우 위험하게 만듭니다.

그 외에는 하위 클래스조차도 무언가를 비공개로 유지해야하는 다른 많은 이유가 있습니다. 자신이하는 일을 반드시 알지 못하는 사람 (주로 코드를 사용하는 다른 사람들에 대한 생각)에 의해 변경되면 클래스의 올바른 작업을 망칠 수있는 구현 세부 사항을 숨길 수 있습니다.


1
이해가 안 돼요 게임이 진행되는 동안 플레이어가 동적으로 수업을 확장하지 않는 한, 어떻게 이것을 속이는 데 사용할 수 있습니까? 이것은 신뢰할 수없는 코드를 코드베이스로 가져오고 있음을 의미합니다. 학생들에게 컴파일 된 클래스를 제공하고 구현 세부 사항을 수정하여 과제에서 부정 행위를하지 않는다고 말하는 경우 보호 수준을 설정해도 과제가 더 안전하게 이루어지지는 않습니다. 학생들은 라이브러리를 디 컴파일하거나 자신의 장점을 반영 할 수 있습니다. 이것은 물론 당신이 따르는 집행 수준에 달려 있습니다.
Sam

@sam 일반적으로 다음에 코드를 수정하는 사람은 전체 코드베이스를 알 필요가 없다는 가정하에 코드를 작성해야합니다. 시간이 지남에 수면 부족 등의 최초의 저자 일 수도 있습니다. 부정 행위는 학생들이 살을 빼기 위해 골격 코드를 받고, 만져서는 안되는 논리를 바꿀 수 있습니다.
Phil Lello

0

프라이빗 메소드 / 변수는 일반적으로 서브 클래스에서 숨겨집니다. 좋은 일이 될 수 있습니다.

개인 메소드는 매개 변수에 대한 가정을하고 호출자에게 상태 점검을 남길 수 있습니다.

보호 된 방법 입력을 확인 해야합니다 .


-1

"개인"이란 클래스 자체를 제외한 다른 사람이 변경하거나 액세스 할 수 없습니다. 서브 클래스가 변경하거나 액세스 할 수 없습니다. 서브 클래스? 어떤 서브 클래스? 이것을 서브 클래스 화해서는 안됩니다!

"protected"는 클래스 또는 서브 클래스에 의해서만 변경되거나 액세스되도록 의도 된 것입니다. 당신이 서브 클래스를해야한다는 공제 일 것입니다. 그렇지 않으면 왜 "비공개"가 아닌 "보호"입니까?

여기에는 분명한 차이점이 있습니다. 내가 사적인 것을 만들면 더러운 손가락을 떼어 놓아야합니다. 서브 클래스 인 경우에도 마찬가지입니다.


-1

클래스를 서브 클래 싱 할 때 가장 먼저하는 일 중 하나는 개인 메소드를 보호하도록 변경하는 것입니다

privateprotected 방법 에 대한 몇 가지 추론 :

private메소드는 코드 재사용을 방지합니다. 서브 클래스는 개인용 메소드에서 코드를 사용할 수 없으며이를 다시 구현해야합니다. 또는 원래 개인용 메소드 & c에 의존하는 메소드를 다시 구현해야합니다.

반면에 다른 사람이 자신의 답변에서 제안한 것처럼 타사 하위 클래스도 "외부 세계"로 간주된다는 점에서 클래스가 "외부 세계"에 제공하는 API로 볼 수 없는 방법 private으로 볼 수 있습니다 이미.

그게 나쁜가요? -나는 그렇게 생각하지 않습니다.

물론 (의사) 공개 API는 원래 프로그래머를 잠그고 해당 인터페이스의 리팩토링을 방해합니다. 그러나 다른 방법으로 보았을 때 프로그래머가 왜 자신의 "구현 세부 사항"을 공개 API만큼 깨끗하고 안정적인 방식으로 디자인하지 않아야합니까? private"개인"코드를 구성하는 데 실수를 할 수 있도록 사용해야합니까 ? 아무도 알아 채지 못해서 나중에 청소할 수 있다고 생각하십니까? - 아니.

프로그래머는 자신의 "비공개"코드에 대해서도 약간의 생각을 기울여야하며, 처음부터 가능한 많은 코드를 재사용하도록 허용하거나 심지어 촉진하는 방식으로 코드를 구성해야합니다. 그러면 비 개인 부분은 미래에 어떤 두려움만큼 부담이되지 않을 수 있습니다.

필자가 본 많은 (프레임 워크) 코드는 일관성없는 사용을 채택합니다 private. : protected비 최종 메서드는 개인 메서드에 위임하는 것 이상을 거의 수행하지 않습니다. protected비공개 필드에 대한 직접 액세스를 통해서만 계약을 이행 할 수있는 비 최종 방법.

기술적으로는 (컴파일러) 명백하게 할 것이 없지만, 이러한 메소드는 논리적으로 재정의 / 향상 될 수 없습니다.

확장 성과 상속을 원하십니까? 당신의 방법을 만들지 마십시오 private.

수업의 특정 행동을 바꾸고 싶지 않습니까? 당신의 방법을 확인하십시오 final.

정의 된 특정 컨텍스트 외부에서 메소드를 호출 할 수 없습니까? 메소드 private를 작성하거나 다른 protected랩퍼 메소드를 통해 재사용하기 위해 필요한 잘 정의 된 컨텍스트를 사용 가능하게하는 방법에 대해 생각하십시오 .

그렇기 때문에 나는 private아껴서 사용하는 것을 옹호합니다 . 그리고 혼동하지하기 privatefinal. -메소드의 구현이 클래스의 일반 계약에 필수적이므로 대체 / 재정의되어서는 안됩니다 final!

필드의 경우 private실제로 나쁘지 않습니다. 적절한 방법을 통해 필드를 합리적으로 "사용"할 수있는 한 ( 그렇지 getXX() 않거나 setXX()!).


2
-1 이것은를 해결하지 않는 privateprotected원래의 질문에, 잘못된 조언을 제공 ( "사용 private아껴서?")과 OO 디자인에 대한 일반적인 합의에 간다. 사용은 private단 정치 못한 코드를 숨기고과는 아무 상관이 없습니다.
Andres F.

3
클래스에 API가 있지만 API 사용자가 알 필요가없는 세부 사항으로 인해 부담을 느끼고 싶지 않다는 것을 언급하지 않는 것 같습니다. 클래스 사용자에게 이상적인 상황은 인터페이스에 필요한 메소드 만 포함하고 다른 것은 포함하지 않는 것입니다. 메소드를 작성 private하면 API를 깨끗하게 유지할 수 있습니다.
Ben Cottrell

1
@HannoBinder 나는 강성을 겪는 클래스가 많이 있다는 것에 동의하지만 유연성과 코드 재사용은 캡슐화 및 장기 유지 관리보다 훨씬 덜 중요합니다. 모든 클래스에 보호 멤버가 있고 파생 클래스가 원하는 구현 세부 정보를 망칠 수있는 경우를 고려하십시오. 아직 작성되지 않은 코드의 어떤 부분이라도 해당 코드가 언제라도 실패 할 수 있다는 것을 알고 클래스를 어떻게 안정적으로 단위 테스트합니까? 코드가 큰 진흙 덩어리로 변질되기 전에 얼마나 많은 그러한 "해킹"이 필요합니까?
벤 Cottrell

2
오, "회원"이라고 했잖아 내가 말하는 것은 방법 만 언급하고 있습니다 . 멤버 변수 (필드)는 프라이버시가 훨씬 정당화되는 다른 이야기입니다.
JimmyB

2
토론의 명명법은 특정 언어에 국한되지 않기 때문에 모든 곳에서 사용됩니다. C ++의 "멤버"는 데이터, 함수, 유형 또는 템플릿 일 수 있습니다.
JDługosz

-1

protected 대신 private이 유용한 도구 인 중요한 유스 케이스에 대해 알고 있거나 OOP 언어에 대해 "protected & public"두 옵션으로 충분합니까?

Private : 서브 클래스가 호출하거나 재정의하는 데 결코 유용한 것이없는 경우.

보호 : 서브 클래스 특정 구현 / 상수가있는 것을 가질 때.

예를 들면 :

public abstract Class MercedesBenz() extends Car {
  //Might be useful for subclasses to know about their customers
  protected Customer customer; 

  /* Each specific model has its own horn. 
     Therefore: protected, so that each subclass might implement it as they wish
  */
  protected abstract void honk();

  /* Taken from the car class. */
  @Override
  public void getTechSupport(){
     showMercedesBenzHQContactDetails(customer);
     automaticallyNotifyLocalDealer(customer);
  }

  /* 
     This isn't specific for any subclass.
     It is also not useful to call this from inside a subclass,
     because local dealers only want to be notified when a 
     customer wants tech support. 
   */
  private void automaticallyNotifyLocalDealer(){
    ...
  }
}

2
서브 클래스가 호출하거나 재정의하는 데 결코 도움이되지 않는 것이있을 때 – 이것은 제 생각에 미리 알 수없는 것입니다.
Adam Libuša

CMOS에서 리셋 버튼을 눌러야 할 수도 있습니다. 그러나 기본 가정은 실제로 필요하지 않으므로 섀시 안에 넣는 것입니다. 방법도 마찬가지입니다. 서브 클래스가이를 다시 구현 / 호출해야하는 경우이를 보호합니다 (호닝 참조). 다른 사람이 전화해야 할 경우 공개합니다.
Arnab Datta

-2

이 문제를 이해하기가 어려웠으므로 내 경험을 공유하고 싶습니다.

  • 보호 필드 는 무엇입니까 ? 그것은 없다 아무것도 즉, 클래스 외부에 액세스 할 수없는 필드보다 공개적으로 다음과 같이 : $classInstance->field. 그리고 이것이 "이것"이라는 속임수입니다. 수업의 아이들은 정당한 내부 부분이기 때문에 전체 액세스 권한을 갖습니다 .
  • 개인 분야 는 무엇입니까 ? 그것은 "의 진정한 개인 자신 만의 클래스" 이 클래스의 당신의 고유의 구현입니다. 약병처럼 "어린이의 손이 닿지 않는 곳에 보관하십시오". 라고 - -있을 것이다 당신은 당신의 클래스의 파생 상품, 당신의 방법으로 unoverridable의 보장해야합니다 정확한 당신이 선언 한 내용을

업데이트 : 내가 해결 한 실제 작업에 의한 실제 예. 여기 있습니다 : USB 또는 LPT와 같은 토큰 (내 경우에는)이 있고 미들웨어가 있습니다. 토큰은 PIN 코드를 요청하고 올바른지 열어서 암호화 된 부분과 여러 키를 해독 할 수 있습니다. 키는 토큰에 저장되어 있으므로 읽을 수 없으며 사용하십시오. 그리고 세션의 임시 키 가 있었고 토큰의 키로 서명되었지만 미들웨어 자체에 저장되었습니다. 임시 열쇠는 외부에서 새는 곳으로 누출되지 않았으며 운전자 수준에서만 존재했습니다. 그리고 개인 필드를 사용하여이 임시 키와 일부 하드웨어 연결 관련 데이터를 저장했습니다. 따라서 파생 제품은 공용 인터페이스뿐만 아니라 일부 보호 기능 도 사용할 수 없었습니다.작업을 위해 만든 "handy"서브 루틴이지만 키와 HW 상호 작용으로 금고를 열 수 없었습니다. 맞는 말이다?


미안 해요! 방금 엉망이되었습니다-내 대답을 업데이트 =) 감사합니다! 나는 서두르고 잘못 입력했다 =)
Alexey Vesnin

2
OP는 두 보호 수준의 차이점을 알고 있지만 한 가지를 다른 것보다 사용해야하는 이유에 관심이 있다고 생각합니다.
Sam

@ Sam 내 답변을 자세히 읽으십시오. 그들은 완전히 다른 유형의 분야입니다! 단지 그들이 공통적으로 가지고있는 것은 그들이 모두 공개적으로 참조 할 수 없다는 것입니다
알렉세이 Vesnin

2
당신이 무엇을 말하는지 잘 모르겠습니다. 개인과 보호의 차이점을 알고 있습니다. 아마도 당신은 내가 보호 수준의 의미를 잘못 이해했을까요? 나는 '액세스 수준'을 언급하고 있습니다. 귀하의 답변이 나쁘지는 않지만 질문을 직접 해결하지는 않습니다. OP는 보호 / 개인 / 공공 모두의 의미를 알고있는 것으로 보이지만 어떤 상황에서 다른 것을 선택하려고하는지 확실하지 않습니다. 이것은 당신이 투표 한 방식 일 수도 있습니다 (나가 아닌).
Sam

@ Sam 나는 당신의 요점이 있다고 생각합니다-실제 연습 / 경험에서 실용적인 사례를 추가했습니다. 요점에서 빠진 것이 있습니까?
Alexey Vesnin
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.