Clean Code 는 "서식 지정"장의 "수직 거리"섹션에서 보호 된 변수를 피할 것을 제안합니다.
밀접하게 관련된 개념은 서로 수직으로 유지해야합니다. 분명히이 규칙은 별도의 파일에 속하는 개념에는 적용되지 않습니다. 그러나 매우 적절한 이유가 없다면 밀접하게 관련된 개념을 다른 파일로 분리해서는 안됩니다. 실제로 이것은 보호 된 변수를 피해야하는 이유 중 하나입니다 .
추론은 무엇입니까?
Clean Code 는 "서식 지정"장의 "수직 거리"섹션에서 보호 된 변수를 피할 것을 제안합니다.
밀접하게 관련된 개념은 서로 수직으로 유지해야합니다. 분명히이 규칙은 별도의 파일에 속하는 개념에는 적용되지 않습니다. 그러나 매우 적절한 이유가 없다면 밀접하게 관련된 개념을 다른 파일로 분리해서는 안됩니다. 실제로 이것은 보호 된 변수를 피해야하는 이유 중 하나입니다 .
추론은 무엇입니까?
답변:
다음과 같은 이유로 보호 된 변수를 피해야합니다.
그러나 보시다시피,이 모든 것들이 '가장 경향이 있습니다'. 때때로 보호 된 구성원이 가장 우아한 솔루션입니다. 그리고 보호 기능 에는 이러한 문제가 적은 경향이 있습니다. 그러나 그것들을 조심스럽게 다루게하는 많은 것들이 있습니다. 이런 종류의 관리가 필요한 것은 사람들이 실수를하거나 프로그래밍 세계에서 버그와 디자인 문제를 의미합니다.
나는이 책을 읽지 않았지만 밥 아저씨가 의미 한 바를 찌를 수있다.
당신이 넣으면 protected
뭔가, 그 클래스가 그것을 상속 할 수 있다는 것을 의미한다. 그러나 멤버 변수는 포함 된 클래스에 속해야합니다. 이것은 기본 캡슐화의 일부입니다. 퍼팅 protected
지금 파생 클래스는 기본 클래스의 구현 세부 사항에 액세스 할 수 있기 때문에 멤버 변수 휴식 캡슐화에. public
일반 클래스 에서 변수를 만들 때 발생하는 것과 동일한 문제입니다 .
문제를 해결하기 위해 다음과 같이 보호 된 속성에 변수를 캡슐화 할 수 있습니다.
protected string Name
{
get { return name; }
private set { name = value; }
}
이를 통해 name
기본 클래스의 구현 세부 사항을 노출시키지 않고 생성자 인수를 사용하여 파생 클래스에서 안전하게 설정할 수 있습니다.
protected
public
BaseType
DerivedType
BaseType
BaseType
protected
DerivedType
base
base
BaseType
Bob 아저씨의 주장은 주로 거리 중 하나입니다. 클래스에 중요한 개념이 있다면 개념을 해당 파일의 클래스와 함께 묶습니다. 디스크의 두 파일에서 분리되지 않습니다.
보호 된 멤버 변수는 두 곳에 흩어져 있으며 다소 마술처럼 보입니다. 이 변수를 참조, 아직 어디 ... 여기에 정의되지 않은 있다 가 정의? 따라서 사냥이 시작됩니다. protected
그의 주장을 완전히 피하는 것이 좋습니다.
이제 나는 규칙이 항상 편지에 순종해야한다고 생각하지 않습니다 (예 : 너는 사용하지 않아야 함 protected
). 상기 봐 정신 ... 그가에서지고 무엇을 하나 개의 파일로 함께 관련 일을 번들 - 그렇게 기술과 기능을 프로그래밍 사용합니다. 나는 당신이 지나치게 분석하지 말고 이것에 대한 세부 사항에 얽 히지 않는 것이 좋습니다.
이미 여기에 아주 좋은 답변이 있습니다. 그러나 한 가지 추가해야 할 사항은 다음과 같습니다.
대부분의 현대 OO 언어에서는 각 클래스를 자체 파일에 넣는 것이 좋습니다 (Java AFAIK에서는 필수).
따라서 소스 클래스에서 변수 정의에 "수직으로 가까운"기본 클래스의 보호 된 변수에 액세스하는 파생 클래스의 함수를 유지하는 것은 사실상 불가능합니다. 그러나 보호 된 변수는 내부 용으로 만들어져있어 기능을 자주 수행하는 기능이 종종 "밀접한 관련 개념"이므로이를 유지해야합니다.
기본 개념은 protected로 선언 된 "필드"(인스턴스 레벨 변수)가 원하는 것보다 더 가시적이며 원하는 것보다 덜 "보호 된"것입니다. C / C ++ / Java / C #에는 "동일한 어셈블리 내에서 자식 클래스 만 액세스 할 수있는"액세스 수정자가 없으므로 어셈블리의 필드에 액세스 할 수있는 자체 자식을 정의 할 수 있지만 다른 어셈블리에서 작성된 하위 항목에 동일한 액세스를 허용하지 않습니다. C #에는 내부 및 보호 수정자가 있지만 이들을 결합하면 "내부 및 보호"가 아닌 "내부 또는 보호"액세스가 가능합니다. 따라서 보호 대상 필드는 그 아이를 쓰든 다른 사람을 쓰든 모든 아이가 액세스 할 수 있습니다. 따라서 보호자는 해커에게 열린 문입니다.
또한 정의에 따라 필드는 필드를 변경하는 데 고유 한 검증이 거의 없습니다. C #에서는 하나의 읽기 전용을 만들 수 있습니다. 이렇게하면 값 유형을 효과적으로 일정하게 유지하고 참조 유형을 다시 초기화 할 수는 없지만 여전히 변경 가능합니다. 따라서 보호 대상이더라도 자녀 (신뢰할 수없는)는이 필드에 액세스 할 수 있으며이 필드를 유효하지 않은 것으로 설정하여 오브젝트의 상태가 일치하지 않도록합니다 (피해야 할 것).
허용되는 필드 작업 방법은 필드를 비공개로 설정하고 속성 및 / 또는 getter 및 setter 메서드를 사용하여 필드에 액세스하는 것입니다. 클래스의 모든 소비자가 가치를 필요로하는 경우 게터를 공개적으로 공개하십시오. 어린이 만 필요하면 게터를 보호하십시오.
질문에 답하는 또 다른 접근법은 스스로에게 물어 보는 것입니다. 자식 메소드의 코드가 내 상태 데이터를 직접 수정하는 기능이 필요한 이유는 무엇입니까? 그 코드에 대해 무엇을 말합니까? 그것은 얼굴의 "수직 거리"주장입니다. 부모 상태를 직접 변경 해야하는 코드가 자식에 있으면 해당 코드가 처음에 부모에 속해야합니까?
흥미로운 토론입니다.
솔직하게 말하면 훌륭한 도구를 사용하면 이러한 "수직"문제를 줄일 수 있습니다. 사실 제 생각에 "파일"이라는 개념은 실제로 소프트웨어 개발을 방해하는 것입니다. Light Table 프로젝트가 진행중인 것입니다 (http://www.chris-granger.com/2012/04/12/light- 표 --- 새로운 아이디어 개념 /).
그림에서 파일을 꺼내면 보호 범위가 훨씬 더 매력적입니다. 상속 개념이 클래스의 원래 개념을 단순히 확장하는 SmallTalk와 같은 언어에서 보호 된 개념이 가장 명확 해집니다. 부모 클래스가하는 모든 것을해야합니다.
내 생각에 클래스 계층은 가능한 한 얕아 야하며 대부분의 확장은 구성에서 나옵니다. 이러한 모델에서는 개인 변수가 보호 되지 않는 이유가 없습니다 . 확장 클래스가 부모 클래스의 모든 동작을 포함하여 확장을 나타내야한다면 (필자가 믿기 때문에 개인 메소드가 본질적으로 나쁘다고 생각합니다) 확장 클래스가 왜 그러한 데이터의 저장을 나타내지 않아야합니까?
다른 방법으로-개인 변수가 보호 변수보다 더 적합하다고 생각되는 경우 상속은 처음에는 문제의 해결책이 아닙니다.
그것이 말했듯이, 이것은 논리적으로 연결된 코드가 물리적으로 연결된 엔티티 (파일, 패키지 및 기타) 안에 있어야하는 이유 중 하나 일뿐입니다. 더 작은 규모에서 이것은 UI를 표시하는 클래스를 사용하여 패키지 내에 DB 쿼리를 만드는 클래스를 넣지 않는 이유와 동일합니다.
그러나 보호 된 변수가 권장되지 않는 주된 이유는 캡슐화를 중단하는 경향이 있기 때문입니다. 변수와 메소드는 가능한 한 제한된 가시성을 가져야합니다. 자세한 내용은 Joshua Bloch의 효과적인 Java , 항목 13- "클래스 및 멤버의 액세스 가능성 최소화"를 참조하십시오 .
그러나이 광고를 모두 길드 라인으로 삼아서는 안됩니다. 보호 된 변수가 매우 나쁘면 처음에는 언어 내부에 배치되지 않았을 것입니다. 보호 필드에 적합한 장소는 테스트 프레임 워크의 기본 클래스 내에 있습니다 (통합 테스트 클래스는이를 확장합니다).