2010-03-28 3 views
6

나는 항상 public, protectedprivate 속성에 대해 궁금해했습니다. 내 기억은 에 누군가의 코드를 해킹하기 위해이 있었고 해킹 된 클래스 변수가 private으로 선언 된 경우 항상 화가 났던시기를 쉽게 기억할 수 있습니다.비공개 대 공개에 대한 실용적인 관점

또한 내가 직접 수업을 작성했으며 그 재산을 사유화하는 잠재적 이득을 전혀 인식하지 못했습니다. 공공 vars를 사용하는 것은 이 아니라 내 습관에입니다. getter와 setter를 활용하여 OOP의 원칙을 고수합니다.

그래서 이러한 제한 사항은 무엇입니까?

+0

모든 것이 게터와 세터를 사용하지 않기를 바랄뿐입니다. 일반적으로 구현 세부 사항을 노출함으로써 OOP의 원칙을 위반합니다. –

답변

7

개인공공의 사용은 캡슐화라고합니다. 소프트웨어 패키지 (클래스 또는 모듈)가 내부와 외부를 필요로한다는 것은 간단한 통찰력입니다.

외부 (공개)는 전 세계와의 계약입니다. 당신은 그것을 간단하고, 일관되고, 분명하고, 절대적이며, 매우 중요하고, 안정하게 유지하려고 노력해야합니다.

좋은 소프트웨어 디자인에 관심이 있다면 규칙은 간단합니다. 모든 데이터를 비공개로 설정하고 필요할 때만 메소드를 공개로 설정하십시오.

데이터를 숨기는 원칙은 클래스의 모든 필드의 합계가 상태 인을 정의한다는 것입니다. 잘 쓰여진 클래스의 경우 각 객체는 유효한 상태를 유지해야합니다. 주정부의 일부가 공개 인 경우, 학급은 그러한 보장을 절대로 제공 할 수 없습니다.

class MyDate 
{ 
    public int y, m, d; 
    public void AdvanceDays(int n) { ... } // complicated month/year overflow 
    // other utility methods 
}; 

당신은 AdvanceDays을 (무시하는 클래스의 사용자를 막을 수 없습니다) 간단하게 수행합니다 :

작은 예를 들어, 우리가 가정

date.d = date.d + 1; // next day 

을하지만 당신이 만드는 경우 y, m, d 개인 및 귀하의 모든 MyDate 방법을 테스트하면 은 시스템에 유효한 날짜 만 있다는 것을 보장 할 수 있습니다.

+0

네, 맞아요. 그러나 'AdvanceDays'에서 끔찍한 실수를하면 어떻게 될까요? 모든 데이터가 비공개 인 경우 내 수업의 사용자가 문제를 해결할 수 없습니다. –

+1

분명히 여기서 다른 방향으로 작업하고 있습니다. 귀하의 사용자는 단지 당신을 걷어차 야합니다 (: –

+0

만약 내가 그것을 모두 공개했다면, 그들은 필요 없을 것입니다) –

2

개인 키워드는 노출하려는 속성을 사유화하기 위해 사용해서는 안되며 클래스의 내부 코드를 보호하기 위해 사용해서는 안됩니다. 모든 사람들이 액세스 할 수있는 코드에서 숨겨져 있어야하는 코드 부분을 정의하는 데 도움을주기 때문에 매우 유용하다고 생각했습니다.

+0

코드를 다른 사람에게 보이지 않게해야하는 이유는 무엇입니까? :) –

0

내 생각에 떠오르는 한 가지 예가 개인 회원의 가치를 설정/가져 오기 전에 일종의 조정이나 점검이 필요할 때입니다. 따라서 private 변수에 직접 액세스하지 않고 항상 코드에서 해당 논리를 처리해야하는 대신 논리 (null 또는 다른 계산이 있는지 확인)를 사용하여 공용 setter/getter를 만듭니다. 코드 계약 및 예상되는 내용에 도움이됩니다.

다른 예는 도우미 함수입니다. 더 큰 논리의 일부를 더 작은 함수로 분해 할 수는 있지만 모든 사용자가이 도우미 함수를보고 사용할 수 있음을 의미하는 것은 아니며, 사용자가 주요 API 함수에 액세스하기를 원할뿐입니다.

다른 말로하면, 코드의 내부 구조 중 일부를 인터페이스에서 숨기려고합니다.

this Google talk과 같은 API에 대한 동영상을 참조하십시오.

+0

내가이 공공 세터/게터에서 실수를하면? 내 클래스의 사용자가 실제로 도우미 기능을 필요로하는 방식으로 확장하는 경우 어떻게해야합니까? –

4

전체적인 요점은 privateprotected을 사용하여 클래스의 내부 세부 정보가 노출되지 않도록하여 다른 클래스가 클래스에서 제공하는 공용 "인터페이스"에만 액세스 할 수있게하는 것입니다. 제대로 수행하면 가치가있을 수 있습니다.

특히 도서관에서 수업을 확장하는 경우 private이 정말 고통 스러울 수 있다는 데 동의합니다. 잠시 뒤에 Piccolo.NET 프레임 워크에서 다양한 클래스를 확장해야했으며, 내가 필요한 모든 것을 private 대신 protected으로 선언 했으므로 새로 고쳐서 코드를 복사하거나 라이브러리를 수정하지 않고도 필요한 모든 것을 확장 할 수있었습니다. . 중요한 테이크 어웨이 교훈은 라이브러리 또는 다른 "재사용 가능한"구성 요소에 대한 코드를 작성하는 경우입니다. 실제로는 두 번 이상 생각해야하며 private을 선언해야합니다.

+0

클래스 사용자가 그것을 확장 할 수 있고, 아마도 직접적인 setter/getter를 작성한다면,이 모든'protected' 물건들은'public'처럼 될 것입니다. 처음부터 모든 것을 '공개'로 선언하는 것이 어떻습니까? –

+0

캡슐화가 없기 때문에. 보호 대상은 이러한 요소가이 클래스 또는 해당 사망자 만 액세스 할 수 있다는 것입니다. 이러한 개체는 내부 세부 정보를 알아야하지만 내부 세부 정보를 사용하는 외부 코드는 알지 못합니다. –

+0

그러나 어떤 사용자라도 내 수업을 연장하고 원하는 방식으로 캡슐을 깰 수 있습니다. * protected *에는 * 효과적인 캡슐화가 없습니다. –

0

최근에 객체 시스템을 처음부터 설계하고 구현할 수 있다는 극단적 인 사치를 가졌으므로 모든 변수가 protected이되도록하는 정책을 채택했습니다. 내 목표는 사용자가 항상 변수를 구현이 아닌 사양의 일부로 취급하도록 유도하는 것이 었습니다. OTOH, 나는 또한이 제한 사항을 따르지 않는 이유가 남아 있으므로 (예 : 객체 직렬화 엔진이 규칙을 따를 수 없음) 코드가이 제한을 깨뜨릴 수 있도록 해두 고 있습니다.

내 수업에 보안을 적용 할 필요가 없습니다. 그 언어에는 다른 메커니즘이있었습니다.

0

내 의견으로는 사설 멤버를 사용하는 가장 중요한 이유는 구현을 숨기는 것이므로 미래에 자손을 변경하지 않고 변경할 수 있습니다.

0

일부 언어 - 예를 들어 스몰 토크는 가시성 수정자를 전혀 가지고 있지 않습니다.

Smalltalk의 경우 모든 인스턴스 변수는 항상 private이며 모든 메서드는 항상 public입니다. 개발자는 메서드의 "private"(변경 될 수있는 것 또는 자체적으로별로 의미가없는 도우미 메서드)를 메서드를 "개인"프로토콜에 배치함으로써 나타냅니다.

클래스의 사용자는 해당 클래스에 개인으로 표시된 메시지를 보내는 것에 대해 두 번 생각할 필요가 있지만 그 방법을 사용할 수있는 자유는 여전히 있음을 알 수 있습니다.

(참고 :. 스몰 토크에서 "속성"단순히 getter와 setter 메소드된다)

+0

이 경고 스타일을 고맙게 생각합니다. 실제로, 그것은 내가 옹호하는 것입니다. –

0

나는 개인적으로 거의 보호 된 멤버를 사용하지 않습니다. 일반적으로 composition, decorator pattern 또는 strategy pattern을 선호합니다. 보호 된 변수를 올바르게 처리하기 위해 서브 클래스 (프로그래머)를 신뢰하는 경우는 거의 없습니다. 때로는 명시 적으로 서브 클래스에 대한 인터페이스를 명시 적으로 제공하는 메소드를 보호하지만, 이러한 경우는 실제로 드뭅니다.

대부분의 경우 공용 순수 가상 (현재 C++을 말함)이있는 absract 기본 클래스가 있으며 구현 클래스는이를 구현합니다. 일부 특수 초기화 메소드 나 다른 특정 기능을 추가하는 경우도 있지만 나머지는 비공개입니다.

0

우선 '속성'은 다른 언어로 된 다른 것들을 참조 할 수 있습니다. 예를 들어 Java에서는 인스턴스 변수를 의미하지만 C#은 두 변수를 구분합니다.

getters/setters에 대해 언급 한 이후 인스턴스 변수를 사용한다고 가정합니다.

다른 사람들이 언급 한 이유는 캡슐화입니다. 캡슐화는 우리에게 무엇을 사 주나요?

일을 변경해야합니다 (그리고 그들은 보통 할) 유연성

, 우리는 훨씬 적은 제대로 캡슐화 특성에 의해 빌드를 깰 가능성이 높다.

예를 들어 우리는 같은 변경을 결정할 수 있습니다 :

우리가 다음 우리가 변경할 수있는 더 많은 코드를 줄로 시작하는 'foo는'캡슐화하지 않았다면
int getFoo() 
{ 
    return foo; 
} 

int getFoo() 
{ 
    return bar + baz; 
} 

.

속성을 캡슐화하는 또 다른 이유는 (이 한 줄 이상), 총알 교정 우리의 코드의 방법을 제공하는 것입니다

우리는 뮤 테이터에서 중단 점을 설정할 수 이것은 또한 편리
void setFoo(int val) 
{ 
    if(foo < 0) 
    throw MyException(); // or silently ignore 

    foo = val; 
} 

, 그래서 우리는 무언가가 우리의 데이터를 수정하려고 할 때마다 깨질 수 있습니다.

우리의 재산이 공개 된 경우 우리는 아무 것도 할 수 없습니다!

+0

예, 가능합니다. 모든 프로그래머는 getters/setter를 사용할 때이를 사용하는 방법을 배웠습니다. 캡슐화는 좋지만 민영화는 그렇지 않습니다. 어떻게 생각해? –

+0

그들은 그 (것)들을 감싸는 방법이 있을지도 모르지만, (당신이 그 방법을 우회 할 수있는 경우에) 캡슐에 넣지 않는다. 필자는 모든 프로그래머가 getter/setter를 제공받을 경우 (그리고 필드에 직접 액세스 할 수있는 옵션이 있음) 동의하지 않습니다. 필자가 들었던 변명은 '효율성의 이유'입니다. 이것은 말도 안되며 유지 관리 문제는 저장할 수있는 프로세서주기를 크게 앞당기 게됩니다. –