2014-12-30 2 views
3

을 깨는 나는이 클래스를 가지고있다.방지 캡슐화

하지만 어떻게 방지 할 수 있습니까?

대개 내 코드에서 내 개체의 일부 개인 데이터를 알아야하기 때문에 (비교는 하나의 예입니다), 그 때문에 getters를 사용합니다.

그래서 나는 이런 식으로 뭔가에 클래스를 재 작성 :

class Phone { 
    private: 
     string producer, color; 
     int weight, dimension; 
    public: 
     Phone(string &producer, string &color, int &weight, int &dimension): 
      producer(producer), color(color), weight(weight), dimension(dimension) {}; 
     Phone(): 
      producer(""), color(""), weight(0), dimension(0) {}; 
     virtual ~Phone() {}; 
     bool isTheProducer(string& producer) const { return this->producer == producer }; 
     bool hasWeight(int& weight) const { return this->weight == weight }; 
     bool hasDimension(int& dimension) const { return this->dimension == dimension }; 
     virtual void displayInfo(void) const; 
    }; 

이 (나는 실제 개인 가치를 얻을하지 않는 사실에 의해) 더 나은 디자인인가?

+1

실제로 세터없이 게터 뭐가 문제? – ForEveR

+0

"문제"란 무엇을 의미합니까? 나를 위해 첫 번째 코드는 거의 모든 OOP 언어에서 찾을 수있는 완전히 유효한 클래스처럼 보입니다. – BDL

+0

"*이 문제는 getter를 통해 객체의 내부 구현을 노출한다는 사실 때문에 발생합니다."* 그리고 왜 이렇게 나쁜가요? 그들이 전화를 가지고 있고 그것에 접근하는 가장 직접적인 방법 인'무게'또는'차원'을 알고 싶다면. – CoryKramer

답변

1

다른 답변과 의견에서 알 수 있듯이 대답은 다음과 같습니다.

사실, 주로 클래스가 사용되는 용도에 따라 다릅니다. 먼저 객체의 비교 질문에 주어진 예제를 고집 해 봅시다. 두 개의 전화 객체 또는 특정 데이터 멤버를 비교하려면이 질문에서 명확하게 볼 수 없으므로 여기서 두 가지 상황을 모두 토론합니다. 그런 다음

for (Phone& p in phoneList) { 
    if (p.getWeight() > x) { 
     cout << "Found"; 
    } 
} 

: 밖으로의 클래스 데이터에 데이터 멤버를 비교

우리가 X보다 큰 무게 (단지 의사) 모든 휴대폰에 대한 검색 곳의이 유스 케이스를 보자 첫 번째 클래스 예제는 전화의 본질적인 기능이 아니기 때문에 완벽하게 괜찮습니다. 따라서 전화 클래스는이를 처리 할 책임이 없습니다. 또한 결과는 작업에 절대적으로 필요한 것 이상을 노출하지 않습니다.

비교 두 개의 전화 객체이 경우

두 코드 예제는 동등하게 좋은 (또는이 경우에는 똑같이 나쁜). 두 경우 모두 사용자는 필요한 모든 구성원을 비교하기 위해 전화가 어떻게 표현되는지에 대해 많은 것을 알고 있어야합니다. 이후 버전에서 새 구성원이 클래스에 추가되면 두 전화기를 비교하는 모든 코드 세그먼트를 수정해야합니다. 이것을 극복하기 위해 정확히 비교를 수행하는 클래스에 함수를 추가 할 수 있습니다.

class Phone { 
private: 
    string producer, color; 
    int weight, dimension; 
public: 
    bool IsEqualTo(const Phone& other) 
    { 
     return (producer == other.producer && color == other.color &&....); 
    } 

비 비교급 유스 케이스

그러나 이제 더 진보 된 예에 가자. 다음 작업을 가정 해 봅시다. 사용자가 핀을 전화기에 입력하고 올바른 핀일 경우 전화기를 잠금 해제해야합니다.

class Phone 
{ 
private: 
    int pin; 
    bool unlocked; 

public: 
    int getPin() { return pin; } 
    void unlock() { unlocked = true; } 
}; 

을 우리는 완전히 다른 상황이이 경우에 해당 호출

if (phone.getPin() == enteredPin) 
    phone.unlock(); 

:의 매우 순진한 접근 방식을 가정 해 봅시다. 여기서 우리는 "tell, don't ask" 규칙을 고려할 필요가 있습니다. 기본적으로 객체의 상태를 먼저 쿼리하고 결정을 내린 다음 객체에 무엇을 할 것인지를 알려주는 것은 나쁜 설계라고합니다. 그 대신에 우리는 우리가 원하는 것을 객체에만 알려주고, 그것이 우리를 위해 작업을하도록해야합니다. 핀이 정확할 때만 전화를 잠금 해제하는 것은 전화 클래스를 사용하는 사용자가 아니라 전화의 책임이므로이 경우에는 분명합니다. 그러나 더 복잡한 시나리오에서는 많은 프로그래머가 여기에 설명 된 것을 정확히 수행 할 것입니다.

위로 문제에

: 여기 좋은 솔루션은 코드

phone.CheckPin(enteredPin); 

희망이 도움이, 감사는 "말씀을 가리키는 위해 @KonradRudolph하기로

class Phone 
    { 
    private: 
     int pin; 
     bool unlocked; 

    public: 
     void CheckPin(int enteredPin) { 
      if (pin == enteredPin) 
       unlocked = true; 
     } 
    }; 

예를

이 될 것입니다, do not는 규칙을 묻는다 ". 내가 그것을 주석 : 당 대답을 개선하는 데 도움 주시기 바랍니다

0

캡슐화는 클래스 내의 메소드를 통해서만 속성을 제어 할 수 있습니다. 두 예제 모두 캡슐화됩니다.

+1

"두 예제 모두 캡슐화되어 있습니다"- 예,하지만 getter가 없으면 더 * 더 * 캡슐에 넣었다. 캡슐화는 이진 값이 아닌 눈금에 있습니다. –

1

첫 번째 것은 getter로 캡슐화됩니다. 문자열을 반환하는 color() 메서드를 생각해보십시오. Phone의 구현을 변경하여 문자열이 아닌 열거 형으로 색을 저장하는 경우에도 먼저 일종의 변환을 수행하면 메서드에서 여전히 문자열을 반환 할 수 있습니다. 중요한 부분은 color()의 구현과 변경할 필요가있는 클래스 사용자가없는 기본 저장소를 변경할 수 있다는 것입니다.

색상을 공개적으로 액세스 할 수있는 문자열로 저장하는 클래스와 비교하십시오. 나중에 데이터 멤버를 열거 형으로 변경하면 색상을 사용하는 모든 위치를 수정해야합니다. 이것은 캡슐화의 특성이 적고 구현과 인터페이스를 분리하는 속성입니다.

+0

다른 대답에서 내 설명 반복 : 클래스는 다소 "캡슐화"될 수 있지만 게터가 없으면 더 캡슐화됩니다. 캡슐화는 이진 값이 아닌 눈금에 있습니다. "중요한 부분은 ..."- 아니. 캡슐화의 중요한 부분입니다. –

+0

나는 "the"대 "one"이라는 까다로운 표현을 인정할 것이다. 분명히 포함되어있는 데이터에 대한 액세스를 제공하지 않는 극단적 인 연속체에 존재합니다. 그러나 문제는 어떤 디자인이 더 캡슐화되었는지에 관한 것이 아니라 어느 것이 더 좋았는지 물었고, 이는 사용법에 관한 것입니다. 'phone.isTheColor ("blue")'는 괜찮지 만, 클라이언트가 실제 색상을 배우는 것이 목표이지만 getter는 괜찮 으면 디자인에서 실패합니다. 나는'std :: vector'가'.size()'보다는'.isTheSize (3)'멤버와 비슷할 것이라고 생각하고 있으며 캡슐화되었지만 끔찍하다는 것에 동의 할 수 있기를 바랍니다. – JHumphrey