게터와 세터 / 액세서를 사용하는 이유는 무엇입니까?


1541

변수에 공용 필드를 사용하는 대신 getter 및 setter를 사용하면 얻을 수있는 장점은 무엇입니까?

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

public String foo;

다음보다 더 나쁘다 :

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

전자는 상용구 코드가 훨씬 적습니다.


6
@Dean J : 다른 많은 질문들과 중복 : stackoverflow.com/search?q=getters+setters
Asaph

8
물론 객체가 속성을 변경할 필요가 없을 때 둘 다 똑같이 나쁩니다. 오히려 모든 것을 비공개로 만들고 유용한 경우 getter를 추가하고 필요한 경우 setter를 추가하고 싶습니다.
Tordek

26
구글 "접근자는 악하다"
OMG Ponies

34
기능 코드 또는 변경 불가능한 객체를 작성하는 경우 "액세서리는 악합니다". 상태 저장 가변 객체를 작성하는 경우 매우 중요합니다.
Christian Hayter

답변:


980

실제로이 있습니다 많은 좋은 이유 접근을 사용하는 것을 고려하는 캡슐화 단지 인수를 넘어 미래를 쉽게 변경하기 -보다는 직접 클래스의 필드를 노출은.

내가 알고있는 몇 가지 이유는 다음과 같습니다.

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

59
+1. 추가하기 : 지연 로딩 허용. 쓰기시 복사 허용
NewbiZ

6
@ bjarkef : public접근 자 메서드가 코드 복제를 유발하고 정보를 노출 한다고 생각 합니다. 마샬링 (직렬화)에는 공개 접근자가 필요하지 않습니다. 일부 언어 (Java)에서 publicget 접근자는 종속 클래스를 중단하지 않고 리턴 유형을 변경할 수 없습니다. 또한 나는 그들이 OO 원칙에 반하는 것을 믿는다. 또한보십시오 : stackoverflow.com/a/1462424/59087
Dave Jarvis

15
@ sbi : 잘 설계된 프레임 워크에서도 속성 설정기를 사용하여 구입하는 한 가지는 속성이 변경 될 때 객체가 다른 객체에게 알리는 기능입니다.
supercat

22
@supercat : 그러나 저는 일반적으로 공개 데이터를 홍보하지 않습니다. 공개 데이터 필드가 많거나 적은 단순한 데이터 컨테이너에서 중요한 추상화를 제공하는 실제 메소드를 통해 다른 객체에 대한 알림을 수행 할 수도 있습니다. 대신 plane.turnTo(dir); plane.setSpeed(spd); plane.setTargetAltitude(alt); plane.getBreaks().release();말하고 싶습니다 plane.takeOff(alt). 비행기를 takingOff모드 로 전환 하기 위해 내부 데이터 필드를 변경 해야하는 것은 내 걱정이 아닙니다. 그리고 다른 객체 ( breaks) 메소드는 내가 알고 싶지 않다는 것을 알려줍니다.
sbi

8
@ BenLee : 나는 그것을 말할 다른 방법을 정말로 모른다. "접근 자"는 "getters / setters"의 동의어 일 뿐이며, 처음 두 의견에서는 왜 "OOP"라는 용어를 남용하는지 설명했습니다. 그것에 도달하고 상태를 직접 조작 해야하는 경우 해당 용어의 OOP 의미의 객체가 아닙니다.
sbi

480

지금부터 2 주 (월, 년) 동안 세터가 단순히 값을 설정하는 것보다 더 많은 일을해야한다는 것을 깨달았 기 때문에이 속성이 238 개의 다른 클래스에서 직접 사용되었다는 것을 알게 될 것입니다. :-)


84
나는 결코 필요하지 않은 500k 라인 앱을보고 쳐다보고있다. 즉, 한 번 필요하면 유지 관리의 악몽을 일으키기 시작합니다. 확인 표시로 충분합니다.
Dean J

20
나는 당신과 당신의 응용 프로그램을 부러워 할 수 있습니다 :-) 즉, 그것은 실제로 소프트웨어 스택에 달려 있습니다. 예를 들어 델파이는 (그리고 C #-내 생각에?) 속성을 1 등석 시민으로 정의하여 처음에 직접 필드를 읽거나 쓸 수 있지만 필요한 경우 getter / setter 메소드를 통해 그렇게 할 수 있습니다. 점액이 편리합니다. Java는 아아, getters / setter를 사용해야하는 javabeans 표준은 말할 것도 없습니다.
ChssPly76

14
이것이 실제로 접근자를 사용하는 좋은 이유이지만, 많은 프로그래밍 환경과 편집기는 이제 문제의 영향을 다소 줄여주는 리팩토링 (IDE 또는 무료 애드 인)을 지원합니다.
LBushkin

62
같은 소리 최적화 사전은 - 성숙
cmcginty

41
게터와 세터를 구현할지 궁금 할 때 물어봐야 할 질문은 다음과 같습니다. 왜 클래스 사용자가 클래스의 내부에 액세스해야합니까? 사용자가 구현 세부 사항에 액세스해야하는 경우 클래스가 추상화를 충분히 제공하지 못한다는 신호입니다. 이 주석 도 참조하십시오 .
sbi

357

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

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

따라서 계약을 파기 했으므로 코드베이스의 모든 파일을 변경하는 것은 피해야 할 일입니다. 피하지 않으면 모든 코드가 해당 메소드의 계약이 다르다고 가정합니다.

이것이 계약이 아니어야한다면, 인터페이스는 클라이언트가 객체를 유효하지 않은 상태로 놓을 수 있도록 허용 한 것입니다. 이것이 캡슐화의 정반대입니다. 해당 필드를 처음부터 아무것도 설정할 수 없다면 왜 처음부터 검증이 이루어지지 않았습니까?

이와 같은 주장은 이러한 통과 게터 / 세터 쌍의 다른 가정 된 장점에도 적용됩니다. 나중에 설정중인 값을 변경하기로 결정하면 계약을 위반하게됩니다. 파생 클래스에서 기본 기능을 재정의하면 몇 가지 무해한 수정 (예 : 로깅 또는 기타 관찰 할 수없는 동작)을 넘어 서면 기본 클래스의 계약을 위반하게됩니다. 이는 OO의 신조 중 하나로 여겨지는 Liskov Substitutability Principle을 위반하는 것입니다.

클래스에 모든 필드에 대해 이러한 벙어리 게터와 세터가있는 경우, 불변성이 없고 계약 이없는 클래스입니다 . 이것이 실제로 객체 지향 디자인입니까? 모든 클래스에 게터와 세터가 있다면 바보 데이터 홀더 일뿐이며 바보 데이터 홀더는 바보 데이터 홀더처럼 보일 것입니다.

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

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

클라이언트 : "이 클래스의 객체로 무엇을 할 수 있습니까?"
디자이너 : "여러 변수를 읽고 쓸 수 있습니다."
클라이언트 : "아 ... 근사한 것 같아?"

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


12
훌륭한 답변 (+1). 나의 유일한 비판은 마지막 문단의 "유효성 검증"이 첫 번째 소수의 "유효성 검증"과 어떻게 다른지 알아내는 데 몇 가지 읽기가 필요하다는 것입니다. 문구를 조정하면 그 점에서 도움이 될 수 있습니다.
궤도에서 가벼움 레이스

14
이것은 훌륭한 해답이지만 현재 시대가 "정보 숨기기"가 무엇인지 또는 무엇을 잊었는지 잊어 버렸습니다. 그들은 결코 불변성에 대해 읽지 않고 가장 민첩한 것을 추구하면서, 물체의 법적 상태가 무엇이고 그렇지 않은지를 정의한 상태 전이도를 그리지 않았습니다.
Darrell Teague

2
주요 관찰 사항은 게터가 세터보다 훨씬 유용하다는 것입니다. 게터는 계산 된 값 또는 캐시 된 계산 된 값을 반환 할 수 있습니다. 세터가 할 수있는 모든 것은 약간의 유효성 검사이며 private필드를 변경하는 것 입니다. 클래스에 세터가 없으면 변경하기가 쉽습니다.
Raedwald

7
어, 나는 당신이 클래스 불변 인이 무엇인지 모른다고 생각합니다. 그것이 사소하지 않은 구조라면, 그것은 유지해야 할 변이가 거의 없으며, 염두에 두지 않고서는 설계 할 수 없다는 것을 의미합니다. "버그가있었습니다. 한 멤버가 잘못 업데이트되었습니다." 또한 "멤버 업데이트가 클래스 불변을 위반했습니다"와 같이 읽습니다. 잘 설계된 클래스는 클라이언트 코드가 그 불변을 위반하는 것을 허용하지 않습니다.
R. Martinho Fernandes

5
'멍청한 데이터 보유자가 바보 같은 데이터 보유자처럼 보일 것'에 +1 불행히도, 요즘 모든 사람들은 바보 같은 데이터 보유자 주위의 모든 것을 디자인하는 것 같고 많은 프레임 워크가 그것을 필요로합니다 ...
Joeri Hendrickx

92

많은 사람들이 게터와 세터의 장점에 대해 이야기하지만 저는 악마의 옹호자를하고 싶습니다. 지금은 프로그래머가 모든 게터와 세터를 만들기로 결정한 매우 큰 프로그램을 디버깅하고 있습니다. 멋지게 보일지 모르지만 리버스 엔지니어링의 악몽입니다.

수백 줄의 코드를 살펴보고 다음과 같은 내용을 접한다고 가정 해보십시오.

person.name = "Joe";

세터를 깨닫기 전까지는 아주 간단하게 코드입니다. 이제 해당 세터를 따라 person.firstName, person.lastName, person.isHuman, person.hasReallyCommonFirstName을 설정하고 person.update ()를 호출하여 데이터베이스로 쿼리를 보내는 등을 찾습니다. 메모리 누수가 발생한 위치

로컬 코드를 한눈에 이해하는 것은 게터와 세터가 깨지기 쉬운 가독성의 중요한 속성입니다. 그렇기 때문에 가능한 한 피하는 것을 피하고 사용하면하는 일을 최소화하려고합니다.


8
예. 현재 큰 코드베이스를 리팩토링하는 것은 악몽이었습니다. 게터와 세터는 가독성이 떨어지는 다른 매우 바쁜 게터와 세터를 호출하는 것을 포함하여 너무 많은 일을합니다. 유효성 검사는 접근자를 사용하는 큰 이유이지만, 그 이상의 기능을 사용하여 잠재적 인 이점을 제거하는 것 같습니다.
Fadecomic

31
이것은 일반적으로 세터에 대한 것이 아니라 구문 설탕에 대한 논쟁입니다.
Phil

6
더욱이 사실이지만, 개별 속성 설정자가 왜 추상화가 누출 될 수있는 주어진 객체의 무결성을 보장하기위한 해결책없이 절대적으로 무효 상태에 대한 문을 여는 이유를 지적합니다.
Darrell Teague

"이것은 세터를 깨달을 때까지 아름답고 단순한 코드입니다."-Java 또는 C #에 대한 원래 게시물입니까? :)
Honza Zidek

나는 가독성에 관해 전적으로 동의합니다. person.name = "Joe";호출 될 때 무슨 일이 일어나고 있는지는 명백합니다 . 정보 방식에는 문제가 없으며 구문 강조 표시는 필드임을 나타내며 리팩토링이 더 간단합니다 (두 가지 방법과 필드를 리팩토링 할 필요가 없음). 둘째, "getIsValid ()"라고 생각하거나 "isValid ()"여야한다고 생각하는 모든 두뇌주기를 잊어 버릴 수 있습니다. 나는 게터 / 세터에 의해 버그에서 구원받은 시간을 생각할 수 없다.

53

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

Elegant Objects의 3.5 절 (객체 지향 프로그래밍에 관한 저서) 에서 더 많은 것을 찾을 수 있습니다 .


7
게터와 세터는 빈혈 도메인 모델을 제안합니다.
Raedwald

7
재미있는 관점. 그러나 대부분의 프로그래밍 환경에서 필요한 것은 데이터 구조입니다. 링크 된 기사의 "개"예제를 보자. 예, 속성을 설정하여 실제 개 체중을 변경할 수 new Dog()는 없지만 a는 개가 아닙니다. 개에 관한 정보를 담고있는 물건입니다. 그리고 그 사용을 위해, 잘못 기록 된 무게를 교정하는 것이 당연합니다.
Stephen C

3
글쎄, 난 것을 당신에게 넣어 가장 유용한 프로그램 모델 / 시뮬레이션 실제 개체를 필요가 없습니다. IMO, 이것은 실제로 프로그래밍 언어에 관한 것이 아닙니다. 우리가 프로그램을 작성하는 것에 관한 것입니다.
Stephen C

3
현실 세계이든 아니든, 예 고르는 완전히 옳습니다. 당신이 가진 것이 진정으로 "Struct"이고 이름으로 참조하는 코드를 작성할 필요가 없다면, 해시 테이블이나 다른 데이터 구조에 넣으십시오. 코드를 작성 해야하는 경우 클래스의 멤버로 넣고 해당 변수를 조작하는 코드를 동일한 클래스에 넣고 세터 및 getter를 생략하십시오. 추신. 나는 대부분 예고 르의 견해를 공유하지만 코드가없는 주석이 달린 빈은 다소 유용한 데이터 구조라고 생각합니다.
Bill K

1
이 답변은 정확하고 관련성이 있지만 질문을 직접 해결하지는 못합니다. 아마도 "세터 / 게터와 퍼블릭 변수가 잘못되었습니다"라고 말해야합니다 ... 절대적으로 구체적으로, 세터와 쓰기 가능 퍼블릭 변수는 절대 사용해서는 안되지만 게터는 퍼블릭 최종 변수와 거의 동일하며 때로는 필요한 악입니다. 그러나 어느 쪽도 다른 쪽보다 훨씬 낫습니다.
Bill K

52

여러 가지 이유가 있습니다. 내가 가장 좋아하는 것은 동작을 변경하거나 변수에 설정할 수있는 것을 조절해야 할 때입니다. 예를 들어 setSpeed ​​(int speed) 메서드가 있다고 가정 해 봅시다. 그러나 최대 속도 100 만 설정할 수 있기를 원합니다.

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

이제 코드의 어디에나 퍼블릭 필드를 사용하고 있고 위의 요구 사항이 필요하다는 것을 깨달았다면 어떻게해야합니까? 세터를 수정하는 대신 퍼블릭 필드의 모든 사용법을 재미있게 찾아보십시오.

내 2 센트 :)


61
퍼블릭 필드의 모든 사용법을 찾아내는 것이 그렇게 어려운 것은 아닙니다. 비공개로 만들고 컴파일러가 찾도록하십시오.
Nathan Fellman

12
그것은 물론 사실이지만, 왜 그것을 설계된 것보다 더 어렵게 만드는가? get / set 접근 방식이 여전히 더 나은 대답입니다.
Hardryv

28
@Nathan : 다른 사용법을 찾는 것은 문제가되지 않습니다. 그것들을 모두 바꾸는 것입니다.
Graeme Perrow

22
@GraemePerrow는 모두 변경해야한다는 것이 문제가 아니라 이점입니다. (속도를 100으로 초과한다고 가정 한 코드가 있다면 계약을 파기하기 전에 속도를 높일 수 있습니다!) ( while(speed < 200) { do_something(); accelerate(); })
R. Martinho Fernandes

29
매우 나쁜 예입니다! 누군가가 전화를해야합니다 : myCar.setSpeed(157);몇 줄만 지나면 speed = myCar.getSpeed();지금 ... 왜 speed==100그럴 수 있는지 이해하려고 노력하면서 행복하게 디버깅하기를 바랍니다 .157
Piotr Aleksander Chmielowski

38

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

예를 들어 foo공개 된 경우 쉽게 설정하고 null다른 사람이 객체에서 메소드를 호출하려고 시도 할 수 있습니다. 그러나 더 이상 존재하지 않습니다! setFoo방법을 사용하면 foo결코 설정되지 않았습니다 null.

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


28

언어에 따라 다릅니다. "Java"가 아닌 "object-oriented"에 태그를 달았으므로 ChssPly76의 답변은 언어에 따라 다릅니다. 예를 들어 파이썬에서는 게터와 세터를 사용할 이유가 없습니다. 동작을 변경해야하는 경우 기본 속성 액세스를 통해 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)

2
예, 내 답변 아래의 의견에서 많이 말했습니다. 파이썬과 마찬가지로 getters / setter를 목발로 사용하는 언어는 Java 뿐이 아닙니다. Python은 속성을 정의 할 수있는 유일한 언어가 아닙니다. 그러나 요점은 여전히 ​​남아 있습니다. "재산"은 동일한 "공공 분야"가 아닙니다.
ChssPly76

1
@jcd-전혀 아닙니다. 공개 필드를 공개하여 "인터페이스"(공개 API가 더 나은 용어 임)를 정의하고 있습니다. 일단 완료되면 다시는 갈 수 없습니다. 속성은 필드에 액세스하려는 시도를 가로 채기위한 메커니즘을 제공하기 때문에 필드가 아닙니다 (정의 된 경우 메소드에 라우팅). 그러나 getter / setter 메소드에 대한 구문 설탕에 지나지 않습니다. 매우 편리하지만 기본 패러다임을 변경하지는 않습니다. 필드에 대한 액세스를 제어 할 수없는 필드를 노출하면 캡슐화 원칙을 위반합니다.
ChssPly76

14
@ ChssPly76 – 동의하지 않습니다. 필요할 때마다 속성을 만들 수 있기 때문에 속성처럼 속성을 많이 제어 할 수 있습니다. 상용구 게터와 세터를 사용하는 속성과 메서드를 호출하는 대신 기본 언어를 사용하므로 원시 속성이 더 빠르다는 점을 제외하고는 원시 속성간에 차이가 없습니다. 기능적으로는 동일합니다. 캡슐화를 위반할 수있는 유일한 방법은 괄호 ( obj.set_attr('foo'))가 본질적으로 등호 ( obj.attr = 'foo') 보다 우수 하다고 생각하는 것 입니다. 공개 액세스는 공개 액세스입니다.
jcdyer

1
@jcdyer 많은 제어 예,하지만 많은 가독성, 다른 사람들은 종종 obj.attr = 'foo'아무 일도 일어나지 않고 변수를 설정 한다고 잘못 가정합니다.
Timo Huovinen

9
@TimoHuovinen obj.setAttr('foo')"다른 일이 발생하지 않고 변수를 설정" 한다고 가정하면 Java 사용자와 다른 점은 무엇입니까? 공용 메소드 인 경우 공용 메소드입니다. 당신이 어떤 부작용을 달성하기 위해 그것을 사용하고 공개하는 경우, 당신은 더 나은 작업 모두에 의지 할 수 있었다 위한 부작용이 일어난 것만처럼 함께 ( 모든 다른 구현 세부 사항 및 기타 부작용, 자원 사용 어떤 , 사용자의 우려에서 숨겨 짐). 이것은 파이썬과 전혀 다르지 않습니다. 효과를 달성하는 파이썬의 구문은 더 간단합니다.
ely

25

글쎄, 때로는 변수 / 객체의 캡슐화 및 보안에 필요한 경우에도 실제 객체 지향 프로그램을 코딩하려는 경우 액세서리 오버 스톱중지 해야하며 때로는 우리가 많이 의존해야합니다. 실제로 필요하지 않을 때 변수를 공개하는 것과 거의 동일합니다.


24

고마워, 정말 내 생각을 명확히했다. 이제 getter와 setter를 사용하지 말아야 할 10 가지 이유가 있습니다.

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

내가 마지막으로 떠나는 마지막 3 명 (N / A 또는 D / C) ...


11
나는 중요한 인자가 생각 "당신이 인터페이스를 설계 할 뭔가에 직접 액세스 확인했다 있는지 여부, 당신은 디자인을 유지해야되지 않은 경우." 게터 / 세터에서 가장 중요한 문제는 클래스를 단순한 (공개) 공용 필드 컨테이너로 줄이는 것입니다. 그러나 실제 OOP에서 개체는 데이터 필드 컨테이너 이상입니다. 상태 및 알고리즘을 캡슐화하여 해당 상태를 조작합니다. 이 문장에서 중요한 것은 상태가 캡슐화 되고 객체가 제공하는 알고리즘에 의해서만 조작되어야한다는 것입니다.
sbi

22

약간 늦었지만 성능에 관심이있는 사람들이 있다고 생각합니다.

약간의 성능 테스트를 수행했습니다. 나는 정수를 보유하고있는 "NumberHolder"클래스를 작성했다. getter 메소드를 사용하거나을 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는 게터입니다)

알다시피, 게터는 (거의) 항상 조금 더 빠릅니다. 그런 다음 다른 횟수의 사이클로 시도했습니다. 1 백만 대신 1 천만 및 0.1 백만을 사용했습니다. 결과 :

천만 사이클 :

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

천만 사이클로 시간은 거의 동일합니다. 10 만 사이클은 다음과 같습니다.

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

또한 다른 사이클 양으로 인해 게터는 일반적인 방식보다 약간 빠릅니다. 이것이 도움이 되었기를 바랍니다.


3
단순히 객체의 주소를로드하고 멤버에 액세스하기위한 오프셋을 추가하는 대신 메모리에 액세스하기위한 함수 호출이있는 "감추기 쉬운"오버 헤드가 있습니다. 어쨌든 VM은 getter를 평평하게 최적화합니다. 어쨌든 언급 된 오버 헤드는 게터 / 세터의 모든 이점을 잃을 가치가 없습니다.
Alex

16

현재 제공에 필요한 경우가 아니면 getters setter를 사용하지 마십시오. 즉, 대부분의 프로덕션 응용 프로그램, 시스템에서 변경 요청이 변경 될 경우 향후 어떤 일이 발생할 지에 대해 너무 많이 생각하지 마십시오.

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

나는 심도 깊은 기술 소유자의 무지를 활용하지 않을 것입니다. 그것이 옳다고 생각하거나 접근 방식을 좋아한다는 이유 만 알고 있습니다.

액세스 수정 자 및 n 비즈 로직을 검증하는 몇 가지 방법으로 만 getters setter없이 작성된 대규모 시스템이 있습니다. 당신이 절대적으로 필요한 경우. 무엇이든 사용하십시오.


16

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

  • 재사용 성
  • 프로그래밍의 후기 단계에서 검증을 수행

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


캡슐화 만트라

캡슐화 만트라는 필드를 개인용 및 메소드를 공용으로 만드는 것입니다.

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

세터 메소드 : 개인 필드를 수정할 수 있습니다.

getter 및 setter 메소드가 새로운 기능을 추가하지 않더라도 나중에 다시 해당 메소드를 작성하도록 마음을 바꿀 수 있습니다.

  • 보다 나은;
  • 더 안전한; 과
  • 빨리.

값을 사용할 수있는 곳이면 해당 값을 반환하는 메소드를 추가 할 수 있습니다. 대신에:

int x = 1000 - 500

사용하다

int x = 1000 - class_name.getValue();

평신도의 관점에서

"사람"클래스의 표현

이것의 세부 사항을 저장해야한다고 가정하자 Person. 이 Person필드를 가지고 name, age하고 sex. 이를 위해서는 name, age및에 대한 메소드를 작성해야합니다 sex. 우리가 다른 사람을 만들 필요하다면 지금, 그것은을위한 방법을 만들 필요가 name, age, sex다시 한번를.

이를 수행하는 대신 class(Person)getter 및 setter 메소드를 사용하여 Bean 을 작성할 수 있습니다 . 따라서 내일 우리는 class(Person class)새로운 사람을 추가해야 할 때마다이 Bean의 객체를 만들 수 있습니다 (그림 참조). 따라서 빈 클래스의 필드와 메소드를 재사용하는 것이 훨씬 좋습니다.


15

Java 케이스에 대해 이것을 생각하는 데 꽤 오랜 시간을 보냈으며 실제 이유는 다음과 같습니다.

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

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

그 방법은 악명 높은 게터와 세터입니다 ....


1
두 번째 질문입니다. 누군가에게 소스를 내 보내지 않는 프로젝트이고 소스를 완전히 제어 할 수있는 경우 ... 게터와 세터로 무언가를 얻고 있습니까?
Dean J

2
사소한 Java 프로젝트에서는 관리 할 수 ​​있고 테스트 할 수 있도록 인터페이스에 코드를 작성해야합니다 (mockup 및 proxy 객체를 생각하십시오). 인터페이스를 사용하는 경우 게터와 세터가 필요합니다.
Thorbjørn Ravn Andersen

15

지연 로딩에 유용 할 수 있습니다. 문제의 객체가 데이터베이스에 저장되어 있으며 필요하지 않으면 가져 가기를 원하지 않습니다. getter가 객체를 검색하면 누군가가 요청할 때까지 내부 객체가 null 일 수 있습니다. 그러면 getter를 처음 호출 할 때 객체를 가져올 수 있습니다.

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

공용 필드에서 게터로 이동했으며 이제 게터가 캐시를 확인하고 웹 서비스가 없으면 캐시를 확인합니다. 작은 줄 바꿈으로 많은 웹 서비스 호출이 방지되었습니다.

따라서 getter는 각 하위 페이지에서 필요한 내용을 파악하지 않아도됩니다. 필요한 경우 getter를 호출하고 아직없는 경우이를 찾으러갑니다.

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

그러면 getter가 setter를 호출합니까?
icc97

필자는 과거에 어떻게했는지에 대한 코드 샘플을 추가했습니다. 본질적으로 실제 클래스를 보호 멤버에 저장 한 다음 get 접근 자에서 해당 보호 멤버를 반환하여 초기화되지 않은 경우 초기화합니다.
quillbreaker


13

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

  • 회원의 경우 설정 및 가져 오기에 대한 하나의 액세스 사양 만 있습니다
  • 세터와 게터의 경우 세밀하게 조정하고 별도로 정의 할 수 있습니다.

13

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

두 가지 주요한 것은 다형성과 검증입니다. 바보 같은 데이터 구조 일지라도.

이 간단한 클래스가 있다고 가정 해 봅시다.

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

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

내가 할 때 어떻게됩니까?

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

글쎄, 당신은 그 일을 기대하지 않을 것입니다. 당신은 어떤 종류의 위생 검사를 원합니다. 그리고 더 이상 최대 용량을 지정하지 않으면 어떻게됩니까? 오, 문제가 있습니다.

그러나 또 다른 문제가 있습니다. 병이 단지 한 유형의 용기라면? 용량과 액체가 채워진 용기가 여러 개인 경우 어떻게해야합니까? 인터페이스를 만들 수 있다면 나머지 프로그램에서 해당 인터페이스를 받아 들일 수 있으며 병, jerrycans 및 모든 종류의 것들이 상호 교환 적으로 작동합니다. 더 나아지지 않을까요? 인터페이스는 메소드를 요구하기 때문에 이것도 좋습니다.

우리는 다음과 같은 결과를 얻었습니다.

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

큰! 이제 병을 다음과 같이 변경합니다.

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에 저장된 병이 다른 것을 알고있을 수 있습니다.

그리고이 모든 것들은 다양한 솜씨를 다루는 다른 방법을 가질 수 있습니다. 병은 방금 확인하고 넘치면 RuntimeException을 발생시킵니다. 그러나 그것은 잘못된 일일 수 있습니다. (오류 처리에 관한 유용한 토론이 있지만 여기서는 매우 간단하게 설명하고 있습니다. 의견을 가진 사람들은이 단순한 접근 방식의 결함을 지적 할 것입니다.;))

그리고 그렇습니다. 우리는 매우 간단한 아이디어에서 훨씬 더 나은 답변을 빨리 얻는 것처럼 보입니다.

병의 용량은 변경할 수 없습니다. 이제 돌로 설정되었습니다. 최종 선언하여 int 로이 작업을 수행 할 수 있습니다. 그러나 이것이 목록 인 경우 목록을 비우고 새 항목을 추가하는 등의 작업을 수행 할 수 있습니다. 내부를 만지는 것에 대한 액세스를 제한 할 수 없습니다.

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


2
내가 읽은 인터페이스에 대한 첫 반 정도의 설명에 감사드립니다. "원격 컨트롤"또는 "자동차"에 대한 언급
djvs

1
"변경 될 때 디스크에 상태를 기록하는 병이나 SQL 데이터베이스에 저장하는 병을 가질 수 있습니다."저는 매우 어려운 xD를 발표했습니다. 어쨌든, 그것을 제시하는 좋은 아이디어!
Xerus

10

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

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


1
다시 : C #. get / set에 기능을 추가하면 어쨌든 재 컴파일이 필요하지 않습니까?
steamer25

@ steamer25 : 죄송합니다, 잘못 입력했습니다. 클래스의 클라이언트를 다시 컴파일해야 함을 의미했습니다.
John Millikin

5
setFoo를 사용해, 방법에 검증 로직을 추가하면 클래스의 인터페이스를 변경 요구하지 않을 것이다 언어 수준에 있지만, 그것은 실제 인터페이스를 변경 않는다 는 전제 조건을 변경하기 때문에, 계약 일명. 왜 컴파일러가 그럴 때 그 변경을 주요 변경으로 취급하지 않기를 원합니까?
R. Martinho Fernandes

@ R.MartinhoFernandes는이 "깨진"문제를 어떻게 해결합니까? 컴파일러는 그것이 깨 졌는지 아닌지를 알 수 없습니다. 이것은 다른 사람들을 위해 라이브러리를 작성할 때만 걱정할 만하지 만 여기에서 용으로 보편적 zOMG로 만들고 있습니다!
Phil

3
답변에서 언급했듯이 재 컴파일을 요구하는 것은 컴파일러가 가능한 주요 변경 사항을 알 수있는 한 가지 방법입니다. 제가 혼자서 일하지 않기 때문에 제가 쓰는 거의 모든 것이 사실상 "다른 사람들을위한 도서관"입니다. 프로젝트의 다른 사람들이 사용할 인터페이스가있는 코드를 작성합니다. 차이점이 뭐야? 지옥, 그 인터페이스의 사용자가 되더라도 품질 표준을 낮추기 위해 왜 코드를 잡아야합니까? 인터페이스를 작성하는 사람이라하더라도 번거로운 인터페이스로 작업하는 것을 좋아하지 않습니다.
R. Martinho Fernandes

6

OO 디자인의 기본 원칙 중 하나 : 캡슐화!

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


23
캡슐화 게터와 세터는 매우 얇습니다. 여기를 참조 하십시오 .
sbi

공용 인터페이스에 'foo'가 'T'유형이고 어떤 것으로도 설정할 수 있다고 표시하면 변경할 수 없습니다. 후자를 'Y'유형으로 결정하거나 크기 제한과 같은 규칙을 강요 할 수 없습니다. 따라서 많은 설정 / 가져 오기를 수행하지 않는 공개 get / set이 있으면 공개 필드가 제공하지 않는 것을 얻지 못하고 사용하기가 더 번거로워집니다. 객체를 null로 설정하거나 값이 범위 내에 있어야하는 등의 제약 조건이있는 경우 공개 설정 방법이 필요하지만 여전히이 값을 설정하여 계약을 제시 할 수 있습니다. t 변화
thecoshman

계약을 변경할 수없는 이유는 무엇입니까?
Phil

5
계약이 변경되면 왜 계속 컴파일해야합니까?
R. Martinho Fernandes

5

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

  • 개념적으로 속성이있는 것을 다루고 있지만
    • 언어에 속성 (또는 Tcl의 변수 추적과 같은 유사한 메커니즘)이 없거나
    • 귀하의 언어 속성 지원이이 사용 사례에 충분하지 않거나
    • 귀하의 언어 (또는 경우에 따라 프레임 워크)의 관용적 관습은이 사용 사례에 대해 게터 나 세터를 권장합니다.

따라서 이것은 일반적인 OO 질문은 거의 없습니다. 다른 언어 (및 다른 유스 케이스)에 대해 다른 답변을 가진 언어 별 질문입니다.


OO 이론의 관점에서, 게터와 세터는 쓸모가 없습니다. 클래스의 인터페이스는 상태가 아니라 클래스의 인터페이스입니다. (그렇지 않은 경우, 잘못된 클래스를 작성했습니다.) 매우 간단한 경우, 클래스가하는 일이 예를 들어 직사각형 좌표로 점을 나타내는 것입니다. * 속성은 인터페이스의 일부입니다. 게터와 세터는 단지 그것을 클라우드합니다. 그러나 매우 단순한 경우를 제외하고는 속성이나 게터 및 세터가 인터페이스의 일부가 아닙니다.

다른 방법으로 설명하자면 : 클래스의 소비자가 자신이 spam속성 을 가지고 있다는 것을 알지 못한다고 생각할 경우, 속성을 변경할 수있는 능력이 훨씬 적으므로, set_spam메소드 를 제공하는 것이 마지막으로해야 할 일입니다.

* 간단한 클래스라도 xy값을 설정하지 않아도 됩니다. 이것이 실제로 클래스 translate라면 rotate, 등의 메소드가 없어야 합니까? 귀하의 언어에 레코드 / 구조체 / 명명 된 튜플이 없기 때문에 클래스 일뿐이라면 이것은 실제로 OO의 문제가 아닙니다 ...


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

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

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

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

또한 사용중인 언어 (또는 프레임 워크)의 관용구를 따르는 것이 중요합니다. C #으로 멋진 루비 스타일 코드를 작성하면 경험이없는 C # 개발자가 코드를 읽는 데 어려움을 겪을 수 있습니다. 어떤 언어는 다른 언어보다 관습에 대해 더 강한 문화를 가지고 있습니다. 관용 게터가 어떻게 다른 스펙트럼 끝에있는 Java와 Python이 가장 강한 문화 중 하나를 갖는 것은 우연이 아닙니다.

인간 독자 이외에도 규칙을 따르고 그렇지 않으면 인생을 더 힘들게 만드는 라이브러리와 도구가 있습니다. Interface Builder 위젯을 ObjC 속성 이외의 것에 연결하거나 게터없이 특정 Java mocking 라이브러리를 사용하면 인생이 더 어려워집니다. 도구가 당신에게 중요하다면, 싸우지 마십시오.


4

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


3

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

getter 및 setter 메소드를 사용하면 몇 가지 장점이 있습니다. 예를 들어, 유사한 특성에 액세스 할 수있는 정교한 기능을 가진 멤버를 작성할 수 있습니다. 또한 읽기 전용 및 쓰기 전용 속성을 만들 수 있습니다.

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

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


3

코드가 진화합니다 . 데이터 멤버 보호가 필요할private 때 유용 합니다 . 결국 모든 클래스는 내부적으로 조일 수없는 잘 정의 된 인터페이스 가진 일종의 "미니 프로그램"이어야합니다 .

즉, 소프트웨어 개발 은 첫 번째 시도에서 주철 조각상을 누르는 것처럼 클래스의 최종 버전을 설정하는 것이 아닙니다. 작업하는 동안 코드는 점토와 비슷합니다. 개발 함에 따라 발전하고 해결하려는 문제 영역에 대해 자세히 알아 봅니다. 개발 과정에서 클래스는 서로 (인식 할 계획 인 의존성), 서로 합치거나 분리되는 것보다 서로 상호 작용할 수 있습니다. 그래서 나는 토론이 종교적으로 글을 쓰고 싶지 않은 사람들에게 귀결된다고 생각합니다.

int getVar() const { return var ; }

그래서 당신은 :

doSomething( obj->getVar() ) ;

대신에

doSomething( obj->var ) ;

getVar()시각적으로 시끄러울 뿐만 아니라 gettingVar()실제보다 복잡한 프로세스라는 착각을줍니다 . 당신이 (클래스 라이터로서) 신성함을 고려하는 var방법은 패스 스루 세터가있는 경우 클래스 사용자에게 특히 혼란 스럽습니다. 그러면 당신이 주장하는 것을 "보호"하기 위해이 게이트를 세우는 것처럼 보입니다. (신성함 var) 그러나 당신 var의 보호 조차도 당신 set var이하고있는 일에 대해 엿보기조차하지 않고, 누군가 가 원하는 값으로 들어올 수있는 능력에 의해 가치가있는 것은 아닙니다 .

따라서 다음과 같이 프로그래밍합니다 ( "민첩한"형식 접근을 가정합니다. 즉, 정확히 어떤 폭포 스타일 인터페이스 세트를 계획 할 시간이나 경험이 없는지 정확히 없는 코드를 작성할 때 ) :

1) 데이터와 행동으로 기본 개체에 대한 모든 공개 멤버로 시작하십시오. 이것이 모든 C ++ "example"코드 struct에서 class어디에서나 대신 사용 하는 것을 알 수있는 이유입니다 .

2) 데이터 멤버에 대한 객체의 내부 동작이 충분히 복잡해지면 (예를 들어, 내부 std::list를 어떤 종류의 순서 로 유지하는 것을 좋아함 ) 액세서 유형 함수가 작성됩니다. 내가 직접 프로그래밍하고 있기 때문에 항상 멤버를 private즉시 설정하지는 않지만 클래스의 발전이 어딘가에서 멤버가 protected또는 로 "승격"됩니다 private.

3) 완전히 구체화하고 자신의 내부에 대한 엄격한 규칙 (즉이되는 클래스 들은 그들이 무엇을 정확히 알고, 당신이 "씨발"(전문 용어로하지 않습니다) 지정된되어 그 내부로) class지정, 개인 회원 기본, 일부 회원 만 선택할 수 있습니다 public.

이 접근 방식을 사용하면 클래스 진화의 초기 단계에서 많은 데이터 멤버가 마이그레이션되거나 이동하는 등 종교적인 게터 / 세터를 피할 수 있습니다.


1
"... 내부적으로 망칠 수없는 잘 정의 된 인터페이스"및 setter의 유효성 검사.
Agi Hammerthief

3

속성 상속이 없기 때문에 접근자를 사용하는 것이 좋습니다. 다음 예를 참조하십시오.

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(a.i);
        a.add();
        System.out.println(a.i);
        System.out.println(a.getI());
    }
}

산출:

0
0
4

3

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

  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();
    }
 }

여기서 전체 이름의 구현 세부 사항은 사용자에게 숨겨져 있으며 공용 속성과 달리 사용자가 직접 액세스 할 수 없습니다.


1
나에게 독창적 인 아무것도하지 않는 수많은 게터와 세터가있는 것은 쓸모가 없습니다. getFullName은 다른 작업을 수행하므로 예외입니다. 세 개의 변수 만 공개하고 getFullName을 유지하면 프로그램을 더 쉽게 읽을 수 있지만 여전히 전체 이름을 숨길 수 있습니다. 일반적으로 나는 게터와 세터로 완전히 괜찮습니다. 그들은 독특하고 /하거나 b. 당신은 단 하나, 예, 당신은 공개 결승과 nah를 제외한 모든 것을 가질 수 있습니다
FacelessTiger

1
이것의 장점은 인터페이스를 변경하지 않고 클래스의 내부를 변경할 수 있다는 것입니다. 세 가지 속성 대신 문자열 배열 하나가 있다고 가정 해보십시오. getter 및 setter를 사용하는 경우 변경을 수행 한 다음 getter / setter를 업데이트하여 names [0]이 이름이고 names [1]이 중간 임 등을 알 수 있습니다. 그러나 공용 속성을 사용한 경우 사용하고있는 firstName 속성이 더 이상 존재하지 않기 때문에 Employee에 액세스 한 모든 클래스를 변경해야합니다.
Andrew Hows

1
사람들이 수업의 내부를 바꿀 때 인터페이스도 바꾸고 모든 코드를 크게 리팩토링합니다
Eildosa

2

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


나는 게터 나 세터가 비싼 작업이 될 것이라고 결코 기대하지 않을 것입니다. 이러한 경우 더 나은 공장을 사용 비싼 된 invoke 당신이 필요로하는 모든 setter를 사용 execute하거나 build하는 방법.
허버트 Grzeskowiak

2

getter / setter의 상대적으로 현대적인 이점 중 하나는 태그가있는 (색인이있는) 코드 편집기에서 코드를 쉽게 찾을 수 있다는 것입니다. 예를 들어 누가 멤버를 설정하는지 보려면 세터의 통화 계층을 열 수 있습니다.

반면, 멤버가 공개 인 경우 도구를 사용하면 멤버에 대한 읽기 / 쓰기 액세스를 필터링 할 수 없습니다. 따라서 회원의 모든 용도를 망쳐 놓아야합니다.


올바른 clic> getter / setter와 정확히 같은 멤버에서 사용법을 찾을 수 있습니다
Eildosa

2

객체 지향 언어에서 메소드와 액세스 수정자는 해당 객체에 대한 인터페이스를 선언합니다. 생성자와 액세서 및 뮤 테이터 메소드 사이에서 개발자가 오브젝트의 내부 상태에 대한 액세스를 제어 할 수 있습니다. 변수가 단순히 public으로 선언되면 해당 액세스를 조절할 방법이 없습니다. 그리고 setter를 사용할 때 필요한 입력으로 사용자를 제한 할 수 있습니다. 해당 변수에 대한 피드가 올바른 채널을 통해 전달되고 해당 채널이 Google에 의해 사전 정의되어 있음을 의미합니다. 따라서 세터를 사용하는 것이 더 안전합니다.


1

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


2
나는 getter 또는 setter의 동작을 변경하는 것이 주요 변경이 아니라고 가정합니다. </ sarcasm>
R. Martinho Fernandes

@ R.MartinhoFernandes가 항상 그런 것은 아닙니다. TBYS
Phil

1

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


1
"사소한 방법"으로 런타임에 구현됩니다. 실제로, 아마도 사소하지 않을 것입니다.
Phil

오늘날 이것은 주석 프리 프로세서로 수행 할 수 있습니다.
Thorbjørn Ravn Andersen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.