source

왜 getter와 setter/accessor를 사용하는가?

factcode 2022. 8. 14. 11:54
반응형

왜 getter와 setter/accessor를 사용하는가?

이러한 변수에 대해 단순히 공개 필드를 사용하는 대신 getter와 setter를 사용하면 어떤 이점이 있습니까?

Getters와 Setters가 단순한 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에 대해 동작하도록 설계된 라이브러리와의 상호 운용성 향상 - 모킹, 시리얼화 및 WPF를 생각할 수 있습니다.
  • 상속자가 getter/setter 메서드를 재정의하여 속성의 동작 및 노출 방법에 대한 의미론을 변경할 수 있습니다.
  • getter/setter를 값이 아닌 람다 식으로 전달할 수 있습니다.
  • getters와 setters는 서로 다른 접근레벨을 허용할 수 있습니다.예를 들어 get은 공개되어 있어도 세트를 보호할 수 있습니다.

지금부터 2주(월, 년) 후에 설정자가 단순히 값을 설정하는 것 이상의 작업을 수행해야 한다는 것을 알게 되면 자산이 238개의 다른 클래스에서 직접 사용되었음을 알게 됩니다.

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

getter/setter 쌍의 장점은 그렇지 않습니다.구현을 변경할 수 있으므로 클라이언트를 다시 컴파일할 필요가 없다는 주장이 있습니다.세터를 사용하면 나중에 검증과 같은 기능을 추가할 수 있으며, 고객은 이에 대해 알 필요도 없습니다.다만, 설정자에 검증을 추가하는 것은, 전제 조건의 변경이며, 이전의 계약 위반입니다.즉, 「무엇이든 여기에 넣을 수 있습니다.게터로부터 나중에 같은 것을 얻을 수 있습니다」라고 하는 매우 간단한 계약 위반입니다.

계약을 파기했으므로 코드베이스의 모든 파일을 변경하는 것은 피하고 싶은 것이 아닙니다.이 문제를 회피하는 것은 모든 코드가 그 방법에 대한 계약이 다르다고 가정하는 것입니다.

그것이 계약이 아닌 경우 인터페이스는 클라이언트가 오브젝트를 비활성 상태로 만들 수 있도록 허용하고 있습니다.캡슐화와는 정반대입니다.필드를 처음부터 아무것도 설정할 수 없는 경우 검증은 왜 처음부터 이루어지지 않았습니까?

이 주장은 이러한 패스스루 getter/setter 쌍의 기타 상정상의 이점에도 적용됩니다.나중에 설정되는 값을 변경하면 계약을 위반하는 것입니다.파생 클래스의 기본 기능을 몇 가지 수정(로깅 또는 기타 관찰할 수 없는 동작 등)하지 않는 방법으로 재정의하면 기본 클래스의 계약을 위반하는 것입니다.그것은 OO의 신조 중 하나로 여겨지는 Liskov 대체가능성 원칙 위반입니다.

만약 클래스에 모든 분야에 대해 이러한 멍청한 게터와 세터가 있다면, 그것은 불변수나 계약이 전혀 없는 클래스입니다.정말 객체 지향적인 디자인인가요?클래스 내에 이러한 게터와 세터만 있다면, 이는 단순한 멍청한 데이터 홀더일 뿐이며, 멍청한 데이터 홀더는 멍청한 데이터 홀더처럼 보여야 합니다.

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

이러한 클래스에 패스스루 getter/setter 쌍을 추가해도 아무런 가치가 없습니다.다른 클래스는 필드가 이미 제공하는 작업이 아니라 의미 있는 작업을 제공해야 합니다.그래야 유용한 불변량을 정의하고 유지할 수 있습니다.

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

getters와 setters를 사용하는 이유도 있지만, 그러한 이유가 존재하지 않는다면 false encapsulation gods라는 이름으로 getter와 setter 쌍을 만드는 것은 좋지 않습니다.getter 또는 setter를 만드는 타당한 이유에는 검증이나 다른 내부 표현 등 나중에 할 수 있는 잠재적인 변경사항으로 자주 언급되는 것들이 포함됩니다.또는 클라이언트는 이 값을 읽을 수 있지만 쓰기 불가능할 수 있습니다(예: 사전 크기 읽기). 따라서 단순한 getter를 선택하는 것이 좋습니다.하지만 이러한 이유들은 여러분이 선택을 할 때 있어야 하며, 단지 나중에 여러분이 원할 수 있는 잠재적인 것만이 아니다.이것은 YAGNI(You An't Non't Need It)의 예입니다.

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

예를 들어 수백 줄의 코드를 보고 있는데 다음과 같은 사실을 발견했다고 가정해 보십시오.

person.name = "Joe";

세터라는 걸 깨닫기 전까지는 아주 간단한 코드 조각이에요.세터를 따라가면 사람도 세팅된다는 걸 알 수 있어요firstName, person.lastName, person.isHuman, person.hasReallyCommonFirstName 및 person.update()를 호출하여 데이터베이스 등에 쿼리를 전송합니다.아, 거기서 당신 메모리 유출이 일어났군요.

로컬 코드를 한눈에 이해하는 것은 getter와 setter가 깨지기 쉬운 읽기 쉬운 중요한 특성입니다.그래서 가능하면 피하고, 사용할 때는 최소한으로 억제하려고 하고 있습니다.

순수한 객체 지향의 세계에서 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;
  }
}

코드의 EveryWHERE가 퍼블릭 필드를 사용하다가 위의 요건이 필요하다고 생각되면 어떻게 될까요?세터를 수정하는 것이 아니라 퍼블릭 필드의 모든 사용 방법을 찾아보세요.

나의 2센트 :)

접근자 및 변환자의 장점 중 하나는 검증을 실행할 수 있다는 것입니다.

를 들어, 「」의 ,foo있었기 때문에 할 수 .null그러면 다른 사람이 그 물건에 대한 메서드를 호출하려고 할 수 있습니다.하지만 그것은 더 이상 거기에 없어요!setFoo방법, 나는 그것을 확실히 할 수 있었다.foo로 되지 않았다null.

액세스 장치와 변환 장치도 캡슐화를 허용합니다. 일단 설정된 값을 볼 수 없게 되어 있으면(아마도 컨스트럭터에서 설정되고 메서드에 의해 사용되지만 절대 변경해서는 안 됩니다) 다른 사용자가 이 값을 볼 수 없습니다.단, 다른 클래스에서 표시 또는 변경을 허용할 수 있는 경우 적절한 접근자 및/또는 뮤테이터를 제공할 수 있습니다.

언어에 따라 다르죠이 "Java"가 아닌 "객체 지향"에 태그를 달았으므로 ChssPly76의 답변은 언어에 의존한다는 점을 지적하고 싶습니다.예를 들어 Python에서는 getters와 setters를 사용할 이유가 없습니다.동작을 변경해야 할 경우 기본 속성 액세스를 중심으로 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)

고마워요, 제 생각을 확실히 해 주셨어요.다음은 getter와 setter를 사용하지 않는 10가지 이유 중 하나입니다.

  1. 단순히 값을 설정하고 얻는 것 이상의 작업을 수행해야 한다는 것을 깨달았을 때 필드를 비공개로 만들면 직접 어디에 액세스했는지 즉시 알 수 있습니다.
  2. 여기서 실행하는 검증은 컨텍스트가 필요 없는 경우에만 실행할 수 있습니다.검증은 거의 실시되지 않습니다.
  3. 설정되는 값은 변경할 수 있습니다.발신자가 [쇼크 호러]가 그대로 보존해 주었으면 하는 값을 건네주면, 이것은 절대적인 악몽입니다.
  4. 을 사용하다 상적입입니니다 따라서 모든 작업이 대칭적으로 수행되도록 해야 합니다.
  5. 시트의 변경으로부터 퍼블릭인터페이스를 보호했습니다.인터페이스를 설계하고 있을 때, 무엇인가에의 직접 액세스가 적절한지 어떨지 확신이 서지 않는 경우는, 계속 설계할 필요가 있었습니다.
  6. 일부 라이브러리는 이를 예상하지만 많지 않습니다. 반사, 직렬화, 모의 개체는 모두 공용 영역에서만 작동합니다.
  7. 이 클래스를 상속하면 디폴트 기능을 덮어쓸 수 있습니다.즉, 실장을 숨길 뿐만 아니라, 일관성이 없게 하는 것으로, 발신자를 정말로 혼란시킬 수 있습니다.

마지막 세 개는 (N/A 또는 D/C)...

변수/개체의 캡슐화와 보안을 위해 필요한 경우도 있지만 실제 객체 지향 프로그램을 코드화하려면 액세스 프로그램의 과도한 사용을 중지해야 합니다. 왜냐하면 실제로 필요하지 않을 때 이러한 프로그램에 많이 의존할 수 있기 때문에 변수를 사용하는 것과 거의 비슷합니다.공개합니다.

조금 늦은 감이 있지만 공연에 관심이 있는 분들이 있을 것 같아요.

나는 약간의 성능 테스트를 했다.는 '숫자'라는.홀더"는 정수를 보관하고 있습니다. 메서드 getter를 수 .anInstance.getNumber() 직접 할 수 있습니다.anInstance.number내 프로그램은 두 가지 방법으로 숫자를 100만 번 읽는다.그 과정을 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가 취득자)

알다시피, (거의) 게터가 항상 조금 더 빠릅니다.그리고 나서 나는 다른 사이클 수로 시도했다.100만 개 대신 1000만 개, 110만 개를 썼어요.결과:

1,000만 사이클:

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만 사이클로 시간은 거의 비슷합니다.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

또한 사이클의 양이 다르므로 일반 방법보다 게터가 조금 더 빠릅니다.도움이 되셨길 바랍니다.

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

두 가지 주요한 것은 다형성과 검증이다.비록 그것이 단지 멍청한 데이터 구조일지라도.

예를 들어 다음과 같은 간단한 클래스가 있다고 합시다.

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

Bottle Overflow의 정의를 남깁니다.독자에 대한 연습으로서의 예외.

이제 이것이 얼마나 더 강력한지 보세요.현재 우리는 Bottle 대신 Liquid Container를 받아들이면 코드에 있는 어떤 종류의 컨테이너도 취급할 수 있습니다.그리고 이 병들이 이런 종류의 것들을 처리하는 방법은 모두 다를 수 있습니다.변경 시 상태를 디스크에 쓰는 병이나 SQL 데이터베이스 또는 GNU에 저장하는 병이 있을 수 있습니다.

그리고 이 모든 것들은 다양한 후유증을 다루는 다른 방법들을 가지고 있다.병은 확인만 하고 오버플로우 시 Runtime(실행 시간)을 발생시킵니다.예외.그러나 이는 잘못된 조치일 수 있습니다.(오류 처리와 관련하여 유용한 논의가 있습니다만, 일부러 단순하게 하고 있습니다.코멘트에 있는 사람은, 이 심플한 어프로치의 결점을 지적할 가능성이 있습니다. ; )

매우 간단한 아이디어에서 훨씬 더 나은 답을 빠르게 얻을 수 있는 것으로 보입니다.

또한 병 용량은 변경할 수 없으므로 주의하시기 바랍니다.그것은 이제 굳어졌다.int를 final로 선언하면 int를 사용할 수 있습니다.그러나 이것이 목록일 경우 비워두거나 새 항목을 추가하는 등의 작업을 수행할 수 있습니다.내장을 만지는 것에 대한 접근은 제한할 수 없습니다.

또한 모든 사람이 해결하지 못한 세 번째 사항이 있습니다. 즉, getter와 setter는 메서드 호출을 사용합니다.이는 다른 모든 곳에서 일반적인 방법처럼 보인다는 것을 의미합니다.DTO와 같은 특수한 구문을 사용하는 대신 모든 곳에서 동일한 구문을 사용할 수 있습니다.

getter와 setter를 사용합니다.

  • 재사용을 위해
  • 프로그래밍의 후반 단계에서 검증을 수행하다

getter 메서드와 setter 메서드는 프라이빗클래스 멤버에 액세스하기 위한 퍼블릭인터페이스입니다


캡슐화 주문

캡슐화의 목적은 필드를 비공개로 하고 메서드를 공개하는 것입니다.

Getter 메서드: 개인 변수에 접근할 수 있어요

설정 방법: 개인 필드를 수정할 수 있습니다.

getter 및 setter 메서드는 새로운 기능을 추가하지 않지만 나중에 다시 그 메서드를 만들 수 있습니다.

  • 보다 나은
  • 보다 안전하다.
  • 빠른.

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

int x = 1000 - 500

사용하다

int x = 1000 - class_name.getValue();

문외한의 말로 하자면

Representation of "Person" class

를 들어, 이 사연에 대한 을 저장해야 한다고 가정해 보겠습니다.Person 이거.Personname,age ★★★★★★★★★★★★★★★★★」sex , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , 의 방법을 .name,age ★★★★★★★★★★★★★★★★★」sex 다른 사람을 할 때, ' 사람을 만들어야 한다'는 방법을 할 것 같아요.name,age,sex츠미야

하는 것이 수 .class(Person)getter와 setter 방법을 사용합니다.그래서 내일 우리는 이 빈의 오브젝트를 만들 수 있습니다.class(Person class)새로운 인물을 추가할 필요가 있는 경우(그림 참조).그래서 우리는 콩 수업의 밭과 방법을 재사용하고 있는데, 이것은 훨씬 더 좋다.

Java의 케이스에 대해서, 이것에 대해 꽤 오랜 시간을 고민했습니다만, 그 진짜 이유는 다음과 같습니다.

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

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

그 방법들은 악명높은 게터, 세터...

현재 배송에 필요한 경우가 아니면 getters setter를 사용하지 마십시오.미래에 무슨 일이 일어날지 너무 많이 생각하지 마세요.변경해야 할 것이 있다면 대부분의 실가동 어플리케이션과 시스템에서 변경 요청을 해야 합니다.

단순하게 생각하고, 쉽게 생각하고, 필요에 따라 복잡함을 더합니다.

나는 그것이 옳다고 생각하거나 내가 그 접근법을 좋아한다는 이유만으로 깊은 기술적 지식을 가진 사업주들에 대한 무지를 이용하지 않을 것이다.

저는 getters setters 없이 액세스 수식자 및 n perform biz 로직을 검증하는 몇 가지 방법으로만 방대한 시스템을 작성했습니다.만약 당신이 꼭 그게 필요하다면요.아무거나 써.

이것은 게으른 부하에 도움이 될 수 있습니다.예를 들어, 문제의 개체가 데이터베이스에 저장되어 있으며, 필요한 경우가 아니면 가져오고 싶지 않다고 합니다.오브젝트가 getter에 의해 취득된 경우 내부 오브젝트는 누군가가 요구할 때까지 null이 될 수 있습니다.그 후 getter에 대한 첫 번째 호출로 취득할 수 있습니다.

프로젝트의 기본 페이지 클래스는 몇 가지 다른 웹 서비스 호출에서 데이터를 로드하는 것이었지만 웹 서비스 호출의 데이터가 모든 하위 페이지에서 항상 사용되는 것은 아니었습니다.웹 서비스는 모든 이점을 위해 "느림"의 새로운 정의를 개척하기 때문에 굳이 웹 서비스를 호출할 필요가 없습니다.

공공 필드에서 게터로 옮겼는데, 이제 게터들이 캐시를 확인하고 캐시가 없으면 웹 서비스에 연락해요.그래서 포장을 조금만 하면 많은 웹 서비스 전화를 막을 수 있었습니다.

따라서 Getter를 통해 각 하위 페이지에서 무엇이 필요한지 파악할 필요가 없습니다.필요할 때, 저는 게터에게 전화를 걸면, 제가 아직 가지고 있지 않다면 찾아줄 것입니다.

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

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

  • 구성원의 경우 설정 및 취득에 대한 접근 사양은 1개뿐입니다.
  • 세터와 게터의 경우 미세 조정하여 별도로 정의할 수 있습니다.

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

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

OOO 디자인의 기본 원리 중 하나:캡슐화!

Getter/Setter의 실장을 백그라운드에서 변경할 수 있지만 데이터 유형이 변하지 않는 한 그 가치를 가진 사용자는 계속 작업할 수 있습니다.

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

  • 개념적으로는 속성이지만 다음과 같은 문제를 다루고 있습니다.
    • 언어에는 속성(또는 TCL의 가변 트레이스 등 유사한 메커니즘)이 없습니다.
    • 해당 언어의 속성 지원이 이 사용 사례에 충분하지 않습니다.
    • 언어(또는 프레임워크)의 관용 규약에 따라서는 이 사용 사례에 대한 취득자 또는 설정자가 권장됩니다.

이 질문은 일반적인 OO 질문이 아닙니다. 언어별 질문으로 언어(사용 사례)에 따라 답변이 다릅니다.


OO이론의 관점에서 보면, getter와 setter는 무용지물이다.클래스의 인터페이스는 상태가 아닌 동작입니다(그렇지 않으면 잘못된 클래스를 쓴 것입니다).매우 단순한 경우에서는 클래스가 하는 일이 직사각형 좌표의 점을 나타내는 것과 같이* 속성이 인터페이스의 일부인 경우 getter와 setter는 이를 클라우딩하기만 하면 됩니다.단, 매우 단순한 경우를 제외하고는 Atribute도 getter도 setter도 인터페이스에 포함되지 않습니다.

바꿔 말하면:만약 당신이 당신의 클래스 소비자들이 당신이 가지고 있다는 것을 알아야 한다고 믿는다면spam아트리뷰트, 하물며 마음대로 변경할 수 있는 것은커녕, 그 다음에 그들에게도,set_spam방법은 절대 하고 싶지 않습니다.

* 이 단순한 클래스에서도 반드시 다음 설정을 허용하고 싶지는 않을 수 있습니다.x그리고.y가치.이게 정말 수업이라면 이런 방법이 있지 않을까?translate,rotate, 등등? 당신의 언어에는 기록/구조/이름 있는 튜플이 없기 때문에 수업일 뿐이라면, 이것은 사실 OO의 문제가 아닙니다.


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

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

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

'나중에 구현을 변경하고 싶은 경우'에 대해서는 다음과 같이 질문합니다(OP의 질문과 수용된 답변 모두 다른 문구로 여러 번 반복됩니다).실제 구현 변경으로 Atribute에서 시작한 경우 인터페이스에 영향을 주지 않고 Atribute로 변경할 수 있습니다.물론 당신의 언어가 그것을 지원하지 않는다면요.그래서 이것은 정말 똑같은 경우입니다.

또한 사용하는 언어(또는 프레임워크)의 숙어를 따르는 것도 중요합니다.C#에 아름다운 Ruby 스타일의 코드를 쓰면, 당신 이외의 경험 많은 C# 개발자가 읽는데 어려움을 겪게 되어 버립니다.어떤 언어들은 다른 언어들보다 관습 주변에 더 강한 문화를 가지고 있다.또한 자바와 Python은 관용적인 getter가 얼마나 강한지에 대해 정반대의 입장을 보이고 있는 것은 우연이 아닐지도 모른다.

인간 독자 외에도, 여러분이 관습을 따르기를 기대하는 도서관과 도구들이 있을 것이고, 그렇지 않으면 여러분의 삶을 더 힘들게 할 것입니다.인터페이스 빌더 위젯을 ObjC 속성 이외의 다른 속성에 연결하거나 getter 없이 특정 Java 모킹 라이브러리를 사용하는 것은 당신의 삶을 더욱 힘들게 할 뿐입니다.도구가 당신에게 중요하다면 싸우지 마세요.

오브젝트 방향 설계의 관점에서 보면, 양쪽의 대안은 클래스의 캡슐화를 약화시켜 코드의 유지보수에 악영향을 줄 수 있습니다.자세한 내용은 http://typicalprogrammer.com/?p=23의 훌륭한 기사를 참조해 주세요.

코드가 진화하다. private데이터 멤버 보호가 필요한 경우에 적합합니다.결국 모든 클래스는 내부 인터페이스만 가지고는 문제 삼을 없는 명확한 인터페이스를 갖춘 미니프로그래밍이 되어야 합니다.

즉, 소프트웨어 개발은 마치 한 번에 주철상을 누르는 것처럼 클래스의 최종 버전을 설정하는 것이 아닙니다.작업하는 동안 코드는 점토에 가깝습니다.개발하면서 해결 중인 문제 영역에 대해 더 자세히 학습하면서 진화합니다.개발 클래스는 서로 필요 이상으로 상호 작용하거나(배제하려는 종속성), 병합하거나 분할할 수 있습니다.그래서 토론은 종교적으로 글을 쓰는 것을 원하지 않는 사람들로 요약된다고 생각한다.

int getVar() const { return var ; }

다음과 같은 것이 있습니다.

doSomething( obj->getVar() ) ;

대신

doSomething( obj->var ) ;

뿐만 아니라getVar()시각적으로 시끄럽다, 그것은 이런 착각을 준다.gettingVar()실제보다 더 복잡한 과정이라고 생각합니다.(수업생으로서) 의 신성함을 어떻게 생각하시나요?var패스스루 세터가 있는 경우 클래스 사용자에게 특히 혼란을 줍니다.그러면 귀중하다고 생각되는 것을 보호하기 위해 게이트를 설치하는 것처럼 보입니다.var하지만 너조차도 인정한다.var님의 보호는 아무나 들어와서 할 수중에 넣을 수 있는 능력으로는 큰 의미가 없습니다.set var그 사람들이 뭘 하는지 엿보지도 않고요

따라서 다음과 같이 프로그램합니다('애자일' 타입의 접근법이라고 가정합니다.즉, 정확히 무엇을 할지 모르는 코드를 작성할 때/정밀한 워터폴 스타일의 인터페이스 세트를 계획할 시간이나 경험이 없습니다).

1) 데이터 및 동작을 포함한 기본 객체에 대해서는 모든 퍼블릭 멤버부터 시작합니다.이 때문에, 모든 C++ 코드의 「예」에서는,struct대신class온통.

2) 데이터 멤버에 대한 오브젝트의 내부 동작이 충분히 복잡해진 경우(예를 들어 내부 상태를 유지하는 것을 좋아한다)std::list어떤 순서로) 접근자 유형 함수가 작성됩니다.혼자 프로그래밍을 하기 때문에 항상 멤버를 설정하지는 않습니다.private지금 당장, 하지만 수업의 진화에 따라 그 구성원은 어느 쪽인가에 대해 "적절"하게 될 것이다.protected ★★★★★★★★★★★★★★★★★」private.

3) 완전히 살찌고 내부 규칙에 엄격한 클래스(즉, 자신이 무엇을 하고 있는지 정확히 알고 있으며, 내부 용어를 사용하여 "fuck"(기술 용어)하지 않음)에는, 다음과 같은 정보가 주어집니다.classmembers 및 됩니다.public.

이 방법을 사용하면 클래스 진화 초기 단계에서 많은 데이터 구성원이 마이그레이션되거나 이동될 때 getter/setters를 주의 깊게 쓰는 것을 피할 수 있습니다.

Getters와 setters는 객체 지향 프로그래밍의 두 가지 기본 측면을 구현하기 위해 사용됩니다.

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

여기서 풀네임 구현 세부 정보는 사용자에게 숨겨져 있으며 공용 애트리뷰트와 달리 사용자가 직접 액세스할 수 없습니다.

getter 메서드와 setter 메서드는 액세스 방식입니다.즉, 일반적으로 프라이빗클래스 멤버를 변경하는 퍼블릭인터페이스입니다getter 및 setter 메서드를 사용하여 속성을 정의합니다.getter 및 setter 메서드는 클래스 내에서 메서드로 정의하더라도 클래스 외부의 속성으로 액세스할 수 있습니다.클래스 외부에 있는 이러한 속성은 클래스의 속성 이름과 다른 이름을 가질 수 있습니다.

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

getter 및 setter 메서드는 유용하지만 특히 특정 상황에서는 코드 유지보수가 더 어려워질 수 있으므로 과도하게 사용하지 않도록 주의해야 합니다.또한 공용 구성원과 같이 클래스 구현에 대한 액세스 권한을 제공합니다.OOP 연습에서는 클래스 내의 속성에 직접 액세스하는 것을 권장하지 않습니다.

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

속성 상속이 없기 때문에 접근기 사용을 고려할 충분한 이유가 있습니다.다음의 예를 참조해 주세요.

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

DataStructure와 Object 사이에는 차이가 있습니다.

데이터 구조는 동작이 아닌 내부 구조를 노출해야 합니다.

물체는 그 내장을 드러내서는 안 되지만, 그 행동을 드러내야 한다.이것은 데메터의 법칙이라고도 불린다.

대부분의 DTO는 오브젝트가 아닌 데이터 구조에 가깝다고 간주됩니다.데이터만 노출하고 행동은 노출하지 않아야 합니다.DataStructure에 Setter/Getter가 있으면 데이터 대신 동작이 노출됩니다.이것은 디메터의 법칙을 위반할 가능성을 더욱 높인다.

밥 삼촌은 그의 책 Clean code에서 디메터의 법칙을 설명했다.

모듈이 조작하는 물체의 내장에 대해 알아서는 안 된다는 데미터의 법칙이라고 불리는 잘 알려진 발견적 연구법이 있다.지난 섹션에서 살펴본 것처럼 개체는 데이터를 숨기고 작업을 노출합니다.즉, 오브젝트는 내부 구조를 숨기는 것이 아니라 공개하는 것이기 때문에 접근자를 통해 내부 구조를 공개해서는 안 됩니다.

보다 정확하게는, C등급의 방법 f는 다음의 방법만을 호출해야 한다고 데메터의 법칙은 말한다.

  • C
  • f에 의해 작성된 오브젝트
  • f에 인수로 전달된 개체입니다.
  • C의 인스턴스 변수에 있는 개체

메서드는 허용된 함수 중 하나에서 반환되는 개체에 대해 메서드를 호출하지 않아야 합니다.다시 말해, 낯선 사람이 아니라 친구들과 이야기하세요.

따라서 LoD 위반의 예는 다음과 같습니다.

final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();

여기서 함수는 여기서 ctxt인 직계 친구의 메서드를 호출해야 하며 직계 친구의 메서드를 호출해서는 안 되지만 데이터 구조에는 이 규칙이 적용되지 않습니다.여기서 ctxt, option, scratchDir가 데이터 구조라면 내부 데이터를 LoD 위반으로 랩하는 이유는 무엇입니까?

대신, 우리는 이런 것을 할 수 있습니다.

final String outputDir = ctxt.options.scratchDir.absolutePath;

이것은 우리의 요구를 충족시키고 심지어 LoD를 위반하지 않는다.

Robert C가 Clean Code에서 영감을 얻었다.마틴(밥 삼촌)

검증이 필요 없고 상태를 유지할 필요도 없는 경우(즉, 하나의 자산이 다른 자산에 의존하므로 하나의 자산이 변경되었을 때 상태를 유지해야 합니다).getter와 setter를 사용하지 않고 필드를 공개함으로써 단순함을 유지할 수 있습니다.

OOP는 프로그램이 커짐에 따라 개발자의 확장이 악몽이 되어 일을 복잡하게 만든다고 생각합니다.

간단한 예로 xml에서 c++ 헤더를 생성합니다.헤더에는 검증이 필요 없는 단순 필드가 포함되어 있습니다.그러나 여전히 OOPS Accessor의 패션은 다음과 같습니다.

const Filed& getfield() const
Field& getField() 
void setfield(const Field& field){...} 

그것은 매우 장황하고 필수가 아니다.단순하다.

struct 
{
   Field field;
};

충분히 읽을 수 있습니다.기능적 프로그래밍은 데이터를 숨긴다는 개념이 없으며 데이터를 변환하지 않기 때문에 필요하지도 않습니다.

게다가 이것은, 당신의 클래스를 「미래에 대비하기 위해서」입니다.특히 필드에서 속성으로 변경하는 것은 ABI 중단입니다.따라서 나중에 "필드 설정/취득" 이상의 논리가 필요하다고 판단하면 ABI를 중단해야 합니다.이것은 물론 이미 클래스에 대해 컴파일된 다른 모든 것에 문제를 일으킵니다.

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

getters/setters의 비교적 현대적인 장점은 태그 부착(인덱스 부착) 코드 에디터에서 코드를 쉽게 참조할 수 있다는 것입니다.예를 들어, 구성원을 설정하는 사용자를 확인하려면 설정자의 콜 계층을 열 수 있습니다.

한편, 멤버가 공개되어 있는 경우, 툴에서는 멤버에 대한 읽기/쓰기 액세스를 필터링 할 수 없습니다.그래서 멤버들의 모든 용도를 터벅터벅 걸어가야 합니다.

언급URL : https://stackoverflow.com/questions/1568091/why-use-getters-and-setters-accessors

반응형