변수에 getter 및 setter가있는 경우 공용이어야합니까?


23

개인 변수가있는 클래스가 있고 클래스에 해당 변수에 대한 getter 및 setter가 있습니다. 왜 변수를 공개하지 않습니까?

getter와 setter를 사용해야한다고 생각하는 유일한 경우는 set 또는 get 이외의 작업을 수행 해야하는 경우입니다. 예:

void my_class::set_variable(int x){
   /* Some operation like updating a log */
   this->variable = x;
}

10
게터와 세터는 차폐를 위해 존재합니다. 언젠가는을 수행 this->variable = x + 5하거나 UpdateStatisticssetter에서 함수를 호출 하려고 할 수 있으며 이러한 경우 classinstancea->variable = 5문제가 발생할 수 있습니다.
Coder

1
또 다른 예이다 : set_inch, set_centimeter, get_inch, get_centimeter, 약간의 무시 무시한 행동으로.
rwong

예, getter 및 setter를 사용하면 인스턴스 변수를 원하는 방식으로 제어 할 수 있습니다.
developerdoug

7
@ 코더 : 필요한 경우 언제든지 getter / setter를 추가 할 수 있습니까? 아니면 이것이 C ++에서 쉽게 할 수없는 일입니까 (제 경험은 대부분 Delphi입니다)?
Marjan Venema

이 질문 : programmers.stackexchange.com/questions/21802/… 관심이있을 수 있습니다.
Winston Ewert

답변:


21

재산에 대해 들어 본 적이 있습니까?

속성은 "기본 제공"접근 자 (getter 및 setter)가있는 필드입니다. 예를 들어 Java에는 속성이 없지만 게터와 세터를 개인 필드에 쓰는 것이 좋습니다. C #에는 속성이 있습니다.

그렇다면 왜 게터와 세터가 필요합니까? 기본적으로 우리 는 필드 를 보호 / 차폐 하기 위해 필요합니다 . 예를 들어, 메모리 참조에서 필드에 액세스하지 않고 필드를 변경하는 메소드 (참조)에 액세스합니다. 이 방법을 사용하면 예와 같이 사용자가 알지 못하는 일부 동작 ( 캡슐화 동작 ) 을 수행 할 수 있습니다. 예를 들어, 12 개의 클래스가 공용 필드를 사용하고 사용 방식을 변경해야한다고 가정 해보십시오. 필드 사용 방식을 변경하려면 각 클래스를 살펴 봐야합니다. "OOlysh"입니다.

그러나 예를 들어, dead라는 부울 필드가있는 경우. setDead 및 isDead를 선언하기 전에 두 번 생각해야합니다. 사람이 읽을 수있는 접근 자를 작성해야합니다 (예 : setDead 대신 kill ()).

그러나 JavaBean 명명 규칙을 따르고 있다고 가정하는 많은 프레임 워크가 있으므로 (여기서는 Java에 대해 이야기 함) 이러한 경우 명명 대류에 따라 모든 getter 및 setter를 선언해야합니다.


2
이제 "사람이 읽을 수 있음"은 마침내 "청산 할 수있는"논쟁입니다. 내가 일반적으로 듣는 다른 모든 주장은 필요할 때 쉽게 해결할 수있는 일종의 미래 증거입니다.
Marjan Venema

13
"미래 교정"에 대한 당신의 경멸은 일반적이지만 잘못 인도됩니다. 예, 해당 코드의 유일한 클라이언트 인 경우 필요할 때 이러한 변경 사항을 해결할 수 있습니다 . 외부 고객을위한 솔루션을 게시하지 않으면 기술 부채가 발생하기 때문에 아무도 알 필요가 없습니다. 그러나 내부 프로젝트는 최소한 기대할 때 공개되는 습관이 있으며, 그런 다음 자신에게 화를냅니다.
Kilian Foth

2
당신은 실제로 환상적인 포인트를 올립니다. kill은 세트 / get이 아니며 액션입니다. 구현을 완전히 숨 깁니다. OO를 코딩하는 방식입니다. 반면, 속성은 setters / getters와 같은 바보입니다. 쉬운 구문은 사람들이 필요하지 않을 때 변수에 변수를 추가하도록 장려하기 때문에 더욱 빨라집니다 (OO-Furbar 대기 중). 죽은 속성에 "속성"태그를 추가 할 때 kill ()을 사용하는 사람은 누구입니까?
Bill K

1
질문은 C ++ 질문으로 태그됩니다. C ++은 속성을 지원하지 않으므로 왜 이것을 게시하겠습니까?
Thomas Eding

1
@ThomasEding : C ++는 재정의 가능한 할당 연산자를 갖는 데있어 다소 독특합니다. C ++은 "속성"이라는 용어를 C # 또는 VB.NET과 같은 언어와 같은 방식으로 사용하지 않지만 개념은 여전히 ​​존재합니다. C ++에서 연산자 오버로딩을 사용 하여 평가 foo.bar = biz.baz+5biz위해 함수를 호출 한 baz다음 5를 추가 하고 결과 값 foo으로 설정 bar하기 위해 함수를 호출 할 수 있습니다 . 이러한 과부하를 "속성"이라고 부르지는 않지만 동일한 목적으로 사용할 수 있습니다.
supercat

25

이것은 가장 대중적인 의견은 아니지만 큰 차이는 없습니다.

세터와 게터는 상당히 나쁜 생각입니다. 나는 그것에 대해 생각했고 솔직히 setter / getter 속성과 실제 변수 사이의 차이점을 생각해 낼 수 없습니다.

이론에서 setter와 getter 또는 property는 변수가 설정 / 취득 될 때 추가 조치를 취할 수있는 장소를 추가하고 이론적으로 코드를 변경으로부터 분리합니다.

실제로 액션을 추가하는 데 사용되는 세터와 게터는 거의 보지 못하며 액션을 추가하려고 할 때 로깅과 같은 클래스의 모든 세터 또는 게터에 액션을 추가하려고합니다. 더 나은 솔루션이 되십시오.

설계 의사 결정을 분리하는 것과 관련하여 int를 오랫동안 변경하면 setter를 변경하고 최소한 직접 설정하여 액세스하는 모든 줄을 확인해야합니다.

어쨌든 가변 클래스는 기본적으로 피해야하므로 setter를 추가하는 것이 최후의 수단이되어야합니다. 오브젝트가 원하는 상태가 될 때까지 값을 설정할 수있는 클래스가 변경 될 수없고 클래스가 변경되지 않고 설정자가 예외를 발생시키는 빌더 패턴으로 완화됩니다.

게터에 관해서는-나는 여전히 게터와 공개 최종 변수 사이의 많은 차이점을 생각해 낼 수 없습니다. 여기서 문제는 어느 경우 든 나쁜 OO라는 것입니다. 객체의 값을 요구하거나 조작해서는 안됩니다. 객체를 조작 해달라고 요구해야합니다.

그건 그렇고, 공개 변수를 옹호하는 것은 아닙니다. 세터와 게터 (및 속성)는 이미 공개 변수와 너무 가깝습니다.

큰 문제는 OO 프로그래머가 아닌 사람들이 setter와 getter를 사용하여 객체 지향 코드가 작동하는 방식과 반대되는 속성 볼 (구조)로 객체를 만들기 위해 너무 유혹적이라는 것입니다.


getter setter에 대한 다른 답변과는 다른 한 가지 좋은 점은 실제 개인 변수가 값을 가정하기 전에 그 안에 유효성 검사 / 변환을 추가 할 수 있다는 것입니다.
WinW

1
@Kiran true, 그러나 생성자에서 설정하면 유효성을 검사 할 수 있으며 변경할 수없는 클래스가 있습니다. 세터에게는 공개 쓰기 가능 변수가 좋다고 말하는 것이 아니라 세터조차도 나쁘다는 것입니다. 게터에게는 공개 최종 변수를 실행 가능한 대안으로 생각할 수 있습니다.
Bill K

C #과 같은 일부 언어에서는 속성이 공용 변수와 이진 호환되지 않으므로 공용 변수를 API의 일부로 만들고 일부 유효성 검사를 추가하려는 경우 클라이언트 프로그램을 변환 할 때 클라이언트 프로그램이 중단됩니다 재산. 처음부터 공공 재산으로 만드는 것이 좋습니다.
Robert Harvey

@RobertHarvey 그것은 여전히 ​​당신이 속성을 노출한다는 것을 의미합니다. 내 요점은 속성 노출을 피해야하며 필요한 경우 getter로 제한하고 클래스를 변경할 수 없도록해야한다는 것입니다. 클래스가 변경 불가능한 경우 왜 getter에 코드가 필요하므로 getter가 없을 수도 있습니다. 노출 가능한 가변 속성없이 클래스를 작성할 수없는 경우 예, setter는 항상 쓰기 가능한 공용 변수보다 낫습니다 (그리고 발에 총을 쏘는 것이 내장에 찔린 것보다 항상 낫습니다).
Bill K

1
가변 상태는 허용 가능하지만 다시 객체에 무언가를 요구하고 객체에 대해 무언가를 요구해서는 안됩니다. 따라서 상태를 변경하면 세터가 그것을 수행하는 좋은 방법이 아니므로 논리를 사용하여 비즈니스 메소드를 작성하십시오. 대신에. 예를 들어 "setZLocation (getZLocation () + 5)가 아닌 move (Up5)"입니다.
Bill K

8

게터와 세터 사용자는 캡슐화 의 원칙을 따릅니다 . 이를 통해 수업 내에서 사물이 작동하는 방식을 변경하고 모든 기능을 유지할 수 있습니다.

예를 들어 3 개의 다른 객체 foo.bar가 bar의 값을 얻기 위해 호출 하고 bar의 이름을 멀리 변경하기로 결정한 경우 손에 문제가 있습니다. 객체가 호출 foo.bar되면이를 가진 모든 클래스를 변경해야합니다. setter / getter를 사용하면 변경할 것이 없습니다. 또 다른 가능성은 변수의 유형을 변경하는 것입니다.이 경우 getter / setter에 일부 변환 코드를 추가하면됩니다.


1
+1-멤버 변수는 구현이고, getter 및 setter는 인터페이스입니다. 인터페이스 만 공개되어야합니다. 또한 getter 및 setter 이름은 단순한 멤버 변수가 있는지 또는 다른 구현에 관계없이 추상화 측면에서 의미가 있어야합니다. 단단하게 결합 된 클래스로 작성된 서브 시스템이 가장 쉬운 방법 인 예외 가 있습니다. 그러나 데이터 숨김 경계를 어쨌든 전체 서브 시스템을 나타내는 클래스로 끌어 올립니다.
Steve314

수업 내에서 작업을 변경해야 할 때 게터 및 / 또는 세터를 간단히 소개 할 수 없습니까? 델파이에서는 쉽게 할 수 있지만 다른 언어로는 할 수없는 것입니까?
Marjan Venema

@ marjan 물론, 나중에 언제든지 getter / setter를 소개 할 수 있습니다. 문제는 다시 돌아가서 getter / setter 대신 public 필드를 사용하고 있던 모든 코드를 변경해야한다는 것입니다. 내가 혼란스러워하는 사람인지 당신인지 확실하지 않습니다. 0.o
Pete

3
개인적으로, 나는 이것이 약간의 가짜 주장이라고 생각합니다. 변수의 의미를 변경했지만 변수에 게터와 세터가 있으면 변수가 무엇인지는 중요하지 않습니다. 인터페이스에서 보이지 않는 부분입니다. 캡슐화 된 변수의 의미에 대한 변경 또는 설명을 클라이언트에 표시하기 위해 게터 및 세터 자체의 이름을 변경하려고 할 가능성이 훨씬 높습니다. 후자의 경우 공용 변수를 사용하면 더 나은 위치에 있지 않습니다. 이것은 getter와 setter가있는 변수가 캡슐화 된 것보다 더 많이 노출된다는 주장과는 별개입니다.
CB Bailey

1
리팩토링 작업은 사실상 어느 쪽이든 무료이므로 실제로 구입하지는 않습니다. 또한 절대적으로 필요하지 않는 한 세터 또는 게터를 사용하는 것은 매우 나쁜 형태입니다. 결국 개념을 이해하지 못하는 사람들에게 필요할 때 대신 자동으로 세터와 게터를 추가하는 것만으로 씨앗을 흘리는 것입니다. 코드베이스 전체에 악이 있습니다.
Bill K

5

게터와 세터를 사용하면 특정 변수에 어떤 내용이 저장되는지 제어 할 수 있습니다. 컨텐츠가 특정 유형 또는 값이어야하는 경우 세터 코드의 일부는 새 값이 이러한 요구 사항을 충족하는지 확인하는 것입니다. 변수가 공용이면 이러한 요구 사항을 충족시킬 수 없습니다.

이 접근 방식은 또한 코드를보다 융통성 있고 관리하기 쉽게 만듭니다. 해당 아키텍처를 해당 클래스를 사용하는 다른 모든 클래스 또는 함수에서 숨겨두는 함수가있는 경우 클래스 아키텍처를 훨씬 쉽게 변경할 수 있습니다. 이미 언급 된 변수 이름 변경은 getter 및 setter와 같은 함수가있는 경우 훨씬 쉽게 수행 할 수있는 많은 변경 중 하나 일뿐입니다. 전반적인 아이디어는 가능한 한 많은 개인, 특히 클래스 변수를 유지하는 것입니다.


고마워요! 나는 당신이 언급 한 것과 같은 사건을 생각하고있었습니다. 변수가 [0,1]의 내용이 되려면 setter에서 들어오는 값을 확인해야합니다. :)
Oni

프로젝트에서 작업하는 유일한 개발자는 이와 같은 일이 쓸모 없다고 생각하기 쉽지만 팀과 함께 일할 때 이와 같은 기술 습관이 있으면 매우 편리하고 도움이 될 것입니다. 길 아래로 많은 버그를 피하십시오.
케네스

C #을 사용하는 경우 속성을 사용하면 속성의 setter 부분에있는 일부 논리에 따라 필요한 경우 속성을 사용하여 프라이빗 인스턴스를 설정할 수 있습니다.
developerdoug

2

"게터와 세터를 사용해야한다고 생각하는 유일한 경우는 세트 나 get 이외의 작업을 수행해야하는 경우입니다."

당신은 미래의 어떤 시점에서 경우 getter 및 setter를 사용해야 수있는 설정 외에 어떤 작업을하고 얻을 필요하고 그렇게되면 소스 코드 라인의 수천을 변경하지 않습니다.

누군가가 변수의 주소를 가져 와서 전달하지 못하게하려면 getter와 setter를 사용해야합니다. 소스 코드를 언급하지 않고 변수가 변경되거나 객체가 더 이상 존재하지 않는 경우에도 변수를 변경할 수있는 경우 비참한 결과가 발생합니다 .


마지막 문단은 두 가지 방법을 모두 줄이는 훌륭한 지적입니다. 게터와 세터를 사용해야한다면 다른 코드가 무언가의 주소를 취하지 못하게됩니다. 외부 코드가 문제를 해결하는 데 큰 이점이 있고 단점이 거의없는 경우 그러한 제한은 나쁜 것일 수 있습니다. 그러한 행동을 허용하는 데 이익이 적고 심각한 단점이 있다면 제한하는 것이 좋습니다.
supercat

1

우선 패러다임을 명확하게합니다.

  • 데이터 구조-> 적절한 지식을 갖춘 기능으로 순회 및 조작 할 수있는 메모리 레이아웃.
  • Objects-> 구현을 숨기고 통신 할 수있는 인터페이스를 제공하는 독립형 모듈.

게터 / 세터는 어디에 유용합니까?

게터 / 세터는 데이터 구조에 유용합니까? 아니.

데이터 구조는 일련의 기능에 공통적이고 조작되는 메모리 레이아웃 사양입니다.

일반적으로 기존의 새로운 기능은 다른 기능이 여전히 이해할 수있는 방식으로 데이터 구조를 처리하고 조작 할 수 있으며이 기능은 패밀리에 합류합니다. 그렇지 않으면 악성 기능과 버그의 원인이됩니다.

잘못 이해하지 마십시오. 어디서나 스 니치, 턴 코트 및 이중 에이전트가있는 데이터 구조를 다루는 여러 기능 군이있을 수 있습니다. 각자 고유의 데이터 구조를 가지고 있으면 좋지만, 공유 할 때 ... 정치에 대해 동의하지 않는 여러 범죄 가족을 상상하면 정말 혼란스러워 질 수 있습니다.

확장 기능 패밀리가 달성 할 수있는 혼란을 감안할 때, 데이터 구조를 인코딩하여 불량 함수가 모든 것을 망칠 수있는 방법이 있습니까? 예, 그것들은 객체라고 불립니다.

게터 / 세터는 객체에 유용합니까? 아니.

데이터 구조를 객체로 감싸는 요점은 악성 함수가 존재하지 않도록하는 것입니다. 그 기능이 가족과 합류하기를 원했다면, 먼저 철저히 조사한 다음 물체의 일부가되어야했습니다.

게터와 세터의 요점 / 목적은 객체 외부의 함수가 객체의 메모리 레이아웃을 직접 변경할 수 있도록하는 것입니다. 그것은 도적을 허용하는 열린 문처럼 들립니다 ...

가장자리 케이스

공개 게터 / 세터가 의미가있는 두 가지 상황이 있습니다.

  • 개체 내 데이터 구조의 일부는 개체에 의해 관리되지만 개체에 의해 제어되지는 않습니다.
  • 일부 요소가 구현 객체를 제어하지 않을 것으로 예상되는 데이터 구조의 고급 추상화를 설명하는 인터페이스입니다.

컨테이너와 컨테이너 인터페이스는이 두 상황의 완벽한 예입니다. 컨테이너는 내부적으로 데이터 구조 (linked-list, map, tree)를 관리하지만 특정 요소를 모두 수동으로 제어합니다. 인터페이스는 이것을 추상화하고 구현을 완전히 무시하고 기대치를 설명합니다.

불행히도 많은 구현들이 이것을 잘못 알고 실제 객체에 직접 접근 할 수 있도록 이러한 종류의 객체의 인터페이스를 정의합니다. 다음과 같은 것 :

interface Container<T>
{
    typedef ...T... TRef; //<somehow make TRef to be a reference or pointer to the memory location of T
    TRef item(int index); 
}

이 고장입니다. 컨테이너의 구현은 내부의 컨트롤을 사용하는 사람에게 내부 컨트롤을 명시 적으로 전달해야합니다. 나는 이것이 괜찮은 가변 값 언어를 아직 보지 못했다.

복사 의미 만 사용하거나 프록시를 사용하여 getter / setter를 개선 / 수정할 수 있습니다.

interface Proxy<T>
{
     operator T(); //<returns a copy
     ... operator ->(); //<permits a function call to be forwarded to an element
     Proxy<T> operator=(T); //< permits the specific element to be replaced/assigned by another T.
}

interface Container<T>
{
     Proxy<T> item(int index);
     T item(int index); //<When T is a copy of the original value.
     void item(int index, T new_value); //<where new_value is used to replace the old value
}

논란의 여지가있는 기능은 여전히 ​​많은 노력을 기울여도 여전히 위력을 발휘할 수 있지만, 카피 시맨틱 및 / 또는 프록시는 많은 오류 가능성을 줄입니다.

  • 과다
  • 언더 플로
  • 하위 요소와의 상호 작용은 형식 확인 / 유형 확인 가능 (언어를 잃어 버리면 이것이 좋습니다)
  • 실제 요소는 메모리 상주이거나 아닐 수 있습니다.

개인 게터 / 세터

이것은 유형에 대해 직접 작업하는 게터와 세터의 마지막 요새입니다. 사실 나는 이러한 게터와 세터뿐만 아니라 접근 자와 조작자를 부르기도합니다.

이러한 맥락에서 때때로 데이터 구조의 특정 부분을 조작하려면 항상 / 거의 항상 / 일반적으로 특정 장부 유지가 필요합니다. 트리의 루트를 업데이트 할 때 look-aside 캐시를 제거해야하거나 외부 데이터 요소에 액세스 할 때 잠금을 얻거나 해제해야한다고 가정하십시오. 이 경우 DRY 교장을 적용하고 해당 조치를 함께 소포하는 것이 좋습니다.

사적인 맥락에서, 가족의 다른 기능들이 이러한 '게터와 세터'를 회피하고 데이터 구조를 조작하는 것이 여전히 가능하다. 따라서 왜 그것들을 접근 자와 조작자로 생각합니다. 데이터에 직접 액세스하거나 다른 가족 구성원에게 의존하여 해당 부분을 얻을 수 있습니다.

보호 된 게터 / 세터

보호 된 컨텍스트에서 공개 컨텍스트와 크게 다르지 않습니다. 외부의 불량 함수는 데이터 구조에 액세스하려고합니다. 따라서 존재하지 않는 경우 공용 게터 / 세터처럼 작동합니다.


0

C ++ 경험에서 setter / getter는 두 가지 시나리오에 유용합니다.

  1. 문자열이나 배열과 같이 멤버에 값을 할당하기 전에 무결성 검사를 수행해야하는 경우
  2. -1 (또는 음수 값)이 false 일 때 할당을 bool하기 위해 int 값과 같이 함수 과부하가 필요할 때 도움이 될 수 있습니다. getter의 경우도 마찬가지입니다.

그 외에도 보안은 유효하지만 로그인 또는 db 액세스 관련 모듈과 같은 개발 응용 프로그램은 매우 중요하지 않습니다. 소수의 사용자 만 모듈을 사용할 때 추가 코딩이 필요하지 않은 이유는 무엇입니까?

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