보호 된 멤버 변수를 사용해야합니까? 장점은 무엇이며 이로 인해 어떤 문제가 발생할 수 있습니까?
답변:
보호 된 멤버 변수를 사용해야합니까?
상태를 숨기는 것에 대해 얼마나 까다로운 지에 따라 다릅니다.
개발자가 함께 와서 클래스를 하위 클래스로 지정하면 완전히 이해하지 못하기 때문에 엉망이 될 수 있습니다. 공용 인터페이스가 아닌 개인 멤버를 사용하면 작업이 수행되는 방식에 대한 구현 특정 세부 사항을 볼 수 없으므로 나중에 변경할 수있는 유연성을 제공합니다.
요즘 일반적인 느낌은 파생 클래스와 그 기반 사이에 과도한 결합을 유발한다는 것입니다.
보호 된 메서드 / 속성에 비해 특별한 이점이 없으며 (한때 약간의 성능 이점이있을 수 있음), 매우 깊은 상속이 유행하던 시대에 더 많이 사용되었지만 현재는 그렇지 않습니다.
no particular advantage over protected methods/properties
될 no particular advantage over *private* methods/properties
?
super
구성을 사용 하여 부모 생성자를 호출 할 수 있습니다 . 그런 다음 부모 클래스에서 개인 상태 변수를 초기화합니다.
일반적으로 의도적으로 공개 된 것으로 간주되지 않은 내용은 비공개로 설정합니다.
파생 클래스에서 해당 개인 변수 또는 메서드에 액세스해야하는 상황이 발생하면 개인에서 보호로 변경합니다.
이것은 거의 발생하지 않습니다. 대부분의 상황을 모델링하는 데 특히 좋은 방법이 아니기 때문에 저는 상속의 팬이 아닙니다. 어쨌든 계속해서 걱정하지 마십시오.
나는 이것이 대부분의 개발자들에게 괜찮다고 말하고 싶습니다 (그리고 아마도 그것에 대해 최선의 방법 일 것입니다).
문제의 간단한 사실은 다른 개발자가 1 년 후에 와서 개인 멤버 변수에 대한 액세스가 필요하다고 결정하면 코드를 편집하고 보호 된 것으로 변경하고 비즈니스를 계속할 것입니다.
이에 대한 유일한 예외는 바이너리 dll을 블랙 박스 형태로 제 3 자에게 배송하는 사업에있는 경우입니다. 이것은 기본적으로 Microsoft, 'Custom DataGrid Control'공급 업체 및 확장 성 라이브러리와 함께 제공되는 몇 가지 다른 대형 앱으로 구성됩니다. 당신이 그 범주에 속하지 않는 한, 이런 종류의 것에 대해 걱정하는 데 시간 / 노력을 소비 할 가치가 없습니다.
나에게 중요한 문제는 일단 변수를 보호 하면 하위 클래스가 항상 범위를 벗어날 수 있기 때문에 클래스의 어떤 메서드도 범위 내에있는 값에 의존 하도록 허용 할 수 없다는 것입니다.
예를 들어 렌더링 가능한 객체의 너비와 높이를 정의하는 클래스가 있고 해당 변수를 보호하는 경우 가로 세로 비율 (예 : 가로 세로 비율)에 대한 가정을 할 수 없습니다.
비판적으로 저는 코드가 라이브러리로 출시 된 순간부터 이러한 가정을 할 수 없습니다. 종횡비를 유지하기 위해 setter를 업데이트하더라도 변수가 setter를 통해 설정되거나 기존 코드의 게터.
내 클래스의 어떤 하위 클래스도 변수 값을 적용 할 수 없기 때문에 보장하도록 선택할 수 없습니다. 그 자신의 서브 클래스의 전체 지점의 경우에도 .
예로서:
변수를 비공개로 제한하면 setter 또는 getter를 통해 원하는 동작을 적용 할 수 있습니다.
일반적으로 보호 된 멤버 변수를 사용하는 코드를 완전히 제어 할 수있는 드문 경우로 유지합니다. 공용 API를 만드는 경우 절대로하지 않습니다. 아래에서 멤버 변수를 개체의 "속성"이라고합니다.
다음 은 private-with-accessor가 아닌 멤버 변수를 보호 한 후에 슈퍼 클래스가 할 수없는 작업입니다.
속성을 읽을 때 즉시 값을 느리게 만듭니다. 보호 된 getter 메서드를 추가하면 값을 느리게 생성하고 다시 전달할 수 있습니다.
속성이 수정되거나 삭제 된시기를 알 수 있습니다. 수퍼 클래스가 해당 변수의 상태에 대해 가정 할 때 버그가 발생할 수 있습니다. 변수에 대해 보호 된 setter 메서드를 만들면 해당 제어가 유지됩니다.
변수를 읽거나 쓸 때 중단 점을 설정하거나 디버그 출력을 추가합니다.
해당 멤버 변수를 사용할 수있는 모든 코드를 검색하지 않고 이름을 바꿉니다.
일반적으로 보호 된 멤버 변수를 만들 것을 권장하는 드문 경우라고 생각합니다. 몇 시간 후에 보호 된 변수를 수정 한 다른 코드에서 버그를 추적하는 것보다 게터 / 세터를 통해 속성을 노출하는 데 몇 분을 보내는 것이 좋습니다. 뿐만 아니라 종속 코드를 손상시키지 않고 향후 기능 (예 : 지연로드)을 추가하지 않도록 보장합니다. 지금하는 것보다 늦게하는 것이 더 어렵습니다.
디자인 수준에서는 보호 된 속성을 사용하는 것이 적절할 수 있지만 구현을 위해 접근 자 / 변이 자 메서드가 아닌 보호 된 멤버 변수에 매핑하는 이점이 없습니다.
보호 된 멤버 변수는 기본 클래스 클래스의 내부 상태에 대한 클라이언트 코드 (하위 클래스) 액세스를 효과적으로 허용하기 때문에 상당한 단점이 있습니다. 이것은 기본 클래스가 불변성을 효과적으로 유지하는 것을 방지합니다.
같은 이유로 보호 된 멤버 변수는 상수가 보장되거나 단일 스레드로 제한되지 않는 한 안전한 다중 스레드 코드 작성을 훨씬 더 어렵게 만듭니다.
접근 자 / 변이 자 메서드는 유지 관리 중에 훨씬 더 많은 API 안정성과 구현 유연성을 제공합니다.
또한 OO 순수 주의자라면 객체는 상태를 읽거나 설정하지 않고 메시지를 보내 공동 작업 / 통신합니다.
그 대가로 그들은 거의 장점을 제공하지 않습니다. 다른 사람의 코드에서 반드시 제거하지는 않지만 직접 사용하지는 않습니다.
대부분의 경우 protected를 사용하는 것은 잘못 설계된 파생 클래스에 의해 잘 분해 될 수있는 클래스의 캡슐화를 다소 깨뜨리기 때문에 위험합니다.
하지만 좋은 예가 하나 있습니다. 일종의 일반 컨테이너를 사용할 수 있다고 가정 해 보겠습니다. 내부 구현과 내부 접근자가 있습니다. 그러나 데이터에 대한 공개 액세스 권한을지도, hash_map, 벡터와 같이 3 개 이상 제공해야합니다. 그러면 다음과 같은 것이 있습니다.
template <typename T, typename TContainer>
class Base
{
// etc.
protected
TContainer container ;
}
template <typename Key, typename T>
class DerivedMap : public Base<T, std::map<Key, T> > { /* etc. */ }
template <typename Key, typename T>
class DerivedHashMap : public Base<T, std::hash_map<Key, T> > { /* etc. */ }
template <typename T>
class DerivedVector : public Base<T, std::vector<T> > { /* etc. */ }
나는 이런 종류의 코드를 한 달 전에 사용했습니다 (따라서 코드는 메모리에서 가져온 것입니다). 몇 가지 생각을 한 후, 제네릭 Base 컨테이너는 추상 클래스 여야한다고 생각합니다. 비록 그것이 꽤 잘 살 수 있더라도 Base를 직접 사용하는 것은 매우 고통 스러울 것이기 때문에 금지되어야합니다.
요약 따라서 파생 클래스에서 사용하는 데이터를 보호했습니다. 그럼에도 불구하고 우리는 Base 클래스가 추상적이어야한다는 사실을 고려해야합니다.
protected
보다 더 이상 캡슐화되지 않습니다 public
. 나는 기꺼이 틀렸다는 것을 증명할 것입니다. 당신이해야 할 일은 보호 된 멤버로 클래스를 작성하고 내가 그것을 수정하는 것을 금지하는 것입니다. protected 사용의 전체 요점은 상속을위한 것이기 때문에 클래스는 최종적이지 않아야합니다. 어떤 것이 캡슐화되어 있거나 그렇지 않습니다. 중간 상태가 없습니다.
.Net 액세스 수정 자에 대한 자세한 정보는 여기로 이동하십시오.
보호 된 멤버 변수에는 실제 장점이나 단점이 없으며 특정 상황에서 필요한 것이 무엇인지에 대한 질문입니다. 일반적으로 멤버 변수를 비공개로 선언하고 속성을 통해 외부 액세스를 활성화하는 것이 허용됩니다. 또한 일부 도구 (예 : 일부 O / R 매퍼)는 객체 데이터가 속성으로 표시 될 것으로 예상하고 공용 또는 보호 된 멤버 변수를 인식하지 못합니다. 그러나 서브 클래스 (및 서브 클래스 만)가 특정 변수에 액세스하기를 원한다는 것을 알고 있다면이를 보호 된 것으로 선언하지 않을 이유가 없습니다.