메서드 이름을 바꾸면 캡슐화를 유지할 수 있습니까?


9

getter / setter가 정당화되는 시점에 대해이 페이지를 읽고 OP는 다음 코드 샘플을 제공했습니다.

class Fridge
{
     int cheese;

     void set_cheese(int _cheese) { cheese = _cheese; }
     int get_cheese() { return cheese; }
 }

void go_shopping(Fridge fridge)
{
     fridge.set_cheese(fridge.get_cheese() + 5);        
}

허용 응답 상태 :

그런데, 귀하의 예제에서, 나는 클래스 줄 것 과 대신의 방법을, 하고 . 그러면 여전히 캡슐화가 발생합니다.FridgeputCheese()takeCheese()get_cheese()set_cheese()

값을 get / set에서 putCheese()/ 로 바꾸면 캡슐화가 어떻게 보존 takeCheese()됩니까? 분명히 값을 얻거나 설정하는 것이므로 get / set으로 그대로 두지 않겠습니까?

같은 대답에서 다음과 같이 말합니다.

게터와 세터가 있다고해서 캡슐화가 깨지는 것은 아닙니다. 캡슐화를 깨뜨리는 것은 모든 데이터 멤버 (Java lingo의 모든 필드)에 대해 아무런 생각없이 자동으로 getter 및 setter를 추가하는 것입니다.

이 경우에는 하나의 변수 만 있으며 cheese치즈를 냉장고로 가져 와서 반환 할 수 있으므로이 경우 get / set 쌍이 정당화됩니다.


7
putCheese냉장고에 치즈를 추가하고 takeCheese제거 할 것입니다. 객체 필드 게터 및 세터 ((저수준) 컴퓨터 프로그래밍 추상화)가 아니라 (상위 레벨) 도메인 지향 추상화입니다.
Erik Eidt

답변:


17

나는 당신이 요점을 놓치고 있다고 생각합니다. 그것은 setter와 getter의 이름을 바꾸어야하지만 냉장고에서 항목을 추가하고 제거하는 메소드를 가져야한다고 말하는 것입니다. 즉

public class Fridge
{
    private int numberOfCheeseSlices;

    public void AddCheeseSlices(int n)
    {
         if(n < 0) { 
             throw new Exception("you cant add negative cheese!");
         }
         if(numberOfCheeseSlices + n > this.capacityOfFridge) { 
             throw new Exception("TOO MUCH CHEESE!!");
         }
         ..etc
         this.numberOfCheeseSlices += n;
    }
}

이제 개인 변수가 캡슐화되었습니다. 나는 단지 내가 원하는 것으로 설정할 수 없으며, 방법을 사용하여 냉장고에서 치즈 조각을 추가하고 제거 할 수 있으며, 결과적으로 원하는 치즈 비즈니스 논리 규칙이 적용되도록합니다.


2
그렇습니다.하지만 setCheese()세터에 동일한 논리가있는 것처럼 그대로 둘 수 있습니다 . 어쨌든, 당신은 메소드의 이름을 바꾸어 세터를 사용하고 있다는 사실을 숨기려고하지만 분명히 게터를 설정하거나 설정합니다.
QueenSvetlana

21
@QueenSvetlana 그것은 세터가 아닙니다. 작업입니다. 냉장고에 "다른 치즈는 여기있다"고 말하고 캡슐화 한 내부 치즈 수에 추가합니다. 세터는 "이제 치즈가 5 개 있습니다"라고 말합니다. 이것들은 다른 이름뿐만 아니라 기능적으로 다른 작업입니다.
Ant P

1
setCheese라고 부를 수는 있지만 치즈의 가치를 설정하지 않기 때문에 혼란 스러울 것입니다.
Ewan

6
여기에 정수 오버플로 버그가 있습니다. 치즈가 이미 0 개를 초과 AddCheese(Integer.MAX_VALUE)하면 실패하지만 실패하지는 않습니다.
user253751

3
그것은 ..etc 섹션에서 완전히 다루어 질 것입니다
Ewan

5

Getter와 Setter 는 정의에 따라 매번 캡슐화를 중단 합니다. 무엇 있습니다 주장 할 수 때로는 우리가 그렇게 할 필요가있다. 그 길을 벗어난 내 대답은 다음과 같습니다.

get / set에서 putCheese () / takeCheese ()로 이름을 바꾸어 캡슐화를 유지하는 방법 분명히 값을 얻거나 설정하는 것이므로 get / set으로 그대로 두지 않겠습니까?

차이점은 시맨틱, 즉 작성하는 내용의 의미에 있습니다. 캡슐화는 보호뿐만 아니라 내부 상태를 숨기는 것 입니다. 내부 상태는 외부에서도 알 수 없으며, 대신 객체는 해당 상태를 조작 / 사용하기 위해 비즈니스 관련 방법 ( "동작"이라고도 함)을 제공해야합니다.

그래서 getset기술 용어이고하면서 "냉장고"도메인과는 아무 상관이없는 것 put하고 take실제로 어떤 의미를 만들 수 있습니다.

그러나 , 여부 put또는 것은 take만들 실제 의미는 여전히 요구 사항에 따라 달라 객관적으로 판단 할 수 없습니다. 다음 사항 참조 :

이 경우, 우리는 하나의 변수 치즈를 가지고 있으며 치즈를 냉장고로 가져 와서 반환 할 수 있으므로이 경우 get / set 쌍이 정당화됩니다.

더 많은 상황이 없다면 객관적으로 결정할 수 없습니다. 귀하의 예에는 go_shopping()다른 곳 의 방법이 포함되어 있습니다 . 즉, 어떤 경우 Fridge가보다위한 것입니다 하지 필요 get또는 set무엇을 필요로하는 것은, Fridge.go_shopping(). 이 방법으로 요구 사항에서 파생 된 방법을 사용할 수 있습니다. 필요한 "데이터"는 모두 로컬이며 얇게 가려진 데이터 구조 대신 실제 동작 이 있습니다 .

일반적인 재사용 가능한 빌드를 작성하지 않음을 기억하십시오 Fridge. 당신은 Fridge당신의 요구 사항에 대해서만 구축하고 있습니다. 필요한 것보다 더 많이 만드는 데 드는 노력은 실제로 낭비입니다.


10
Getters and setters break encapsulation every single time-내 취향으로는 말이 너무 강하다. 메소드 (게터 및 세터 포함)는 콘서트에서 게이트가하는 것과 동일한 목적을 가지고 있습니다.
Robert Harvey

8
"게터와 세터는 정의에 따라 매번 캡슐화를 중단합니다" -어떤 정의로? getter와 setter는 다른 공용 멤버와 마찬가지로 공용 인터페이스의 일부이기 때문에 이것도 문제가 있습니다. 그것들 은 의도적으로 (즉, 프로그래머 (또는 팀)의 결정에 의해) 내부적 으로 간주되는 구현 세부 사항을 노출하는 경우에만 캡슐화를 중단 합니다. 게터와 세터가 커플 링 제어를 나중에 생각할 때 우연히 추가되는 경우는 전적으로 또 다른 문제입니다.
Filip Milovanović '

2
@ FilipMilovanović 페어 포인트. 대답에서 언급했듯이 "캡슐화"는 객체 내부 를 숨기는 데 사용됩니다 (== 객체 상태 == 인스턴스 변수). 게터와 세터 객체 내부를 게시 합니다. 따라서 이러한 정의에 의해 그들은 영구적으로 충돌합니다. 이제, 때로는 여부를 우리가 필요로 캡슐화 별도로 처리해야 다른 문제입니다 휴식. 분명히, setters / getters가 항상 캡슐화를 중단한다고 말하면 그것이 도움이된다면 그것이 항상 "틀린"것이 아닙니다.
Robert Bräutigam

5
게터와 세터는 "문자 그대로 캡슐화를 항상 깨뜨리지"않습니다. 게터와 세터는 종종 직접 아래의 멤버를 참조하지 않거나 일종의 작업을 수행하거나 독점적으로 정의 된 경우에만 게터 만 있거나 세터 만 가질 수 있습니다. 게터와 세터가 멤버 액세스 이상을 수행하지 않고 둘 다 동일한 필드에 대해 정의되면 캡슐화가 중단됩니다. 내부 변경으로 ABI / API를 중단하고 클라이언트 재 컴파일을 피하지 않으려는 라이브러리 관리자에게는 이것이 필요할 수도 있습니다.
whn

4
좋아, 게터와 세터는 캡슐화를 99 % 만 깨뜨립니다. 행복? 그리고 캡슐화 된 객체 의 유형 을 노출시킴으로써 캡슐화를 확실히 깨뜨립니다. 일단 당신이 public int getFoo()그것을 가지고 실제로는 다른 유형으로 변경하는 것은 거의 불가능합니다.
user949300

3

이 대부분은 캡슐화에 대한 근본적인 오해와 그 적용 방법을 보여줍니다.

캡슐화를 중단 한 초기 응답은 잘못되었습니다. 응용 프로그램은 증가 / 감소 또는 추가 / 제거 대신 냉장고의 치즈 값을 간단히 설정해야 할 수도 있습니다. 또한, 무엇을 호출하든, 속성을 액세스 및 / 또는 변경해야 할 필요가있는 경우 시맨틱이 아니므로 속성을 제공하여 캡슐화를 중단하지 않습니다. 마지막으로 캡슐화는 실제로 "숨김"에 관한 것이 아니라 클래스 외부에서 공개하거나 조작 할 필요가없는 상태 및 값에 대한 액세스를 제어하는 ​​한편 내부적으로 사용할 수있는 작업을 수행하는 사람에게 부여하는 것입니다.

getter 또는 setter는 값을 얻거나 설정해야 할 정당한 요구가있을 때 캡슐화를 중단하지 않습니다. 이것이 방법이 공개 될 수있는 이유입니다.

캡슐화는 데이터와 해당 데이터를 직접 수정하는 메서드를 하나의 논리적 위치 인 클래스에 보관하는 것입니다.

이 특별한 경우에, 응용에서 치즈의 가치를 변화시킬 필요가 분명히있다. 메소드가 클래스에 캡슐화되어있는 한 객체 지향 스타일을 따르는 한 get / set 또는 add / remove를 통해이 작업을 수행하는 방법에 관계없이.

설명을 위해 메소드 이름이나 논리적 실행에 관계없이 액세스를 제공하여 캡슐화가 어떻게 깨지는 지 예를 들어 보겠습니다.

냉장고에 "평생"이 있다고 가정 해 봅시다. 냉장고가 더 이상 작동하지 않을 때까지 몇 번의 진드기 만하면됩니다 (논쟁을 위해 냉장고를 수리 할 수 ​​없음). 논리적으로 사용자 (또는 나머지 응용 프로그램)가이 값을 변경할 수있는 방법은 없습니다. 비공개 여야합니다. "isWorking"으로 알려진 다른 공용 속성을 통해서만 볼 수 있습니다. 수명이 만료되면 내부적으로 냉장고 세트는 작동 중입니다.

수명 카운트 다운 및 isWorking 스위치 뒤집기의 실행은 모두 냉장고 내부에 있으며 외부에서는 프로세스에 영향을 줄 수 없습니다. isWorking 만 표시되므로 getter가 캡슐화를 중단하지 않습니다. 그러나 수명 프로세스의 요소에 접근자를 추가하면 캡슐화가 중단됩니다.

대부분의 것들과 마찬가지로 캡슐화의 정의는 문자적인 것이 아니라 상대적입니다. 클래스 외부에서 X를 볼 수 있어야합니까? Y를 바꿀 수 있을까요? 이 클래스의 객체에 적용되거나 모든 기능이 여러 클래스에 분산되어 있습니까?


실용적으로 살펴 보겠습니다. 코드가 그렇게 의도 된 경우 또는 "합법적 인"이유가있는 경우 캡슐화가 중단되지 않습니다 . 이는 기본적으로 캡슐화가 깨 졌다고 결코 말할 수 없다는 것을 의미합니다. 개발자가 "그대로"의도 한 것만 말하거나 "합법적 인"이유가 있었기 때문입니다. 그렇다면이 정의는 기본적으로 쓸모가 없습니까?
Robert Bräutigam 19 :

아니요, 액세스를 제공하는 것만으로 캡슐화가 중단되지는 않습니다. 또한 프로그래머가 말하는 것과는 관련이 없지만 응용 프로그램의 요구는 무엇입니까. 응용 프로그램은 개체를 조작 할 수있는 액세스 권한이 있어야하며 캡슐화는 액세스 제어에 관한 것입니다. 응용 프로그램은 객체의 속성을 "설정"해야하지만 해당 "세트"작업을 수행하는 데 필요한 논리 및 계산은 객체 클래스에 캡슐화되어야합니다.
user343330

"이것은 우리가 근본적으로 다른 곳이라고 생각합니다."응용 프로그램이 객체의 속성을 "설정"해야 할 수도 있습니다 ... " 나는 그렇게 생각하지 않습니다. 속성을 설정하거나 얻는 것과 관련된 디자인을 선택하는 것은 개발자에게 달려 있습니다. 선택입니다! 코드를 작성하는 방법에는 여러 가지가 있지만 인스턴스 변수 값을 가져 오거나 설정하는 것은 아닙니다.
Robert Bräutigam 19 :

아마도 ... 디자인은 프로그래머가 선택한 것이 비즈니스 환경을 기반으로하는지 여부에 관계없이 요구를 충족시키는 것입니다. 두 경우 모두, 응용 프로그램이 객체의 일부인 값을 조작해야하는 근본적인 필요성이 있다면 어떤 방식 으로든 해당 기능에 액세스 할 수 있어야합니다. 작업을위한 진입 점을 제공한다고해서 캡슐화가 깨지는 것은 아닙니다. 판매 앱을 가져 가십시오. 어떤 시점에서 당신의 거래는 거래의 객체에 캡슐화 유지,하지만 응용 프로그램이 상태 transaction.CalcTax 할 수 있어야하고, 세금을 계산한다
user343330

세터는 단순성으로 인해 나쁜 예입니다. 객체 속성이 클래스 외부에서 작업을 수행 한 다음 object.attribute = x라고하는 것과 비교하여 훨씬 더 많은 작업을 수행하는 함수의 관점에서 생각하십시오. 첫 번째는 적절한 액세스를 제공하는 동안 캡슐화가 잘되고 두 번째는 그렇지 않습니다. getter에 관해서는 응용 프로그램이 객체 클래스에 포함될 수없는 다른 것을 수행하기 위해 객체의 일부만 알아야합니까? 그렇다면 노출이 캡슐화를 손상시키지 않습니다. 그렇지 않다면, 객체 클래스에 캡슐화하십시오
user343330

1

메서드 이름 만 바꾸는 것이 아닙니다. 두 방법은 다르게 작동합니다.

(당신의 마음에 이것을 그림)

get_cheese 및 set_cheese는 치즈를 노출합니다. putCheese () 및 takeCheese ()는 치즈를 숨기고 치즈 관리를 담당하며 사용자가 치즈를 처리 할 수있는 방법을 제공합니다. 관찰자는 치즈를 볼 수없고, 치즈를 조작하는 두 가지 방법 만 볼 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.