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

변수에 공용 필드를 사용하는 대신 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; }

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



답변

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

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

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

답변

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


답변

공개 필드는 필드를 반환하고 할당하는 것 외에는 아무것도하지 않는 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 ).


답변

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

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

person.name = "Joe";

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

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


답변

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

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


답변

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

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

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

내 2 센트 🙂


답변

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

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

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