게터와 세터가 정당화되는시기


175

게터와 세터는 종종 적절한 OO가 아니라고 비판합니다. 반면에 내가 본 대부분의 OO 코드에는 광범위한 게터와 세터가 있습니다.

게터와 세터는 언제 정당화됩니까? 그것들을 사용하지 않으려 고합니까? 그들은 일반적으로 남용됩니까?

좋아하는 언어에 속성 (광산)이있는 경우 이러한 질문은이 질문에 대한 게터 및 세터로 간주됩니다. 그것들은 OO 방법론 관점에서 똑같습니다. 그들은 더 좋은 구문을 가지고 있습니다.

Getter / Setter 비판의 출처 (일부 의견에서 더 나은 가시성을 제공하기 위해 가져옴) :

비판을 간단히 말하면 : Getter와 Setter를 사용하면 객체 외부에서 객체의 내부 상태를 조작 할 수 있습니다. 이것은 캡슐화를 위반합니다. 객체 자체 만 내부 상태를 관리해야합니다.

그리고 절차 적 코드 버전의 예입니다.

struct Fridge
{
    int cheese;
}

void go_shopping(Fridge fridge)
{
     fridge.cheese += 5;
}

코드의 뮤 테이터 버전 :

class Fridge
{
     int cheese;

     void set_cheese(int _cheese) { cheese = _cheese; }
     int get_cheese() { return cheese; }
 }

void go_shopping(Fridge fridge)
{
     fridge.set_cheese(fridge.get_cheese() + 5);        
}

getter와 setter는 적절한 캡슐화없이 코드를 훨씬 더 복잡하게 만들었습니다. 내부 상태는 다른 객체에 액세스 할 수 있기 때문에 이러한 게터와 세터를 추가하여 많은 것을 얻지 못합니다.

이 질문은 이전에 스택 오버플로에서 논의되었습니다.


21
Getters and setters are often criticized as being not proper OO-인용 부탁드립니다.
Robert Harvey


45
@Job, 왜 코드가 있습니까? 진지하게 받아들이면 좋은 질문이자 거룩한 전쟁의 악취가납니다.
피터 터너

2
@Winston Ewert : "... 문제는 클래스 내부의 데이터에 전혀 액세스해야하는지에 대한 질문입니다." 그래서 공개 멤버 변수 대신 게터와 세터를 사용하는 것입니다.
Giorgio

2
@Winston Ewert : getter / setter가 없으면이 문제를 어떻게 해결할지 모르겠습니다. 그렇지 않으면 모든 데이터에 액세스 할 수있는 방법이 있어야합니다. 그렇지 않으면 쓸모가 없습니다. 데이터의 어느 부분이 코드의 어느 부분에 액세스 가능한지를 결정하는 것은 좋은 디자인의 과제입니다. 나쁜 디자이너라면 게터 나 세터가 있거나없는 사람 일 것입니다. 그냥 내 2 센트.
조르지오

답변:


162

게터와 세터가 있다고해서 캡슐화가 깨지는 것은 아닙니다. 캡슐화를 깨뜨리는 것은 모든 데이터 멤버 ( Java lingo의 모든 필드 )에 대해 아무런 생각없이 자동으로 getter 및 setter를 추가하는 것입니다. 이것은 모든 데이터 멤버를 공개하는 것보다 낫지 만 조금만 걸 으면됩니다.

캡슐화의 요점은 당신이 알고 또는 객체 외부에서 개체의 상태를 변경할 수 없게하는 것,하지만 당신은 합리적인있는 것이 아니다 정책 을 수행하기위한합니다.

  • 일부 데이터 멤버는 객체 내부에있을 수 있으며 게터 나 세터가 없어야합니다.

  • 일부 데이터 멤버는 읽기 전용이어야하므로 게터가 필요하지만 세터는 필요하지 않을 수 있습니다.

  • 일부 데이터 멤버는 서로 일관성을 유지해야 할 수도 있습니다. 이 경우 각 설정기에 대해 세터를 제공하지 않고 동시에 설정하는 단일 방법을 제공하므로 값의 일관성을 확인할 수 있습니다.

  • 일부 데이터 멤버는 일정량 씩 증가 또는 감소와 같은 특정 방식으로 만 변경하면됩니다. 이 경우 세터 대신 increment()및 / 또는 decrement()메소드를 제공해야합니다 .

  • 그러나 다른 사람들은 실제로 읽기 / 쓰기가 필요할 수 있으며 게터와 세터가 모두 있어야합니다.

의 예를 고려하십시오 class Person. 사람의 이름, 사회 보장 번호 및 연령이 있다고 가정 해 봅시다. 사람들이 이름이나 주민등록번호를 변경하는 것을 허용하지 않는다고 가정 해 봅시다. 그러나 사람의 나이는 매년 1 씩 증가해야합니다. 이 경우 이름과 SSN을 지정된 값으로 초기화하고 나이를 0으로 초기화하는 생성자를 제공합니다. 또한 incrementAge()나이를 1 씩 증가시키는 메소드 도 제공합니다. 세 가지 모두에 대한 게터. 이 경우 세터가 필요하지 않습니다.

이 디자인에서는 클래스 외부에서 오브젝트의 상태를 검사하고 클래스 외부에서 오브젝트를 변경할 수 있습니다. 그러나 상태를 임의로 변경할 수는 없습니다. 이름과 SSN을 전혀 변경할 수 없으며 연령을 한 번에 1 년씩 증분 할 수 있다는 정책이 있습니다.

이제 사람에게 급여가 있다고 가정 해 봅시다. 그리고 사람들은 마음대로 일자리를 바꿀 수 있습니다. 즉, 급여도 바뀔 것입니다. 이 상황을 모델링하기 위해 다른 방법은 없습니다 setSalary(). 이 경우 연봉 변경을 허용하는 것이 완벽하게 합리적인 정책입니다.

그런데, 귀하의 예제에서, 나는 클래스 줄 것 과 대신의 방법을, 하고 . 그러면 여전히 캡슐화가 발생합니다.FridgeputCheese()takeCheese()get_cheese()set_cheese()


public class Fridge {
  private List objects;
  private Date warranty;

  /** How the warranty is stored internally is a detail. */
  public Fridge( Date warranty ) {
    // The Fridge can set its internal warranty, but it is not re-exposed.
    setWarranty( warranty );
  }

  /** Doesn't expose how the fridge knows it is empty. */
  public boolean isEmpty() {
    return getObjects().isEmpty();
  }

  /** When the fridge has no more room... */
  public boolean isFull() {
  }

  /** Answers whether the given object will fit. */
  public boolean canStore( Object o ) {
    boolean result = false;

    // Clients may not ask how much room remains in the fridge.
    if( o instanceof PhysicalObject ) {
      PhysicalObject po = (PhysicalObject)o;

      // How the fridge determines its remaining usable volume is a detail.
      // How a physical object determines whether it fits within a specified
      // volume is also a detail.
      result = po.isEnclosedBy( getUsableVolume() );
    }

     return result;
  }

  /** Doesn't expose how the fridge knows its warranty has expired. */
  public boolean isPastWarranty() {
    return getWarranty().before( new Date() );
  }

  /** Doesn't expose how objects are stored in the fridge. */
  public synchronized void store( Object o ) {
    validateExpiration( o );

    // Can the object fit?
    if( canStore( o ) ) {
      getObjects().add( o );
    }
    else {
      throw FridgeFullException( o );
    }
  }

  /** Doesn't expose how objects are removed from the fridge. */
  public synchronized void remove( Object o ) {
    if( !getObjects().contains( o ) ) {
      throw new ObjectNotFoundException( o );
    }

    getObjects().remove( o );

    validateExpiration( o );
  }

  /** Lazily initialized list, an implementation detail. */
  private synchronized List getObjects() {
    if( this.list == null ) { this.list = new List(); }
    return this.list;
  }

  /** How object expiration is determined is also a detail. */
  private void validateExpiration( Object o ) {
    // Objects can answer whether they have gone past a given
    // expiration date. How each object "knows" it has expired
    // is a detail. The Fridge might use a scanner and
    // items might have embedded RFID chips. It's a detail hidden
    // by proper encapsulation.
    if( o implements Expires && ((Expires)o).expiresBefore( today ) ) {
      throw new ExpiredObjectException( o );
    }
  }

  /** This creates a copy of the warranty for immutability purposes. */
  private void setWarranty( Date warranty ) {
    assert warranty != null;
    this.warranty = new Date( warranty.getTime() )
  }
}

4
냉장고 예제를 너무 진지하게 받아들이지 마십시오. :) 실제 냉장고는 컨테이너 객체 여야합니다. 정확히 무엇인지 걱정하지 않고 객체를 보관하는 방법을 알고 싶습니다. IE는 ArrayList와 같습니다. 냉장고가 무엇인지에 관해서는, 저장시 객체를 디스크로 직렬화하여 시스템 장애로부터 살아남을 것이라고 가정 해 봅시다. 승인. 냉장고 예제를 진지하게 받아들이면 충분합니다.
Winston Ewert

6
그러나 냉장고가 유통 기한을 알면 치즈가 나빠져 버려야한다는 것을 알 수 있습니까? :) 좋아, 우리는 이것을 멈춰야한다! :)
Dima

10
Fridge Logic에 대한 흥미로운 토론이 있습니다.
Mason Wheeler

35
하하, 그 광고를보고 싶습니다 : "새로운 종류의 냉장고입니다. 존재하지 않는 것을 잡으려고 할 때 물건을 던집니다! 이렇게하면 한 번만 시도 할 것입니다! 냉장고를 채우고 냉장고에 불법적 인 행동을 걱정하게하세요! "
gablin

42
예는 모두 잘못되었습니다. Age 필드 나 setAge () 메소드가 없어야합니다. 나이는 특정 시점에 비해 Person birthDate의 함수입니다. 사소한 것처럼 보이지만 이것은 개인 필드에 대한 get / set 메소드에서 볼 수 있듯이 실제 변경 가능한 필드, 필드, 오브젝트를 신중하게 고려하는 것과 같이 객체 및 기타 나쁜 디자인의 전체 변경 가능성에 대한 현대의 관행에있어 잘못된 것입니다. 동작과 실제로 유효한 상태 변경 (setX 메소드가 완전히 파괴됨)에 대해 알아야합니다.
Darrell Teague

41

Java에서 getter 및 setter의 기본 이유는 매우 간단합니다.

  • 인터페이스에서는 필드가 아닌 메소드 만 지정할 수 있습니다 .

따라서 필드가 인터페이스를 통과하게하려면 리더와 라이터 메소드가 필요합니다. 이들은 일반적으로 필드 x에 대해 getX 및 setX라고합니다.


44
언어 제한입니다. 실제 문제는 다른 객체가 해당 상태를 조작하도록 허용해야하는지 여부입니다.
윈스턴 에워 트

3
@ 피터 터너 (Peter Turner)는 언어가 속성을 포함하는 인터페이스를 갖지 못하게 막습니다. 덮개 아래에서 getter / setter로 구현 될 수 있지만 속성에 대한 인터페이스 정의에 대한 지원을 추가하기에 충분히 쉽습니다.
Winston Ewert

2
@Winston, 결국 실제로 작업을 수행하려면 클래스가 서로 정보를주고 받도록해야합니다. 대신 무엇을 제안 하시겠습니까?

6
객체는 내부에 더 높은 수준의 인터페이스를 제공해야합니다. 게터와 세터는 저수준 인터페이스 인 경향이 있습니다. 예를 들어 이진 트리를 구현하는 클래스가 있다고 가정합니다. 트리를 탐색하기 위해 GetLeft (), GetRight (), GetValue () 및 GetKey ()와 같은 함수를 가질 수 있습니다. 그러나 그것은 완전히 잘못된 접근법입니다. 이진 트리 클래스는 찾기, 삽입, 삭제와 같은 작업을 제공해야합니다.
Winston Ewert

6
다른 예를 들자면 테트리스 조각을 고려하십시오. 테트리스 조각은 block_type, rotation, position과 같은 내부 상태를 갖습니다. GetBlockType (), GetRotation (), GetPosition ()과 같은 게터를 가질 수 있습니다. 그러나 당신은 정말로해서는 안됩니다. 당신이 가져야 할 것은이 조각이 차지하는 모든 사각형의 목록을 반환하는 GetSquares () 메서드입니다. SetPosition () 또는 SetRotation ()과 같은 것도 없어야합니다. 대신 MoveLeft (), MoveRight (), Rotate (), Fall ()과 같은 작업이 있어야합니다.
Winston Ewert

20

에서 http://www.adam-bien.com/roller/abien/entry/encapsulation_violation_with_getters_and

자바 빈즈 스타일 :

connection.setUser("dukie");
connection.setPwd("duke");
connection.initialize();

OO 스타일 :

connection.connect("dukie","duke");

글쎄, 나는 후자의 접근법을 선호한다. 구현 세부 사항을 피하지 않고 더 간단하고 간결하며 필요한 모든 정보가 메서드 호출에 포함되어 있으므로 올바르게 얻을 수 있습니다. 또한 가능할 때마다 생성자에서 매개 변수를 사용하여 개인 멤버를 설정하는 것을 선호합니다.

귀하의 질문은 언제 getter / setter가 정당화되는 것입니까? 아마도 모드 변경이 필요하거나 정보를 얻기 위해 개체를 조사해야 할 때가 있습니다.

myObject.GetStatus();
myObject.SomeCapabilitySwitch = true;

그것에 대해 생각할 때, C #으로 코딩을 처음 시작했을 때 위에서 설명한 Javabeans 스타일로 많은 코드를 작성했습니다. 그러나 언어에 대한 경험을 쌓으면서 생성자에서 더 많은 멤버를 설정하고 위의 OO 스타일과 유사한 메소드를 사용하기 시작했습니다.


6
"모든 인수를 매개 변수로 제공"이 OO 스타일 인 이유는 무엇입니까?

5
귀하의 "OO 스타일"은 2 또는 3 옵션에 적합하지만, 일단 그 이상에 도달하면 JavaBean 스타일을 선호합니다. 가능한 모든 매개 변수 조합에 대해 20 개의 오버로드 된 메소드를 갖는 것은 끔찍한 것 같습니다
TheLQ

1
@TheLQ : C # 4.0은 생성자 및 메서드 호출에서 선택적 및 명명 된 매개 변수를 허용하여이 작업을 더 쉽게 만듭니다.
Robert Harvey

7
@TheLQ 유창한 구문을 가진 Builder의 목적은 구아바의 MapMaker 입니다.
maaartinus

5
@ Thorbjørn Ravn Andersen은 "모든 인자를 매개 변수로 제공"이 "JavaBean setter 호출"보다 OO 스타일보다 좋다고 말합니다. 왜냐하면 setter는 기본 속성이 설정되어 있음을 암시하므로 내부 세부 사항을 노출시킵니다. 예제에서 connect (..) 메소드를 사용하면 그러한 가정이 없습니다. 사용자 및 비밀번호 속성을 설정했을 수도 있고 그렇지 않을 수도 있습니다. 중요한 것은 올바른 OO 개념 인 "연결"메시지에 집중하는 것입니다.
Andres F.

13

게터와 세터는 언제 정당화됩니까?

동작 "get"및 "set"이 실제로 모델의 동작과 일치 할 때 실제로는 결코 그렇지 않습니다 .

비즈니스 영역의 동작이 명확하지 않기 때문에 다른 모든 용도는 속임수입니다.

편집하다

그 대답은 플립 팬트로 나타 났을 것입니다. 위의 답변은 대부분 정확하지만 OO 디자인의 프로그래밍 패러다임과 큰 그림을 놓친 부분에 중점을 둡니다. 내 경험상 이것은 사람들로 하여금 get과 setter를 피하는 것이 OO 프로그래밍 언어의 학문적 규칙이라고 생각하게합니다 (예 : 사람들은 getter를 속성으로 대체하는 것이 웅장하다고 생각합니다)

실제로 이는 설계 프로세스의 결과입니다. 인터페이스와 캡슐화 및 패턴에 빠질 필요가 없으며 이러한 패러다임을 깨뜨릴 것인지 아닌지, 그리고 OO 프로그래밍이 좋은지 아닌지를 논쟁합니다. 궁극적으로 중요한 점은 도메인에 이런 식으로 작동하는 도메인이 없으면 도메인을 모델링하지 않는다는 것입니다.

실제로는 도메인 공간의 시스템에 게터와 세터가있을 가능성이 거의 없습니다. 급여를 담당하는 남녀에게 걸어 가서 "이 급여를 X로 설정하십시오" 또는 "이 급여를 받으십시오 " 라고 간단히 말 하십시오 . 그러한 행동은 단순히 존재하지 않습니다

이것을 코드에 넣으면 도메인 모델과 일치하도록 시스템을 설계하지 않은 것입니다. 예, 인터페이스와 캡슐화를 깨뜨 렸지만 요점은 아닙니다. 요점은 존재하지 않는 것을 모델링하고 있다는 것입니다.

더 이상 당신은 아마도 중요한 단계 또는 프로세스를 잃어 버릴 것입니다. 왜냐하면 내가 롤을 지불 하고이 급여를 X로 설정한다고 말할 수없는 이유가있을 수 있기 때문입니다.

사람들이 게터와 세터를 사용할 때이 프로세스에 대한 규칙을 잘못된 위치로 밀어 넣는 경향이 있습니다. 이것은 도메인에서 훨씬 더 멀어지고 있습니다. 실제 예를 사용하면, 들어간 임의의 사람이 이러한 값을 얻을 수있는 권한이 있다고 가정하면 급여와 같습니다. 그렇지 않으면 값을 요구하지 않을 것입니다. 그것은 도메인의 상태뿐만 아니라 실제로 도메인의 상태에 관한 것입니다.


포인트를 만든 전에 17 답 설명을 통해이 상당한 아무것도 제공하지 않는 것
모기

1
다른 답변은 객체, 인터페이스 및 기타 언어 패러다임에 대해 이야기합니다. 어느 것이 좋지만 중심적인 문제는 아닙니다. Getter와 Setter는 일부 코딩 규칙을 위반하기 때문에 나쁜 것이 아니라 주로 표현하는 실제 모델에서이 동작이 거의 발생하지 않기 때문에 나쁩니다. 이 점은 최상의 코딩 방법에 대한 토론에서 길을 잃는 경향이 있습니다.
Cormac Mulhall

급여가 아니라면 급여에 대한 인터페이스는 무엇이라고 생각 set/get하십니까?
Winston Ewert

1
이들이 인증 계층을 감싸고 특정 외부 엔티티로 제한되면 게터 및 세터가 아닙니다. 급여 부서에 급여를 변경하는 방법이 없다고 말하지는 않지만 그 방법은 회사 자체의 내부 프로세스와 일치해야합니다. 예를 들어, 대부분의 회사는 직원 계약을 기반으로 급여를 설정합니다.이 계약은 관리자가 승인합니다. 직원의 급여가 변경되면 새 계약이 작성되고 관리자가 계약에 서명해야합니다. 따라서 급여는 계약서 및 일부 승인서가 급여 명세서를 변경해야합니다
Cormac Mulhall

3
또는 달리 말하면 set_salary (new_salary, employee_id)와 certified_salary_update (employee_contract, authorising_manager) 사이에는 상당한 차이가 있습니다. 프로세스는 내부 비즈니스 프로세스를 모델링해야합니다
Cormac Mulhall

11

일반적으로 게터와 세터는 나쁜 생각입니다. 필드가 논리적으로 인터페이스의 일부가 아니고 개인으로 만들면 괜찮습니다. 논리적으로 인터페이스의 일부이고 공용으로 만들면 괜찮습니다. 그러나 비공개로 만든 다음 게터와 세터를 제공하여 다시 공개하고 효과적으로 공개하면 코드가 더 장황하고 난독 화 된 것을 제외하고 시작한 곳으로 돌아갑니다.

분명히 예외가 있습니다. Java에서는 인터페이스를 사용해야합니다. Java 표준 라이브러리는 일반적인 코드 품질 측정치보다 훨씬 높은 역 호환성 요구 사항을 갖습니다. 실제로 전설을 다루는 경우도 있지만 인터페이스를 손상시키지 않고 저장된 필드를 즉석 계산으로 바꿀 수도 있습니다. 그러나 이것들은 예외입니다. 게터와 세터는 특별한 타당성을 요구하는 반 패턴입니다.


6
getter 및 setter는 필드가 아닌 속성이 인터페이스의 일부임을 의미합니다. getBirthDate () 및 SetBirthDate ()에 "yyyy / mm / dd"가 걸리지 만 저장된 필드는 01/01/1000 이후의 일 수입니다. 이를 01/01/0001로 변경하면 getter와 setter가 인터페이스를 동일하게 유지합니다. 특히 'public'은 공개적으로 쓰레기를 의미하기 때문에 변수는 절대 공개되지 않아야합니다. 항상 setter를 사용하여 들어오는 값을 확인하고 관련 필드를 업데이트하고 필요에 따라 변환하십시오. 내부 저장소가 변경 될 경우 getter를 사용해보십시오.
Andy Canfield

@AndyCanfield는 공개적으로 말하기에는 약간 강력하지만 공개적으로 쓰레기를 버릴 수 있음을 의미합니다. setter가 있고 잘못된 값이 전송되면 u는 프로그램을 휴지통에 버릴 수있는 예외를 던질 수 있지만 오류로 종료됩니다. 또한 객체의 사용자가 변수에 값을 줄 수 있고 cud가 잘못된 경우 그런 다음 u는 그것을 염두에두고 그것을 테스트 할 수 있습니다 .u는 "아 그러나 세터를 사용하는 경우 1 테스트 만하면됩니다"라고 말할 수 있지만 ur 코드는 변수에 나쁜 값을줍니다. 테스트와 함께 귀하의 테스트를 줄이십시오. n 테스트는 "
휴지

3

필드가 직접적으로 접근 가능한지 아니면 방법을 통해 접근 할 수 있는지 여부는 실제로 중요하지 않습니다.

클래스 불변 (유용한 것)이 중요합니다. 그리고 그것들을 보존하기 위해 때때로 외부에서 무언가를 바꿀 수 없어야합니다. 예 : 너비와 높이가 분리 된 Square 클래스가 있으면 그 중 하나를 변경하면 사각형이 아닌 다른 것이됩니다. 따라서 메소드 변경이 필요합니다. Rectangle 인 경우 setters / public 필드를 가질 수 있습니다. 그러나 0보다 큰지 테스트하는 것이 더 좋습니다.

그리고 구체적인 언어 (예 : java)로 우리가 그러한 메소드 (인터페이스)가 필요한 이유입니다. 방법의 또 다른 이유는 호환성 (소스 및 이진)입니다. 따라서 추가하기가 더 쉬워서 공공 장소가 충분한 지 생각합니다.

btw. 공개 최종 필드와 함께 간단한 불변 값 보유 클래스를 사용하고 싶습니다.


이것은 피해야 할 유일한 것입니다. 필드에서 속성 / 게터 / 세터로 이동하는 것은 대부분의 언어에서 중요한 변화입니다.
MrDosu

2

인터페이스를 동일하게 유지하면서 내부를 무엇이든 바꿀 수 있습니다. 인터페이스가 다양하지 않으면 코딩하지 않습니다. 당신은 여전히 ​​당신이 원하는대로 내부를 변경할 수 있습니다.


1
이 답변이 너무나 놀랐습니다. Getter 및 Setter를 사용하면 기존 API를 중단하지 않고 향후 더 많은 작업을 수행 할 수 있습니다 (예 : 이벤트 발생, 입력 유효성 검사 수행, 내부 부기 수행). 비공개 코드를 사용하더라도 변경해야하는 API 수가 적고 업데이트해야 할 종속성이 적으며 업데이트시 발생하는 버그가 적습니다.
AmadeusDrZaius

0

내 접근 방식은 이것입니다-

나중에 데이터와 함께 수수께끼를 기대할 때 getter / setter가 정당화됩니다. 또한 변경이 발생하면 종종 데이터를 getter / setter로 푸시합니다.

POD 구조라면 슬롯을 사용할 수 있습니다.

보다 추상적 인 수준에서 문제는 "데이터를 관리하는 사람"이며 프로젝트에 따라 다릅니다.


0

게터와 세터를 사용하는 것이 복잡하다고 생각되면 개념 자체가 아닌 언어 문제 일 수 있습니다.

다음 은 Ruby로 작성된 두 번째 예제 의 코드입니다 .

class Fridge
  attr_accessor :cheese
end

def go_shopping fridge
  fridge.cheese += 5
end

Java 의 첫 번째 예제 와 매우 비슷 합니까? 게터와 세터가 일류 시민으로 취급 될 때, 그들은 사용하기 힘든 일이 아니며, 추가 된 유연성이 때로는 실질적인 이익이 될 수 있습니다. 예를 들어, 새로운 냉장고에서 치즈의 기본값을 반환하기로 결정할 수 있습니다.

class Fridge
  attr_accessor :cheese

  def cheese
    @cheese || 0
  end
end

물론 공개적으로 노출되어서는 안되는 변수가 많이 있습니다. 내부 변수를 불필요하게 노출하면 코드가 더 나빠지지만 게터와 세터에서 그 코드를 탓할 수는 없습니다.


그것은 아름답게 언급되어 있습니다. 조리법을 점차적으로 구축하면서 불변의 객체를 만들고 싶기 때문에 빌더 기능이 추가되었습니다. 인공 감미료를 첨가하면 설탕을 첨가 할 필요가 없습니다. 명명 된 매개 변수를 사용하고 과부하가 걸리더라도 모든 작업을 수행하는 한 가지 방법을 만드는 것은 매우 어렵습니다. 그리고 물론 java는 매개 변수에 이름을 지정하지 않았으므로 사람들이 Builder 패턴을 사용하는 또 다른 이유입니다.
YoYo

0

Size너비와 높이를 캡슐화 하는 클래스를 고려하십시오 . 생성자를 사용하여 세터를 제거 할 수는 있지만 어떻게 사각형을 그리는 데 도움이 Size됩니까? 너비와 높이는 클래스의 내부 데이터가 아닙니다. 그들은 크기의 소비자가 사용할 수있는 공유 데이터입니다.

객체는 동작과 상태 또는 속성으로 구성됩니다. 노출 된 상태가 없으면 동작 만 공개됩니다.

상태가 없으면 개체 컬렉션을 어떻게 정렬 하시겠습니까? 객체의 특정 인스턴스를 어떻게 검색 하시겠습니까? 생성자 만 사용하는 경우 객체에 긴 속성 목록이 있으면 어떻게됩니까?

검증없이 메소드 매개 변수를 사용해서는 안됩니다. 따라서 쓰는 게으름입니다.

setMyField(int myField){
    this.myField = myField;
}

그런 식으로 쓰면 적어도 세터를 사용하여 유효성을 검사 할 준비가 된 것입니다. 공공 장소보다 낫지 만 간신히. 그러나 최소한 고객의 코드를 위반하지 않고 되돌아와 유효성 검사 규칙을 적용 할 수있는 일관된 공용 인터페이스가 있습니다.

게터, 세터, 프로퍼티, 뮤 테이터는 여러분이 원하는대로 부르지 만 필요합니다.


그러나 최소한 고객의 코드를 위반하지 않고 되돌아와 유효성 검사 규칙을 적용 할 수있는 일관된 공용 인터페이스가 있습니다. 그건 사실이 아니야. 도로 아래에 검증 규칙을 추가하면 "고객 코드가 손상 될 수 있습니다". int예를 들어 인스턴스 변수를 가져 와서 음수가 아닌 값만 허용하도록 유효성 검사 규칙을 추가하기로 결정했다고 가정 해보십시오. 문제는 고객의 코드가 이미 음수 값으로 설정할 가능성에 의존 할 수 있다는 것입니다.
jub0bs

0

게터와 세터가 캡슐화와 진정한 OO를 위반하면 심각한 문제가 발생합니다.

나는 항상 당신이 필요로하는 것이 무엇이든 마음에 드는 것을 나타내는 물체를 느꼈습니다.

Java로 Maze를 생성하는 프로그램 작성을 마쳤으며 "Maze Squares"를 나타내는 클래스가 있습니다. 이 클래스에는 좌표, 벽 및 부울 등을 나타내는 데이터가 있습니다.

이 데이터를 변경 / 조작 / 액세스 할 수있는 방법이 필요합니다! 게터와 세터없이 무엇을해야합니까? Java는 속성을 사용하지 않으며이 클래스에 로컬 인 모든 데이터를 public으로 설정하는 것은 분명히 캡슐화 및 OO의 위반입니다.


6
질문은 다음과 같습니다. 모든 필드를 공개하고 getter 및 setter 사용을 중단하면 코드가 어떻게 다릅니 까?
Winston Ewert

이론적으로는 그렇지 않습니다. 그 시점에서 수업을하는 이유는 무엇입니까? 무엇이든 같은 주장을 할 수 있습니다. 그러나 내 아래의 게시물은 더 우아하게 말한 것 같습니다. Getter와 Setter는 개체에 값을 안전하게 전달하거나 해당 개체에서 값을 검색하는 방법입니다. 게시물은 계속됩니다.
Bryan Harrington

3
나는 지적했다. 그 포스터는 결국 나와 동의했고 그 효과에 대한 또 다른 대답을 게시했다. 기본적으로 게터와 세터를 사용하는 것은 데이터를 직접 조작하는 것과 같습니다. 그렇게함으로써 OOness를 얻을 수는 없습니다. OO가 되려면 데이터에 대한 더 높은 수준의 인터페이스를 제공해야합니다.
Winston Ewert

4
나는 그것을 설명하는 가장 좋은 방법은 내부가 아닌 외부에서 인터페이스를 디자인해야한다고 말하는 것입니다. 객체가 제공하는 인터페이스는 객체가 어떻게 구현되는지가 아니라 어떻게 사용되는지에 따라 결정되어야합니다. 따라서 getter를 작성하지 말고 외부 객체가 데이터를 해석하도록 허용하십시오. 그들이 어떤 질문에 대답해야하는지 찾고 그 질문에 대답하는 방법을 쓰십시오. 외부 객체가 setter에 의해 상태를 수정하는 것을 허용하지 말고 어떤 종류의 조작을 수행해야하는지 확인하고이를 수행하는 메소드를 작성하십시오.
Winston Ewert

2
경우에 따라 Getter 및 Setter가 가장 좋은 방법입니다. 때로는 제공 할 수있는 최상의 인터페이스입니다. 그러나 많은 경우에 그렇지 않습니다. 대부분의 경우 구현 세부 정보를 다른 클래스로 유출하고 있습니다.
Winston Ewert

-1

첫째, 가치와 서비스 유형이라는 두 가지 유형의 객체가 있습니다.

서비스 유형에는 setter가 없어야합니다. 필요한 종속성은 gettable이 아니어야합니다. 종속성을 전달하는 가장 좋은 방법은 생성자 또는 팩토리를 통해 모든 인스턴스가 처음부터 평범하고 단순하게 완전히 구성되는 방식입니다.

ORM과 같이 실용적이지 않거나 위젯에서 객체로의 다른 매핑과 같은 실용적이지 않은 경우도 있습니다. 한 계층에서 다른 계층으로 시스템을 통과하는 다른 모든 값 유형은 변경할 수 없으며 설정자가 없어야합니다.


하나 이상의 값을 보유하는 것이 목적인 가변 컨테이너; 대부분의 경우 컨테이너에 논리 또는 유효성 검사 방식이 많이 필요하지 않아야합니다. 6 개의 양의 정수를 계산하기위한 방법을 필요로하는 코드는 6 개의 정수를위한 컨테이너를 그 결과를 저장할 방법으로 전달할 수있다. 숫자가 양수인지 확인하는 책임은 일반적으로 컨테이너가 아닌 호출자 또는 호출 된 메소드에 있어야합니다.
supercat

-1

Getter / Setter는 다른 공용 메소드와 마찬가지로 정당화됩니다. 정당화는 주로 클래스가 다른 클래스와 상호 작용하는 방식을 정의하는 인터페이스를 외부 세계에 제공하려고하기 때문입니다. 우리는 주로 별도의 엔티티 사이의 커플 링을 줄이려고하기 때문에이를 수행합니다. 여러 가지 이유로 커플 링을 줄이는 것이 좋습니다.

  • 현재 클래스에서 동일한 클래스 인터페이스를 사용할 수 있지만 그 동안 클래스에는 새로운 메소드가 추가되었지만 이전 인터페이스는 유지됩니다.
  • 소비자에게 영향을 미치지 않고 클래스의 내부 표현을 변경할 수 있습니다
  • 버그 발생 가능성 감소 : 내부 데이터를 비공개로 설정하면 외부 코드가 내부 데이터와 충돌하지 않는지 확인할 수 있습니다.

-1

예, getter 및 setter는 객체 지향 프로그래밍의 반 패턴이며 http://www.yegor256.com/2014/09/16/getters-and-setters-are-evil.html 과 같이 사용 해서는 안됩니다 . 간단히 말해서, 객체 지향 패러다임에는 적합하지 않습니다. 데이터 구조처럼 객체를 처리하도록 권장하기 때문입니다. 이것은 중요한 오해입니다.


2
이것은 이전의 18 답변에서 만들어지고 설명 된 점에 비해 실질적인 것을 제공하지 않는 것 같습니다
gnat

4
그것도 결코 말하지 않는 것이 좋습니다.
Winston Ewert

-4

프로그래밍 언어 자동 생성을 개발하는 회사가 개발 한 IDE가 "객체 지향의 원칙"을 위반하지 않기를 바랍니다.

즉, 공개 범위 변수가있을 때마다 게터와 세터를 사용하면 황금색입니다. 마치 엄청나게 많은 코드처럼 보일지라도 캡슐화의 객체 지향 원칙의 필수 요소 인 것 같습니다.

그것들을 사용하는 이유는 적절한 캡슐화가 아직 이루어질 수 있고 객체를 원숭이가 객체를 느끼는 사람이 객체를 느끼게하는 레이어를 추상화하지 않는 한 올바르게 알지 않고도 객체를 가져갈 수 있기 때문입니까?

충분히 말하면, 분할 된 주택은 참을 수 없으며 OO의 입주자 중 하나는 스스로 켜지지 않으며 캡슐화와 조기 최적화를 모두 제공 할 수 없습니다.


4
변수를 다룰 때마다 setFoo () 및 getFoo ()를 호출하는 많은 코드를 추가하여 정확히 무엇을 얻었습니까?
Winston Ewert

7
여기에 캡슐화가 있다고 생각하지 않습니다. 여전히 다른 곳에서 객체의 상태를 조작하고 있습니다. 당신은 그것을 더 장황하게하고 있습니다. 캡슐화를 얻으려면 해당 값을 소유 한 클래스의 값 조작을 중앙 집중화해야합니다. 다른 것은 OO 의류의 절차 코드 일뿐입니다. (그것에 반드시 잘못된 것은 없지만 그것이 무엇입니까).
Winston Ewert

2
캡슐화의 장점은 특정 값과 관련된 모든 논리가 한곳에 있다는 것입니다. 나는 게터와 세터로 그것을 얻지 못한다. 따라서 나는 그들에게 많은 이익을 얻는다고 생각하지 않습니다.
Winston Ewert

1
그러나 getter 및 setter가있는 코드를 사용하고 공개 액세스를 통해 자유롭게 데이터를 조작하는 코드가 있음에 동의합니다. 그렇게하면 최소한 들어오는 데이터의 유효성 검사를 첨부 할 수 있습니다.
Winston Ewert

3
나는 확실히 장황한 팬이 아니다. 그러나 내 이의는 실제로 변수를 비공개로 만들고 게터와 세터를 호출하여 아무런 차이없이 자유롭게 끝나는 사람들입니다. 클래스 내에서 getter / setter를 사용하려면 괜찮습니다. 문제는 왜? 내가 알고있는 주요 이점은 데이터에 대해 약간의 유효성 검사를 수행하여 오류를 일찍 포착 할 수 있다는 것입니다. 데이터를 조작하는 모든 코드가 같은 위치에있을 때는 도움이되지 않습니다. 그러나 여전히 도움이 될 수 있습니다. 이상적으로는 속성을 지원하고 자세한 정보를 피할 수있는 언어가 있습니다.
Winston Ewert

-4

나는 우리가 여기에 더 일반적인 대답을 줄 것이라고 생각 했습니까?

게터와 세터는 일반적으로 매우 OOP입니다 (다른 것을 잘못 말하는 사람은 그렇게 간단합니다).

오버 엔지니어링을하지 않아도된다는 것을 기억해야하지만 필요없는 게터 나 세터를 만들지 마십시오. 다른 클래스에서 사용하지 않을 정보는 getter 또는 setter가 없어야합니다.

하지만 필드를 공개하지 않고 게터와 세터가있는 이유는 대부분 다음과 같습니다.

  • 필드를 사용하여 적절한 테스트를 수행 할 수 없습니다. 그런 점에서 게터 / 세터가 훨씬 좋습니다.

  • 실시간 프로그래밍 설정에서 필드를 올바르게 사용하는 것은 불가능합니다. 동기화 된 게터 / 세터가 갈 길입니다.

  • 인터페이스 주제 (이미 설명하지 않았으므로).

  • 시스템을 올바르게 재사용 할 때 사용하기가 더 쉽습니다.

  • 클래스를 사용하는 클래스와 getter / setter보다 필드를 변경하면 어떤 클래스가 중단되는지 알기가 훨씬 어렵습니다.

따라서 게터 / 세터 대신 퍼블릭 필드를 사용하는 유일한 경우는 공식 프로젝트를 만들지 않고 단지 재미를 위해 게터를 쓰거나 게터 / 세터를 방해 할 수없는 경우입니다.


2
테스트 가능성 +1 아무도 언급하지 않았다는 사실에 충격을 받았습니다. 속성의 또 다른 유용한 기능은 디버깅입니다. 필드에 하드웨어 / 메모리 중단 점을 요구하는 것보다 코드에 중단 점을 삽입하는 것이 훨씬 쉽습니다.
Mark H

9
게터와 세터에 대한 반대는 정신과 의도를 무시하면서 종종 OOP 법의 서한을 따르는 데 사용된다는 것입니다. OOP에 따르면 다른 물체가 내부와 뭉쳐서는 안된다고한다. 어쨌든 그렇게 할 수있는 게터와 세터를 정의하면 결국 OOP를 위반하게됩니다.
Winston Ewert

6
나는 단순한 공공 장소에 비해 게터와 세터의 많은 이점이 있음에 동의합니다. 그러나 테스트가 어떻게 더 나은지 잘 모르겠습니다. 설명해 주시겠습니까?
Winston Ewert

4
@Skarion : 나는 당신의 대답에 동의하지 않습니다. 게터 / 세터를 사용하거나 필드를 공개하는 두 가지 대안을 제시하는 것 같습니다. 그러나 세 번째 옵션이 있습니다. getter / setter를 사용하거나 필드를 노출하지 않는 것입니다! 내부 필드의 상태를 테스트해야하는 이유는 무엇입니까? 객체의 퍼블릭 API를 테스트해서는 안됩니까?
Andres F.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.