게터와 세터 안에 무엇이 허용되어야합니까?


45

나는 getter와 setter 메소드와 캡슐화에 관한 흥미로운 인터넷 논쟁에 들어갔다. 누군가는 "순결한"상태를 유지하고 캡슐화를 보장하기 위해 할당 (세터) 또는 가변 액세스 (게터) 만해야한다고 말했다.

  • 이것이 처음에는 게터와 세터를 갖는 목적을 완전히 잃고 검증과 다른 논리 (이상한 부작용없이)가 허용되어야한다는 것이 맞습니까?
  • 언제 검증이 이루어져야합니까?
    • 값을 설정할 때 setter 내부에서 (객체가 잘못된 상태로 들어 가지 않도록 보호하기 위해-내 의견)
    • 값을 설정하기 전에 설정 기 외부
    • 객체 내부에서 값이 사용될 때마다
  • 세터가 값을 변경할 수 있습니까 (유효한 값을 표준 내부 표현으로 변환 할 수 있습니까)?

18
게터와 세터에 대한 가장 좋은 점 은 그것들을 갖지 않는 능력입니다 . 즉, 세터를 떠나고 읽기 전용 속성, 게터를 떠나고 현재 값이 누구의 사업도 아닌 구성 옵션이 있습니다.
Michael Borgwardt

7
@MichaelBorgwardt 깨끗한“말하지 말고”인터페이스를 갖도록 두십시오. 속성 = 잠재적 코드 냄새.
Konrad Rudolph


2
이벤트 를 발생시키기 위해 세터를 사용할 수도 있습니다 .
John Isaiah Carmona

@KonradRudolph 저는 "잠재적"이라는 단어를 강조하고 싶지만 귀하의 진술에 동의합니다.
Phil

답변:


37

대학에서 C ++을 배울 때 강사와 비슷한 주장을했던 것을 기억합니다. 변수를 공개 할 수있을 때 게터와 세터를 사용하는 요점을 알 수 없었습니다. 나는 수년간의 경험을 통해 더 잘 이해하고 있으며 단순히 캡슐화를 유지하는 것보다 더 나은 이유를 배웠습니다.

게터와 세터를 정의함으로써 구현을 변경하고 싶을 때 의존 코드를 깰 가능성이 없도록 일관된 인터페이스를 제공하게됩니다. 이는 수업이 API를 통해 노출되고 다른 앱이나 타사에서 사용될 때 특히 중요합니다. 게터 나 세터에 들어가는 것은 어떻습니까?

게터는 일반적으로 행동을 예측할 수 있기 때문에 값에 액세스하기위한 단순한 바보 같은 패스 스루로 구현하는 것이 좋습니다. 필자는 일반적으로 게터가 계산이나 조건부 코드로 조작 된 값에 액세스하는 데 사용 된 사례를 보았 기 때문에 일반적으로 말합니다. 일반적으로 디자인 타임에 사용할 시각적 구성 요소를 만드는 것은 좋지 않지만 런타임에는 편리해 보입니다. 그러나 메소드를 사용할 때 코드를 읽을 때 "getter"의 기능이 더 명확 해 지도록 메소드의 이름을 더 적절하게 지정할 수 있다는 점을 제외하면이 메소드와 간단한 메소드를 사용하는 것 사이에는 실질적인 차이가 없습니다.

다음을 비교하십시오.

int aValue = MyClass.Value;

int aValue = MyClass.CalculateValue();

두 번째 옵션을 사용하면 값이 계산되고 있음을 알 수 있지만 첫 번째 예에서는 값 자체에 대해 전혀 몰라도 값을 반환하고 있음을 나타냅니다.

다음이 더 명확 할 것이라고 주장 할 수 있습니다.

int aValue = MyClass.CalculatedValue;

그러나 문제는 값이 이미 다른 곳에서 조작되었다고 가정한다는 것입니다. 따라서 getter의 경우 값을 반환 할 때 다른 일이 진행되고 있다고 가정 할 수 있지만 속성의 맥락에서 그러한 것을 명확하게하는 것은 어렵고 속성 이름에는 동사가 포함되어서는 안됩니다 그렇지 않으면 액세스 할 때 사용 된 이름을 괄호로 장식해야하는지 한 눈에 알기가 어렵습니다.

세터는 약간 다른 경우입니다. 값을 설정하면 속성의 정의 된 경계를 위반하는 경우 예외가 발생하여 속성에 제출되는 데이터의 유효성을 검사하기 위해 세터가 추가 처리를 제공하는 것이 전적으로 적절합니다. 그러나 일부 개발자가 세터에 처리를 추가 할 때의 문제점은 세터가 어떤 방식으로 데이터를 계산하거나 조작하는 것과 같이 세터가 조금 더 노력을 기울여야한다는 유혹이 항상 있다는 것입니다. 여기에서 어떤 경우에는 예측할 수 없거나 바람직하지 않은 부작용을 얻을 수 있습니다.

세터의 경우 항상 간단한 경험 법칙을 적용합니다. 예를 들어, 일반적으로 경계 테스트와 반올림을 허용하여 적절한 경우 예외를 발생 시키거나 불필요한 예외를 피할 수있는 예외를 피할 수 있습니다. 부동 소수점 속성은 예외가 발생하지 않도록 과도한 소수 자릿수를 반올림하고 소수의 소수 자릿수로 범위 값을 입력 할 수있는 좋은 예입니다.

setter 입력에 일종의 조작을 적용하는 경우 getter와 같은 문제가 있으므로 다른 사람이 단순히 setter의 이름을 지정하여 setter가 수행하는 작업을 알기가 어렵습니다. 예를 들면 다음과 같습니다.

MyClass.Value = 12345;

이것이 세터에게 주어질 때 그 가치에 어떤 일이 일어날 지에 대해 말해 주는가?

어때요 :

MyClass.RoundValueToNearestThousand(12345);

두 번째 예는 데이터에 어떤 일이 일어날 지 정확하게 알려주는 반면 첫 번째 예는 가치가 임의로 수정 될 것인지 여부를 알려주지 않습니다. 코드를 읽을 때 두 번째 예는 목적과 기능이 훨씬 명확합니다.

이것이 처음에는 게터와 세터를 갖는 목적을 완전히 잃고 검증과 다른 논리 (이상한 부작용없이)가 허용되어야한다는 것이 맞습니까?

getter와 setter를 갖는 것은 "순도"를위한 캡슐화에 관한 것이 아니라 클래스의 인터페이스를 변경하지 않고도 코드를 쉽게 리팩터링하여 클래스의 호출 코드와의 호환성을 손상시킬 수 있도록 캡슐화에 관한 것입니다. 유효성 검사는 세터에서 전적으로 적합하지만 호출 코드가 특정 방식으로 발생하는 유효성 검사에 의존하는 경우 유효성 검사 변경으로 인해 호출 코드와의 호환성이 손상 될 위험이 적습니다. 이것은 일반적으로 드물고 상대적으로 위험이 낮은 상황이지만 완전성을 위해 주목해야합니다.

언제 검증이 이루어져야합니까?

실제로 값을 설정하기 전에 setter 컨텍스트 내에서 유효성 검증이 수행되어야합니다. 이를 통해 예외가 발생하면 객체의 상태가 변경되지 않고 데이터가 무효화 될 수 있습니다. 일반적으로 setter 코드를 비교적 깔끔하게 유지하기 위해 setter 내에서 가장 먼저 호출되는 별도의 메서드에 유효성 검사를 위임하는 것이 좋습니다.

세터가 값을 변경할 수 있습니까 (유효한 값을 표준 내부 표현으로 변환 할 수 있습니까)?

아주 드문 경우 일 수 있습니다. 일반적으로 그렇지 않은 것이 좋습니다. 이것은 다른 방법에 가장 적합한 종류입니다.


다시 : 값을 변경, 세터가 잘못된 값을 전달하는 경우 -1 또는 일부 NULL 플래그 토큰으로 설정하는 것이 합리적 일 수 있습니다
Martin Beckett

1
이것에는 몇 가지 문제가 있습니다. 임의로 값을 설정하면 의도적이고 불명확 한 부작용이 발생합니다. 또한 호출 코드가 잘못된 데이터를보다 잘 처리하는 데 사용할 수있는 피드백을받을 수 없습니다. 이는 UI 수준의 값에서 특히 중요합니다. 공평하게, 방금 생각한 한 가지 예외는 날짜를 표준 날짜 / 시간 형식으로 저장하면서 여러 날짜 형식을 입력으로 허용하는 경우 일 수 있습니다. 입력 데이터가 합법적이라면이 특정 "부작용"이 유효성 검사시 데이터의 정규화라고 단언 할 수있다.
S.Robins

예, 세터의 정당성 중 하나는 값을 설정할 수 있으면 true / false를 반환해야한다는 것입니다.
Martin Beckett

1
"부동 소수점 속성은 예외 발생을 피하기 위해 과도한 소수 자릿수를 반올림 할 수있는 좋은 예입니다."소수점 이하 자릿수가 너무 많으면 예외가 발생하는 상황은 무엇입니까?
Mark Byers

2
유효성 검사의 형태로 값을 표준 표현으로 변경하는 것을 봅니다. 결 측값 (예 : 시간 소인에 시간 만 포함 된 경우 현재 날짜)을 기본값으로 설정하거나 내부 일관성이 양호하도록 값을 조정 (.93275-> 93.28 %)하지만 이러한 조작은 API 문서에서 명시 적으로 호출해야합니다. 특히 API 내에서 일반적이지 않은 관용구 인 경우.
TMN

20

getter / setter가 단순히 값을 미러링하는 경우 값을 가지거나 값을 비공개로 만들 때 아무런 의미가 없습니다. 정당한 이유가있는 경우 일부 멤버 변수를 공개하는 데 아무런 문제가 없습니다. 3D 포인트 클래스를 작성하는 경우 .x, .y, .z public을 사용하는 것이 완벽합니다.

랄프 왈도 에머슨 (Ralph Waldo Emerson)은 "어리석은 일관성은 작은 정치인들과 철학자들, 그리고 자바 디자이너들이 사랑하는 작은 정신의 옹호 블린입니다."

게터 / 세터는 다른 내부 변수를 업데이트하고 캐시 된 값을 다시 계산하고 클래스를 유효하지 않은 입력으로부터 보호해야하는 부작용이있는 경우에 유용합니다.

내부 구조를 숨기는 일반적인 이유는 일반적으로 가장 유용하지 않습니다. 예. 이 점을 3 개의 부동 소수점으로 저장하면 원격 데이터베이스에 문자열로 저장하기로 결정할 수 있으므로 호출자의 코드에 다른 영향을 미치지 않고 getter / setter를 사용하여 숨길 수 있습니다.


1
와우, 자바 디자이너들은 신성합니까? </ jk>

@delnan - 분명하지 - 또는 그들이 ;-) 더 나은 운율 것
마틴 베켓에게

x, y, z가 모두 Float.NAN 인 3D 점을 작성하는 것이 유효합니까?
앤드류 T 피넬

4
나는 "일반적인 정당화"(내부 구조 숨기기)가 게터와 세터의 가장 유용한 속성이라는 점에 동의하지 않습니다. C #에서, 그것은 재산 그 기본 구조 변경 될 수있는 인터페이스 만들기 위해 확실히 유용하다 - 당신은 단지 열거 형의 속성을 사용할 수 원하는 경우, 예를 들어,이 말을 훨씬 낫다 IEnumerable<T>같은 뭔가를 강요보다 List<T>. 내가 말하는 데이터베이스 액세스의 예는 단일 책임을 위반하는 것입니다-모델 표현을 유지하는 방법을 혼합합니다.
Brandon Linton

@AndrewFinnell는 - 그것은 등 / 삭제 / 불가능 유효하지로 포인트를 신고하는 좋은 방법이 될 수 있습니다
마틴 베켓

8

Meyer의 통일 된 액세스 원칙 : "모듈이 제공하는 모든 서비스는 통일 된 표기법을 통해 사용 가능해야하며, 스토리지 또는 계산을 통해 구현되는지 여부를 배신하지 않아야합니다." 게터 / 세터, 즉 속성이라는 주요 원인입니다.

클래스의 한 필드를 캐시하거나 느리게 계산하기로 결정한 경우 구체적인 데이터가 아닌 속성 접근자가 노출 된 경우 언제든지 변경할 수 있습니다.

가치 객체, 간단한 구조는 이러한 추상화가 필요하지 않지만 본격적인 수업은 필자의 의견으로는 필요합니다.


2

에펠 언어를 통해 도입 된 클래스 디자인을위한 일반적인 전략은 Command-Query Separation 입니다. 아이디어는 방법을해야한다는 것입니다 중 하나를 당신에게 객체에 대해 뭔가를 말 하거나 뭔가를 객체에게 있지만, 두 가지를 모두 수행 할 수 없습니다.

이것은 내부 표현이 아닌 클래스의 공용 인터페이스에만 관련됩니다. 데이터베이스의 행으로 백업되는 데이터 모델 오브젝트를 고려하십시오. 데이터를로드하지 않고 객체를 만든 다음 getter를 처음 호출하면 실제로 작업을 수행합니다 SELECT. 괜찮습니다. 객체가 표현되는 방식에 대한 내부 세부 정보를 변경하고 있지만 해당 객체의 클라이언트에 표시되는 방식을 변경하지는 않습니다. 게터에게 여러 번 전화를 걸 수 있지만 결과를 반환하기 위해 다른 작업을 수행하더라도 동일한 결과를 얻을 수 있어야합니다.

마찬가지로 setter는 계약 상태에서 객체의 상태를 변경하는 것처럼 보입니다. UPDATE데이터베이스에 데이터를 쓰거나 일부 내부 객체에 매개 변수를 전달하여 복잡한 방식으로이를 수행 할 수 있습니다 . 괜찮지 만 상태 설정과 관련이없는 것을하는 것은 놀라운 일입니다.

Meyer (Eiffel 제작자)도 검증에 대해 할 말이있었습니다. 기본적으로 개체가 대기 상태 일 때마다 유효한 상태 여야합니다. 따라서 생성자가 완료된 직후, 모든 외부 메서드 호출 전후에 (필수 동안 반드시 그런 것은 아님) 객체의 상태는 일관되어야합니다.

해당 언어에서 프로 시저를 호출하고 노출 된 속성을 읽는 구문은 모두 동일하게 나타납니다. 다시 말해, 호출자는 메소드를 사용하고 있는지 또는 인스턴스 변수와 직접 작업 하는지를 알 수 없습니다. 질문이 발생하는 경우이 구현 세부 사항을 숨기지 않는 언어로만되어 있습니다. 발신자가 알 수없는 경우 클라이언트 코드로의 변경을 누설하지 않고 공개 ivar과 접근자를 전환 할 수 있습니다.


1

또 다른 허용 가능한 작업은 복제입니다. 어떤 경우에는 누군가가 수업을 마치고 난 후에 확인해야합니다. 어떤 것의 목록이라면, 그는 당신의 클래스 안에서 그것을 바꿀 수 없습니다 (그 목록의 객체를 바꾸지 마십시오). 따라서 setter에서 매개 변수의 딥 카피를 만들고 getter에서 딥 카피를 반환합니다. (불변의 유형을 매개 변수로 사용하는 것이 또 다른 옵션이지만, 위의 방법은 불가능하다고 가정합니다.) 필요하지 않은 경우 접근 자에서 복제하지 마십시오. 속성 / 게터 및 세터에 대해 일정한 비용으로 생각하기는 쉽지만 (적절하지는 않지만) api 사용자를 기다리는 성능 지뢰입니다.


1

속성 접근 자와 데이터를 저장하는 ivar간에 항상 1-1 매핑이있는 것은 아닙니다.

예를 들어 뷰 클래스는 뷰 center의 중심을 저장하는 ivar이 없더라도 속성을 제공 할 수 있습니다. 설정 center같은 다른 인스턴스 변수에 원인 변경 origin하거나 transform또는 무엇이든하지만, 클래스의 클라이언트가 모르거나 상관 없어 어떻게 center 제대로 작동하는지 제공 저장됩니다. 그러나 일어나지 않아야 할 것은 설정 center이 새로운 가치를 저장하는 데 필요한 것 이상으로 일이 발생한다는 것입니다.


0

세터와 게터의 가장 큰 장점은 API를 변경하지 않고도 API 규칙을 쉽게 변경할 수 있다는 것입니다. 버그를 발견하면 라이브러리에서 버그를 수정하고 모든 소비자가 코드베이스를 업데이트하지는 않을 가능성이 훨씬 높습니다.


-4

나는 세터와 게터가 악하다고 믿고 경향이있다. 프레임 워크 / 컨테이너가 관리하는 클래스에서만 사용해야한다. 적절한 클래스 디자인은 게터와 세터를 생성해서는 안됩니다.

편집 : 이 주제에 대해 잘 작성된 기사 .

Edit2 : 공개 필드는 OOP 방식에서 넌센스입니다. 게터와 세터가 악하다고 말함으로써 그들이 공공 장소로 대체되어야한다는 것을 의미하지는 않습니다.


1
필자는 기사의 요점을 놓치고 있다고 생각합니다. 게터 / 세터를 조금만 사용하고 필요하지 않으면 클래스 데이터가 노출되는 것을 피하는 것이 좋습니다. 이 IMHO는 현명한 설계 원칙으로 개발자가 의도적으로 적용해야합니다. 클래스에서 속성을 만드는 관점 에서 변수를 간단히 노출 할 는 있지만 변수가 설정 될 때 유효성 검사를 제공하거나 "가져올"경우 대체 소스에서 값을 가져 와서 캡슐화를 위반하고 잠재적으로 인터페이스 디자인을 유지하기 어려운 상황에 빠지게합니다.
S.Robins

@ S.Robins 내 의견으로는 공개 게터와 세터가 잘못되었습니다. 퍼블릭 필드가 더 잘못되었습니다 (비교할 수있는 경우).
m3th0dman

@methodman 예, 공공 장소가 잘못되었다는 데 동의하지만 공공 재산이 유용 할 수 있습니다. 이 속성은 당시의 특정 요구 사항에 따라 데이터 설정 또는 반환과 관련된 유효성 검사 또는 이벤트를위한 장소를 제공하는 데 사용할 수 있습니다. 게터와 세터 자체는 잘못된 것이 아닙니다. 반면에 언제 어떻게 사용 또는 남용되는지는 상황에 따라 설계 및 유지 관리 측면에서 열악한 것으로 보일 수 있습니다. :)
S.Robins

@ S.Robins OOP 및 모델링의 기본에 대해 생각하십시오. 객체는 실제 엔티티를 복사해야합니다. getter / setter와 같은 이러한 유형의 작업 / 속성을 갖는 실제 엔터티가 있습니까?
m3th0dman

여기에 너무 많은 의견을 피하기 위해, 나는에이 대화를 할게요 이 채팅 거기에 당신의 코멘트를 해결합니다.
S.Robins
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.