etc./StackOverFlow

getter 및 setter/접근자를 사용하는 이유는 무엇입니까?

청렴결백한 만능 재주꾼 2022. 1. 6. 11:11
반응형

질문자 :Dean J


단순히 해당 변수에 대해 공개 필드를 사용하는 대신 getter 및 setter(get 및 set만 가능)를 사용하면 어떤 이점이 있습니까?

getter와 setter가 단순한 get/set 이상의 작업을 수행하는 경우 이를 매우 빠르게 파악할 수 있지만 방법에 대해 100% 명확하지 않습니다.

 public String foo;

다음보다 더 나쁩니다:

 private String foo; public void setFoo(String foo) { this.foo = foo; } public String getFoo() { return foo; }

전자는 훨씬 적은 상용구 코드를 사용합니다.



캡슐화 및 향후 변경을 더 쉽게 만드는 것 이상으로 클래스의 필드를 직접 노출하는 것보다 접근자를 사용하는 것을 고려해야 하는 좋은 이유 가 실제로 많이 있습니다.

다음은 내가 알고 있는 몇 가지 이유입니다.

  • 속성을 가져오거나 설정하는 것과 관련된 동작의 캡슐화 - 이를 통해 나중에 더 쉽게 추가 기능(예: 유효성 검사)을 추가할 수 있습니다.
  • 대체 표현을 사용하여 속성을 노출하면서 속성의 내부 표현을 숨깁니다.
  • 공개 인터페이스를 변경으로부터 격리 - 기존 소비자에게 영향을 주지 않고 구현이 변경되는 동안 공개 인터페이스가 일정하게 유지되도록 합니다.
  • 속성의 수명 및 메모리 관리(폐기) 의미 제어 - 특히 관리되지 않는 메모리 환경(예: C++ 또는 Objective-C)에서 중요합니다.
  • 런타임에 속성이 변경될 때 디버깅 차단 지점 제공 - 속성이 특정 값으로 변경된 시기와 위치를 디버깅하는 것은 일부 언어에서 이것이 없으면 매우 어려울 수 있습니다.
  • 속성 getter/setter에 대해 작동하도록 설계된 라이브러리와의 향상된 상호 운용성 - Mocking, Serialization 및 WPF가 떠오릅니다.
  • 상속자가 getter/setter 메서드를 재정의하여 속성이 작동하고 노출되는 방식의 의미 체계를 변경할 수 있도록 합니다.
  • getter/setter가 값이 아닌 람다 식으로 전달되도록 허용합니다.
  • Getter와 setter는 다른 액세스 수준을 허용할 수 있습니다. 예를 들어 get은 공개될 수 있지만 세트는 보호될 수 있습니다.

LBushkin

지금부터 이주 (월, 년) 당신이 당신의 세터의 요구보다 단지 값을 설정보다 할 것을 깨닫게 때 때문에, 당신은 또한 속성 (238 개) 다른 클래스에 직접 사용 된 것을 깨닫게됩니다 :-)


ChssPly76

공개 필드는 필드를 반환하고 할당하는 것 외에는 아무것도 하지 않는 getter/setter 쌍보다 나쁘지 않습니다. 첫째, (대부분의 언어에서) 기능적 차이가 없다는 것이 분명합니다. 모든 차이점은 유지 관리 가능성이나 가독성과 같은 다른 요소에 있어야 합니다.

getter/setter 쌍의 자주 언급되는 이점은 그렇지 않습니다. 구현을 변경할 수 있고 클라이언트를 다시 컴파일할 필요가 없다는 주장이 있습니다. 아마도 setter를 사용하면 나중에 유효성 검사와 같은 기능을 추가할 수 있으며 클라이언트는 이에 대해 알 필요조차 없습니다. 그러나 setter에 유효성 검사를 추가하는 것은 전제 조건의 변경 이며 이전 계약을 위반하는 것입니다. 이는 아주 간단하게 "여기에 무엇이든 넣을 수 있고 나중에 getter에서 동일한 것을 얻을 수 있습니다"였습니다.

따라서 이제 계약을 위반했으므로 코드베이스의 모든 파일을 변경하는 것은 피하는 것이 아니라 해야 하는 일입니다. 그것을 피하면 모든 코드가 해당 메서드에 대한 계약을 가정한 것으로 가정합니다.

그것이 계약이 아니어야 한다면 인터페이스는 클라이언트가 개체를 잘못된 상태로 두는 것을 허용하고 있었습니다. 그것은 캡슐화의 정반대입니다. 그 필드가 처음부터 아무 것도 설정할 수 없다면 왜 처음부터 유효성 검사가 없었습니까?

이 동일한 주장은 이러한 통과 getter/setter 쌍의 다른 가정된 이점에도 적용됩니다. 나중에 설정되는 값을 변경하기로 결정하면 계약을 위반하는 것입니다. 몇 가지 무해한 수정(예: 로깅 또는 기타 관찰할 수 없는 동작)을 넘어 파생 클래스의 기본 기능을 재정의하면 기본 클래스의 계약을 위반하는 것입니다. 그것은 OO의 신조 중 하나로 간주되는 Liskov 대체 가능성 원칙에 대한 위반입니다.

클래스가 모든 필드에 대해 이러한 멍청한 getter와 setter를 가지고 있다면 그것은 불변성이나 계약 이 없는 클래스입니다. 그것이 정말로 객체 지향적인 디자인인가? 모든 클래스에 이러한 getter와 setter가 있는 경우, 이것은 단지 벙어리 데이터 홀더일 뿐이며 벙어리 데이터 홀더는 벙어리 데이터 홀더처럼 보여야 합니다.

 class Foo { public: int DaysLeft; int ContestantNumber; };

이러한 클래스에 통과 getter/setter 쌍을 추가하면 값이 추가되지 않습니다. 다른 클래스는 필드가 이미 제공하는 작업뿐만 아니라 의미 있는 작업을 제공해야 합니다. 이것이 유용한 불변량을 정의하고 유지하는 방법입니다.

클라이언트 : "이 클래스의 개체로 무엇을 할 수 있습니까?"
디자이너 : "여러 변수를 읽고 쓸 수 있습니다."
클라이언트 : "오... 멋지죠?"

getter와 setter를 사용하는 이유가 있지만, 그런 이유가 없다면 false encapsulation 신의 이름으로 getter/setter 쌍을 만드는 것은 좋지 않습니다. getter 또는 setter를 만드는 유효한 이유에는 유효성 검사 또는 다른 내부 표현과 같이 나중에 만들 수 있는 잠재적인 변경으로 자주 언급되는 사항이 포함됩니다. 또는 값은 클라이언트가 읽을 수 있지만 쓰기는 불가능해야 하므로(예: 사전 크기 읽기) 간단한 getter가 좋은 선택입니다. 그러나 그러한 이유는 선택을 할 때 거기에 있어야 하며 나중에 원할 수도 있는 잠재적인 것이 아닙니다. 이것은 YAGNI( You Ain't Gonna Need It )의 인스턴스입니다.


R. Martinho Fernandes

많은 사람들이 게터와 세터의 장점에 대해 이야기하지만 저는 악마의 옹호자 역할을 하고 싶습니다. 지금 나는 프로그래머가 모든 것을 getter와 setter로 만들기로 결정한 매우 큰 프로그램을 디버깅하고 있습니다. 보기에는 좋아 보이지만 역공학의 악몽입니다.

수백 줄의 코드를 살펴보고 다음과 같은 내용을 발견했다고 가정해 보겠습니다.

 person.name = "Joe";

setter를 깨달을 때까지는 아름답고 단순한 코드 조각입니다. 이제 해당 setter를 따라가서 person.firstName, person.lastName, person.isHuman, person.hasReallyCommonFirstName도 설정하고 데이터베이스에 쿼리를 보내는 person.update()를 호출하는 등을 찾습니다. 오, 그렇군요. 메모리 누수가 발생한 곳.

로컬 코드를 언뜻 이해하는 것은 getter와 setter가 깨지는 경향이 있는 좋은 가독성의 중요한 속성입니다. 그렇기 때문에 가능하면 피하고 사용할 때 하는 일을 최소화하려고 합니다.


Kai

순수한 객체 지향 세계에서 getter와 setter는 끔찍한 안티 패턴 입니다. 이 기사 읽기: Getters/Setters. 사악한. 기간 . 간단히 말해서 프로그래머가 객체를 데이터 구조로 생각하도록 권장하며 이러한 유형의 사고는 순수한 절차적(COBOL 또는 C에서와 같이)입니다. 객체 지향 언어에는 데이터 구조가 없지만 동작을 노출하는 객체만 있습니다(속성/속성이 아님!).

이에 대한 자세한 내용은 Elegant Objects (객체 지향 프로그래밍에 대한 내 책) 섹션 3.5에서 찾을 수 있습니다.


yegor256

많은 이유가 있습니다. 내가 가장 좋아하는 것은 행동을 변경하거나 변수에 설정할 수 있는 것을 규제해야 할 때입니다. 예를 들어, setSpeed(int speed) 메서드가 있다고 가정해 보겠습니다. 그러나 최대 속도를 100으로만 설정할 수 있기를 원합니다. 다음과 같이 하면 됩니다.

 public void setSpeed(int speed) { if ( speed > 100 ) { this.speed = 100; } else { this.speed = speed; } }

이제 코드의 모든 곳에서 공개 필드를 사용하다가 위의 요구 사항이 필요하다는 것을 깨달았다면 어떻게 될까요? setter를 수정하는 대신 public 필드의 모든 사용법을 재미있게 찾아보십시오.

내 2센트 :)


Peter D

접근자와 돌연변이자의 장점 중 하나는 유효성 검사를 수행할 수 있다는 것입니다.

예를 들어 foo null 쉽게 설정할 수 있으며 다른 사람이 해당 개체에서 메서드를 호출하려고 할 수 있습니다. 하지만 더 이상 거기에 없습니다! setFoo 메서드를 사용하면 foo null 설정되지 않았는지 확인할 수 있습니다.

접근자와 뮤테이터는 캡슐화도 허용합니다. 값이 설정되면(아마도 생성자에서 설정되고 메서드에서 사용되지만 절대 변경되어서는 안 됨) 값을 볼 수 없는 경우 아무에게도 표시되지 않습니다. 그러나 다른 클래스가 이를 보거나 변경하도록 허용할 수 있다면 적절한 접근자 및/또는 돌연변이자를 제공할 수 있습니다.


Thomas Owens

귀하의 언어에 따라 다릅니다. 이 태그를 "Java"가 아닌 "객체 지향"으로 지정했으므로 ChssPly76의 대답은 언어에 따라 다르다는 점을 지적하고 싶습니다. 예를 들어 파이썬에서는 getter와 setter를 사용할 이유가 없습니다. 동작을 변경해야 하는 경우 기본 속성 액세스 주위에 getter 및 setter를 래핑하는 속성을 사용할 수 있습니다. 이 같은:

 class Simple(object): def _get_value(self): return self._value -1 def _set_value(self, new_value): self._value = new_value + 1 def _del_value(self): self.old_values.append(self._value) del self._value value = property(_get_value, _set_value, _del_value)

jcdyer

덕분에 제 생각이 정말 명확해졌습니다. 이제 getter와 setter를 사용하지 않는 (거의) 10가지 (거의) 좋은 이유가 있습니다.

  1. 값을 설정하고 가져오는 것 이상의 작업이 필요하다는 것을 알게 되면 필드를 비공개로 만들 수 있습니다. 그러면 직접 액세스한 위치를 즉시 알 수 있습니다.
  2. 거기에서 수행하는 모든 유효성 검사는 컨텍스트가 없는 경우에만 가능하며 유효성 검사는 실제로 거의 없습니다.
  3. 설정 중인 값을 변경할 수 있습니다. 발신자가 [충격 공포]를 있는 그대로 저장하기를 원하는 값을 전달할 때 이것은 절대적인 악몽입니다.
  4. 내부 표현을 숨길 수 있습니다. 환상적입니다. 따라서 이러한 모든 작업이 대칭인지 확인하고 있습니까?
  5. 시트 아래의 변경 사항으로부터 공용 인터페이스를 격리했습니다. 인터페이스를 디자인할 때 무언가에 직접 액세스할 수 있는지 여부가 확실하지 않다면 계속 디자인해야 합니다.
  6. 일부 라이브러리는 이것을 기대하지만 많은 것은 아닙니다. 리플렉션, 직렬화, 모의 객체는 모두 공용 필드에서 잘 작동합니다.
  7. 이 클래스를 상속하면 기본 기능을 재정의할 수 있습니다. 즉, 구현을 숨길 뿐만 아니라 일관성이 없게 만들어 호출자를 혼란스럽게 할 수 있습니다.

내가 막 떠나는 마지막 세 개(N/A 또는 D/C)...


user595447

글쎄, 나는 때때로 그것들이 변수/객체의 캡슐화와 보안을 위해 필요하더라도 실제 객체 지향 프로그램을 코딩하고 싶다면 우리는 ACCESSORS를 남용하는 것을 중지해야 한다고 덧붙이고 싶습니다. 때로는 우리가 많이 의존하기 때문입니다. 실제로 필요하지 않을 때 변수를 공개하고 변수를 공개하는 것과 거의 동일하게 만듭니다.


Jorge Aguilar

조금 늦은 감이 있지만, 퍼포먼스에 관심이 있으신 분들이 계실 거라 생각합니다.

약간의 성능 테스트를 해봤습니다. 나는 Integer를 보유하는 "NumberHolder"클래스를 작성했습니다. anInstance.getNumber() anInstance.number 를 사용하여 숫자에 직접 액세스하여 정수를 읽을 수 있습니다. 내 프로그램은 두 가지 방법을 통해 숫자를 1,000,000,000번 읽습니다. 이 과정을 5번 반복하면 시간이 출력됩니다. 나는 다음과 같은 결과를 얻었다:

 Time 1: 953ms, Time 2: 741ms Time 1: 655ms, Time 2: 743ms Time 1: 656ms, Time 2: 634ms Time 1: 637ms, Time 2: 629ms Time 1: 633ms, Time 2: 625ms

(시간 1은 직접 방법, 시간 2는 getter)

알다시피, getter는 (거의) 항상 조금 더 빠릅니다. 그런 다음 다른 수의 주기로 시도했습니다. 100만 대신 1000만과 1000만을 사용했다. 결과:

천만 사이클:

 Time 1: 6382ms, Time 2: 6351ms Time 1: 6363ms, Time 2: 6351ms Time 1: 6350ms, Time 2: 6363ms Time 1: 6353ms, Time 2: 6357ms Time 1: 6348ms, Time 2: 6354ms

1000만 사이클의 경우 시간은 거의 동일합니다. 다음은 100,000(0.1백만) 주기입니다.

 Time 1: 77ms, Time 2: 73ms Time 1: 94ms, Time 2: 65ms Time 1: 67ms, Time 2: 63ms Time 1: 65ms, Time 2: 65ms Time 1: 66ms, Time 2: 63ms

또한 주기가 다르기 때문에 getter는 일반 방식보다 약간 빠릅니다. 도움이 되었기를 바랍니다.


kangalioo

편집 : 프로그래밍을 배우는 많은 사람들이 이것을 묻는 많은 사람들이 있기 때문에이 질문에 대답했으며 대부분의 답변은 매우 기술적으로 유능하지만 초보자라면 이해하기 쉽지 않습니다. 우리는 모두 뉴비였기 때문에 더 뉴비에게 친근한 답변을 해보자고 생각했습니다.

두 가지 주요 기능은 다형성과 유효성 검사입니다. 그것이 단지 어리석은 데이터 구조일지라도.

다음과 같은 간단한 클래스가 있다고 가정해 보겠습니다.

 public class Bottle { public int amountOfWaterMl; public int capacityMl; }

액체의 양과 용량(밀리리터)을 보유하는 매우 간단한 클래스입니다.

다음을 수행하면 어떻게 됩니까?

 Bottle bot = new Bottle(); bot.amountOfWaterMl = 1500; bot.capacityMl = 1000;

글쎄, 당신은 그것이 효과가있을 것이라고 기대하지 않을 것입니다. 당신은 일종의 온전한 검사가 있기를 원합니다. 더군다나 최대 용량을 지정하지 않으면 어떻게 될까요? 이런, 문제가 있습니다.

하지만 또 다른 문제도 있습니다. 병이 단지 한 종류의 용기라면? 액체의 용량과 양이 모두 채워진 여러 개의 용기가 있다면 어떨까요? 인터페이스만 만들 수 있다면 프로그램의 나머지 부분이 그 인터페이스를 받아들이도록 할 수 있고 병, 제리캔 및 모든 종류의 물건은 상호 교환 가능하게 작동합니다. 더 좋지 않을까요? 인터페이스는 메서드를 요구하기 때문에 이것도 좋은 일입니다.

우리는 다음과 같이 끝낼 것입니다:

 public interface LiquidContainer { public int getAmountMl(); public void setAmountMl(int amountMl); public int getCapacityMl(); }

엄청난! 이제 Bottle을 다음과 같이 변경합니다.

 public class Bottle extends LiquidContainer { private int capacityMl; private int amountFilledMl; public Bottle(int capacityMl, int amountFilledMl) { this.capacityMl = capacityMl; this.amountFilledMl = amountFilledMl; checkNotOverFlow(); } public int getAmountMl() { return amountFilledMl; } public void setAmountMl(int amountMl) { this.amountFilled = amountMl; checkNotOverFlow(); } public int getCapacityMl() { return capacityMl; } private void checkNotOverFlow() { if(amountOfWaterMl > capacityMl) { throw new BottleOverflowException(); } }

BottleOverflowException의 정의는 독자에게 연습으로 남겨두겠습니다.

이제 이것이 얼마나 더 강력한지 주목하십시오. 이제 Bottle 대신 LiquidContainer를 수락하여 코드에서 모든 유형의 컨테이너를 처리할 수 있습니다. 그리고 이 병이 이런 종류의 물건을 처리하는 방법은 모두 다를 수 있습니다. 상태가 변경될 때 디스크에 상태를 기록하는 병이나 SQL 데이터베이스나 GNU에 저장하는 병이 있을 수 있습니다.

그리고 이 모든 것들은 다양한 헛소리를 처리하는 다른 방법을 가질 수 있습니다. Bottle은 확인만 하고 넘치면 RuntimeException을 던집니다. 그러나 그것은 잘못된 행동일 수 있습니다. (오류 처리에 대해 유용한 토론이 있지만 여기서는 의도적으로 매우 간단하게 유지하고 있습니다. 댓글에 있는 사람들은 이 단순한 접근 방식의 결함을 지적할 가능성이 높습니다. ;) )

그리고 예, 우리는 매우 간단한 아이디어에서 훨씬 더 나은 답변을 빨리 얻는 것으로 이동하는 것 같습니다.

또한 병의 용량은 변경할 수 없습니다. 그것은 지금 돌로 설정되었습니다. int를 final로 선언하여 이 작업을 수행할 수 있습니다. 그러나 이것이 목록이라면 비우고 새 항목을 추가하는 등의 작업을 수행할 수 있습니다. 내장을 만지는 것에 대한 접근을 제한할 수 없습니다.

모든 사람이 다루지 않은 세 번째 사항도 있습니다. getter와 setter는 메서드 호출을 사용합니다. 즉, 다른 모든 곳에서 일반적인 방법처럼 보입니다. DTO 및 기타 항목에 대해 이상한 특정 구문을 사용하는 대신 모든 곳에서 동일한 것을 사용할 수 있습니다.


Haakon Løtveit

우리는 getter와 setter를 사용합니다:

  • 재사용을 위해
  • 프로그래밍의 나중 단계에서 유효성 검사를 수행하기 위해

Getter 및 setter 메서드는 개인 클래스 멤버에 액세스하기 위한 공용 인터페이스입니다.


캡슐화 만트라

캡슐화 만트라는 필드를 비공개로 만들고 메서드를 공개하는 것입니다.

Getter 메서드: 개인 변수에 액세스할 수 있습니다.

Setter 메서드: 개인 필드를 수정할 수 있습니다.

getter 및 setter 메소드가 새로운 기능을 추가하지 않더라도 나중에 생각을 변경하여 해당 메소드를 만들 수 있습니다.

  • 더 나은;
  • 더 안전한; 그리고
  • 더 빠르게.

값을 사용할 수 있는 모든 위치에 해당 값을 반환하는 메서드를 추가할 수 있습니다. 대신에:

 int x = 1000 - 500

사용하다

 int x = 1000 - class_name.getValue();

평신도 용어로

"Person" 클래스의 표현

Person 의 세부 정보를 저장해야 한다고 가정합니다. 이 Person name , age , sex 필드를 가지고 있습니다. name , agesex 대한 메서드를 만드는 작업이 포함됩니다. 이제 다른 사람을 생성해야 하는 경우 name , age , sex 대한 메서드를 다시 생성해야 합니다.

이렇게 하는 대신 getter 및 setter 메서드를 class(Person) 그래서 내일 우리는 새로운 사람을 추가해야 할 때마다 class(Person class) 객체를 생성할 수 있습니다(그림 참조). 따라서 우리는 훨씬 더 나은 bean 클래스의 필드와 메소드를 재사용하고 있습니다.


Devrath

나는 Java의 경우에 대해 이것을 생각하는 데 꽤 오랜 시간을 보냈고 실제 이유는 다음과 같다고 생각합니다.

  1. 구현이 아닌 인터페이스에 대한 코드
  2. 인터페이스는 필드가 아닌 메서드만 지정합니다.

즉, 인터페이스에서 필드를 지정할 수 있는 유일한 방법은 새 값을 쓰는 방법과 현재 값을 읽는 방법을 제공하는 것입니다.

이러한 방법은 악명 높은 getter 및 setter입니다....


Thorbjørn Ravn Andersen

현재 전달에 필요한 경우가 아니면 getter setter를 사용하지 마십시오. 즉, 대부분의 프로덕션 애플리케이션, 시스템에서 변경 요청이 변경될 경우 미래에 일어날 일에 대해 너무 많이 생각하지 마십시오.

간단하고 쉽게 생각하고 필요할 때 복잡성을 추가하십시오.

나는 그것이 옳다고 생각하거나 접근 방식이 마음에 든다고 해서 깊은 기술 지식을 가진 비즈니스 소유자의 무지를 이용하지 않을 것입니다.

접근 수정자와 n 수행 biz 논리를 검증하는 몇 가지 방법으로만 getter setter 없이 작성된 대규모 시스템이 있습니다. 당신이 절대적으로 필요하다면. 무엇이든 사용하세요.


Mohamed

지연 로딩에 유용할 수 있습니다. 문제의 개체가 데이터베이스에 저장되어 있고 필요한 경우가 아니면 가져오고 싶지 않다고 가정해 보겠습니다. 객체가 getter에 의해 검색되면 누군가 요청할 때까지 내부 객체가 null이 될 수 있습니다. 그러면 getter에 대한 첫 번째 호출에서 가져올 수 있습니다.

몇 가지 다른 웹 서비스 호출에서 일부 데이터를 로드하는 프로젝트에 기본 페이지 클래스가 있었지만 해당 웹 서비스 호출의 데이터가 모든 하위 페이지에서 항상 사용되지는 않았습니다. 웹 서비스는 모든 이점에 대해 "느림"의 새로운 정의를 개척하므로 필요하지 않은 경우 웹 서비스 호출을 원하지 않습니다.

공개 필드에서 getter로 이동했으며 이제 getter가 캐시를 확인하고 캐시가 없으면 웹 서비스를 호출합니다. 따라서 약간의 래핑으로 많은 웹 서비스 호출이 방지되었습니다.

따라서 getter를 사용하면 각 자식 페이지에서 내가 필요한 것이 무엇인지 알아내려고 하지 않아도 됩니다. 내가 필요하면 getter를 호출하고 내가 아직 가지고 있지 않으면 나를 위해 찾아갑니다.

 protected YourType _yourName = null; public YourType YourName{ get { if (_yourName == null) { _yourName = new YourType(); return _yourName; } } }

quillbreaker

지금까지 답변에서 놓친 한 가지 측면은 액세스 사양입니다.

  • 회원의 경우 설정 및 가져오기 모두에 대해 하나의 액세스 사양만 있습니다.
  • setter 및 getter의 경우 미세 조정하고 별도로 정의할 수 있습니다.

jdehaan

"속성"(C++, Java)을 지원하지 않거나 필드를 속성(C#)으로 변경할 때 클라이언트를 다시 컴파일해야 하는 언어에서는 get/set 메서드를 사용하여 수정하는 것이 더 쉽습니다. 예를 들어, setFoo 메서드에 유효성 검사 논리를 추가하는 경우 클래스의 공용 인터페이스를 변경할 필요가 없습니다.

"실제" 속성을 지원하는 언어(Python, Ruby, 아마도 Smalltalk?)에서는 메서드를 가져오거나 설정할 필요가 없습니다.


John Millikin

객체지향 디자인의 기본 원칙 중 하나: 캡슐화!

많은 이점을 제공합니다. 그 중 하나는 배후에서 getter/setter의 구현을 변경할 수 있지만 해당 값의 소비자는 데이터 유형이 동일하게 유지되는 한 계속 작동한다는 것입니다.


Justin Niessner

다음과 같은 경우 getter 및 setter를 사용해야 합니다.

  • 당신은 개념적으로 속성인 것을 다루고 있지만:
    • 귀하의 언어에는 속성(또는 Tcl의 변수 추적과 같은 유사한 메커니즘)이 없습니다.
    • 귀하의 언어 속성 지원이 이 사용 사례에 충분하지 않거나
    • 귀하의 언어(또는 때때로 귀하의 프레임워크)의 관용적 규칙은 이 사용 사례에 대한 getter 또는 setter를 권장합니다.

따라서 이것은 매우 드물게 일반적인 OO 질문입니다. 다른 언어(및 다른 사용 사례)에 대해 다른 답변이 있는 언어별 질문입니다.


객체지향 이론의 관점에서 getter와 setter는 쓸모가 없습니다. 클래스의 인터페이스는 상태가 아니라 클래스가 수행하는 작업입니다. (그렇지 않다면 잘못된 클래스를 작성한 것입니다.) 클래스가 수행하는 작업이 직교 좌표*의 한 점을 나타내는 것과 같은 매우 간단한 경우에 속성은 인터페이스의 일부입니다. getter와 setter는 그것을 흐리게합니다. 그러나 매우 단순한 경우를 제외하고는 속성이나 getter 및 setter가 인터페이스의 일부가 아닙니다.

다시 말해, 당신의 클래스 소비자가 당신에게 spam 속성이 있다는 사실조차 알지 못한다고 생각한다면, 그것을 마음대로 변경할 수는 set_spam 것입니다. 그러면 그들에게 set_spam 메소드를 제공하는 것이 당신이 하고 싶은 마지막 일입니다.

xy 값 설정을 반드시 허용하고 싶지 않을 수 있습니다. translate , rotate 등과 같은 메서드가 있어야 하지 않을까요? 당신의 언어에 레코드/구조체/명명된 튜플이 없기 때문에 클래스일 뿐이라면 이것은 실제로 OO의 문제가 아닙니다…


그러나 아무도 일반적인 OO 디자인을 하지 않습니다. 그들은 특정 언어로 디자인과 구현을 하고 있습니다. 그리고 일부 언어에서는 getter와 setter가 전혀 쓸모가 없습니다.

언어에 속성이 없는 경우 개념적으로는 속성이지만 실제로 계산되거나 검증되는 등을 나타내는 유일한 방법은 getter 및 setter를 사용하는 것입니다.

언어에 속성이 있더라도 불충분하거나 부적절한 경우가 있을 수 있습니다. 예를 들어, 동적 액세스가 없는 언어에서 하위 클래스가 속성의 의미를 제어하도록 허용하려는 경우 하위 클래스는 속성에 대해 계산된 속성을 대체할 수 없습니다.

"나중에 구현을 변경하려면 어떻게 합니까?" 질문(OP의 질문과 허용된 답변 모두에서 다른 표현으로 여러 번 반복됨): 실제로 순수한 구현 변경이고 속성으로 시작한 경우 인터페이스에 영향을 주지 않고 속성으로 변경할 수 있습니다. 물론, 당신의 언어가 그것을 지원하지 않는 한. 그래서 이것은 다시 같은 경우입니다.

또한 사용 중인 언어(또는 프레임워크)의 관용구를 따르는 것이 중요합니다. C#으로 아름다운 Ruby 스타일 코드를 작성하면 당신이 아닌 경험 많은 C# 개발자가 그것을 읽는 데 어려움을 겪을 것입니다. 일부 언어는 다른 언어보다 관습에 더 강한 문화를 가지고 있습니다. 그리고 관용적 getter의 스펙트럼의 반대편에 있는 Java와 Python이 우연히 가장 강력한 두 문화를 갖게 된 것은 우연이 아닐 수도 있습니다.

인간 독자를 넘어서, 당신이 규칙을 따르기를 기대하는 라이브러리와 도구가 있을 것이며, 그렇지 않으면 당신의 삶을 더 힘들게 만들 것입니다. Interface Builder 위젯을 ObjC 속성 이외의 다른 것에 연결하거나 getter 없이 특정 Java 모의 라이브러리를 사용하는 것은 삶을 더 어렵게 만들고 있습니다. 도구가 당신에게 중요하다면, 그것들과 싸우지 마십시오.


abarnert

객체 지향 설계 관점에서 두 대안 모두 클래스의 캡슐화를 약화시켜 코드 유지 관리에 손상을 줄 수 있습니다. 토론을 위해 이 훌륭한 기사를 살펴볼 수 있습니다. http://typicalprogrammer.com/?p=23


andrers52

코드 는 진화합니다 . private 은 데이터 구성원 보호가 필요할 때 유용합니다. 결국 모든 클래스는 잘 정의된 인터페이스를 가진 일종의 "미니 프로그램"이 되어야 합니다. 이 인터페이스는 .

즉, 소프트웨어 개발 은 첫 번째 시도에서 주철 조각상을 누르는 것처럼 클래스의 최종 버전을 설정하는 것이 아닙니다. 작업하는 동안 코드는 점토와 비슷합니다. 그것은 당신이 그것을 개발하고 당신이 해결하고 있는 문제 영역에 대해 더 많이 배우면서 발전합니다. 개발하는 동안 클래스는 해야 하는 것보다 서로 상호 작용하거나(제거하려는 종속성), 함께 병합하거나 분리할 수 있습니다. 그래서 나는 논쟁이 종교적으로 글을 쓰기를 원하지 않는 사람들로 귀결된다고 생각합니다.

 int getVar() const { return var ; }

그래서 당신은 가지고 있습니다 :

 doSomething( obj->getVar() ) ;

대신에

 doSomething( obj->var ) ;

getVar() 시각적으로 시끄러울 뿐만 아니라 gettingVar() 가 실제보다 더 복잡한 프로세스라는 환상을 줍니다. 당신이 (클래스 작성자로서) var 의 신성함을 어떻게 여기는지는 패스스루 세터가 있는 경우 클래스 사용자에게 특히 혼란스럽습니다. 그러면 당신이 가치 있다고 주장하는 것을 "보호"하기 위해 이러한 게이트를 설치하는 것처럼 보입니다. , ( var 의 신성함) 그러나 당신도 var 의 보호가 그들이 하는 일을 엿보지도 않고 var set 수 있는 능력에 의해 그다지 가치가 없다는 것을 인정합니다.

그래서 저는 다음과 같이 프로그래밍합니다("민첩한" 유형의 접근 방식을 가정합니다. 즉, 코드를 작성할 때 수행할 작업을 정확히 알지 못하거나 정교한 워터폴 스타일 인터페이스 세트를 계획할 시간이나 경험이 없을 때):

1) 데이터 및 동작이 있는 기본 개체에 대한 모든 공개 멤버로 시작합니다. 이것이 내 모든 C++ "예제" 코드에서 class struct 를 사용하는 것을 볼 수 있는 이유입니다.

2) 데이터 멤버에 대한 개체의 내부 동작이 충분히 복잡해지면(예 std::list 를 어떤 종류의 순서로 유지하려는 경우) 접근자 유형 함수가 작성됩니다. 나는 혼자 프로그래밍하고 있기 때문에 항상 멤버를 private 설정하지는 않지만 어딘가에 클래스의 진화는 멤버가 protected 또는 private 으로 "승격"될 것입니다.

3) 완전히 구체화하고 자신의 내부에 대한 엄격한 규칙을 (즉, 그들이 일을 정확히 알고, 당신이 "씨발"(전문 용어로하지 않습니다)의 내부와) 지정된되어이되는 클래스 class private 멤버를 기본값을 지정 , 그리고 선택된 소수의 구성원만이 public 될 수 있습니다.

이 접근 방식을 사용하면 클래스 진화의 초기 단계에서 많은 데이터 멤버가 마이그레이션되거나 다른 곳으로 이동할 때 거기에 앉아서 종교적으로 getter/setter를 작성하는 것을 피할 수 있습니다.


bobobobo

GetterSetter 는 다음과 같은 객체 지향 프로그래밍의 두 가지 기본 측면을 구현하는 데 사용됩니다.

  1. 추출
  2. 캡슐화

Employee 클래스가 있다고 가정합니다.

 package com.highmark.productConfig.types; public class Employee { private String firstName; private String middleName; private String lastName; public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getMiddleName() { return middleName; } public void setMiddleName(String middleName) { this.middleName = middleName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getFullName(){ return this.getFirstName() + this.getMiddleName() + this.getLastName(); } }

여기서 Full Name의 구현 세부 정보는 사용자에게 숨겨져 있으며 public 속성과 달리 사용자가 직접 액세스할 수 없습니다.


Pritam Banerjee

Getter 및 setter 메서드는 접근자 메서드입니다. 즉, 일반적으로 private 클래스 멤버를 변경하는 공용 인터페이스입니다. getter 및 setter 메서드를 사용하여 속성을 정의합니다. getter 및 setter 메서드는 클래스 내에서 메서드로 정의하더라도 클래스 외부의 속성으로 액세스합니다. 클래스 외부의 속성은 클래스의 속성 이름과 다른 이름을 가질 수 있습니다.

속성처럼 액세스할 수 있는 정교한 기능으로 멤버를 생성할 수 있는 기능과 같이 getter 및 setter 메서드를 사용하면 몇 가지 이점이 있습니다. 또한 읽기 전용 및 쓰기 전용 속성을 생성할 수 있습니다.

getter 및 setter 메서드가 유용하더라도 다른 문제 중에서 특정 상황에서 코드 유지 관리를 더 어렵게 만들 수 있으므로 남용하지 않도록 주의해야 합니다. 또한 public 멤버와 같은 클래스 구현에 대한 액세스를 제공합니다. OOP 관행은 클래스 내의 속성에 대한 직접 액세스를 권장하지 않습니다.

클래스를 작성할 때 항상 가능한 한 많은 인스턴스 변수를 비공개로 만들고 그에 따라 getter 및 setter 메서드를 추가하는 것이 좋습니다. 사용자가 클래스 내에서 특정 변수를 변경하는 것을 원하지 않을 수 있는 경우가 여러 번 있기 때문입니다. 예를 들어 특정 클래스에 대해 생성된 인스턴스 수를 추적하는 전용 정적 메서드가 있는 경우 사용자가 코드를 사용하여 해당 카운터를 수정하는 것을 원하지 않습니다. 생성자 문만 호출될 때마다 해당 변수를 증가시켜야 합니다. 이 상황에서 개인 인스턴스 변수를 만들고 카운터 변수에 대해서만 getter 메서드를 허용할 수 있습니다. 즉, 사용자는 getter 메서드를 사용해야만 현재 값을 검색할 수 있고 새 값을 설정할 수 없습니다. setter 메서드를 사용합니다. setter 없이 getter를 만드는 것은 클래스의 특정 변수를 읽기 전용으로 만드는 간단한 방법입니다.


Sumit Singh

접근자를 사용하는 것을 고려해야 하는 좋은 이유는 속성 상속이 없기 때문입니다. 다음 예를 참조하십시오.

 public class TestPropertyOverride { public static class A { public int i = 0; public void add() { i++; } public int getI() { return i; } } public static class B extends A { public int i = 2; @Override public void add() { i = i + 2; } @Override public int getI() { return i; } } public static void main(String[] args) { A a = new B(); System.out.println(ai); a.add(); System.out.println(ai); System.out.println(a.getI()); } }

산출:

 0 0 4

GeZo

(속성을 지원하는 언어에서) 또 다른 용도는 setter와 getter가 작업이 중요하지 않다는 것을 암시할 수 있다는 것입니다. 일반적으로 속성에서 계산 비용이 많이 드는 작업은 피하려고 합니다.


Jason Baker

getter/setter의 비교적 현대적인 이점 중 하나는 태그가 지정된(인덱싱된) 코드 편집기에서 코드를 더 쉽게 탐색할 수 있다는 것입니다. 예를 들어 누가 구성원을 설정했는지 확인하려면 설정자의 호출 계층을 열 수 있습니다.

반면에 구성원이 공개인 경우 도구를 사용하여 구성원에 대한 읽기/쓰기 액세스를 필터링할 수 없습니다. 그래서 당신은 회원의 모든 용도를 터벅터벅 걸어야 합니다.


Rakesh Singh

객체 지향 언어에서 메서드 및 해당 액세스 한정자는 해당 객체에 대한 인터페이스를 선언합니다. 생성자와 접근자 및 변경자 메서드 사이에서 개발자는 개체의 내부 상태에 대한 액세스를 제어할 수 있습니다. 변수가 단순히 공개로 선언되면 해당 액세스를 규제할 방법이 없습니다. 그리고 setter를 사용할 때 필요한 입력에 대해 사용자를 제한할 수 있습니다. 바로 그 변수에 대한 피드가 적절한 채널을 통해 올 것이고 채널은 우리가 미리 정의한다는 것을 의미합니다. 따라서 setter를 사용하는 것이 더 안전합니다.


Antz

또한 이것은 클래스를 "미래에 대비"하기 위한 것입니다. 특히 필드에서 속성으로 변경하는 것은 ABI 중단이므로 나중에 "필드 설정/가져오기"보다 더 많은 논리가 필요하다고 결정하면 ABI를 중단해야 합니다. else는 이미 클래스에 대해 컴파일되었습니다.


Pete

주석의 아이디어를 던지고 싶습니다: @getter 및 @setter. @getter를 사용하면 obj = class.field는 가능하지만 class.field = obj는 불가능합니다. @setter를 사용하면 그 반대도 마찬가지입니다. @getter와 @setter를 사용하면 둘 다 할 수 있어야 합니다. 이렇게 하면 런타임에 간단한 메서드를 호출하지 않음으로써 캡슐화를 유지하고 시간을 줄일 수 있습니다.


fastcodejava

출처 : http:www.stackoverflow.com/questions/1568091/why-use-getters-and-setters-accessors

반응형