클래스의 메소드가 자체 getter 및 setter를 호출해야합니까?


53

내가 일하는 곳에서 다음과 같은 일을하는 많은 수업을 봅니다.

public class ClassThatCallsItsOwnGettersAndSetters {

    private String field;

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }

    public void methodWithLogic() {
        setField("value");
        //do stuff
        String localField = getField();
        //do stuff with "localField"
    }
}

이것을 처음부터 작성했다면 methodWithLogic()대신 다음과 같이 작성했을 것입니다.

public class ClassThatUsesItsOwnFields {

    private String field;

    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }

    public void methodWithLogic() {
        field = "value";
        //do stuff            
        //do stuff with "field"
    }
}

클래스가 자체 getter 및 setter를 호출하면 코드를 읽기가 더 어려워집니다. 나에게 그것은 거의 우리의 경우에 결코 그렇지 않더라도 그 메소드 호출에서 복잡한 논리가 일어나고 있음 을 거의 암시 합니다. 익숙하지 않은 코드를 디버깅 할 때 버그가 해당 방법에서 부작용이 아니라고 말하는 사람은 누구입니까? 다시 말해, 코드를 이해하는 여정에서 많은 사이드 트립을 수행하게됩니다.

첫 번째 방법에는 이점이 있습니까? 첫 번째 방법이 실제로 더 낫습니까?


익숙하지 않은 코드를 디버깅 할 때 버그가 해당 방법에서 부작용이 아니라고 말하는 사람은 누구입니까? 당신의 단위 테스트. :)
Joshua Taylor

1
내부 코드에서 getter / setter를 사용하면 디버거를 사용하여 코드에서 중단 점을 만들 수 있습니다. 또한 설정 / 값 가져 오기 설정에 문제가있는 경우 잘못된 액세스 때문이 아니라 해당 방법으로 인한 것임을 알 수 있습니다. 전반적으로 더 많은 일관성 코드를 제공합니다.
callyalater

답변:


46

어느 쪽이 더 나은지 나쁜지는 말하지 않을 것입니다. 그러나 게터와 세터가 나중에 구현을 변경하고 무시하면 해당 논리를 건너 뛸 수 있습니다.

예를 들어, 나중에 일부 세터 필드에 "dirty"플래그를 추가하면 어떻게됩니까? 내부 코드에서 setter를 호출하면 다른 코드를 변경하지 않고 dirty 플래그를 설정합니다. 많은 상황에서 이것은 좋은 일입니다.


그러나 백엔드에서 데이터를 초기화 할 때 데이터가 더티로 해석되기를 원하지 않는 경우는 어떻습니까? 당신이 전화하면 setField()처음부터 그냥 버그를 소개했다.
Daniel Kaplan

6
그렇기 때문에 부분적으로 상황에 따라 달라집니다. 데이터 초기화가 설정자를 건너 뛰어야하지만 다른 논리 코드는 건너 뛰어야합니다. 적절한 규칙을 선택하고 준수하십시오.
Matt S

3
@DanielKaplan : 요점은 게터와 세터를 호출하는 것이 대부분의 경우 올바른 일이며, 특정 상황에서만 그렇지 않다는 것입니다. 그러나 실제 코드에서는 나중에 기존의 getter / setter 구현을 변경하여 의도적 인 부작용을 유발할 때 클래스 내부의 getter 또는 setter에 대한 모든 호출과 클래스에 대한 모든 직접 액세스를 확인해야합니다. 들. 그렇기 때문에 수업을 최대한 작게 유지해야합니다.
Doc Brown

33

세터를 직접 호출하는 것은 그 자체로는 문제가되지 않습니다. 문제는 실제로 다음과 같습니다. 왜 우리 코드에 세터가 있습니까?

가변 클래스는 위험한 게임이며, 특히 클래스 자체가 자체 상태를 관리하는 경우에 효과적입니다. 그러한 세터 중 몇 명이 실제로 존재해야하는지 고려하십시오. 생성자에 몇 개를 설정 한 다음 클래스 자체로 완전히 캡슐화 할 수 있습니까?

필드를 외부에서 설정할 수 있어야하는 경우 논리가있는 방법이 있는지 스스로에게 물어보십시오. 수업 자체가 데이터 / 주 수업입니까? 이 수업에는 두 가지 이상의 책임이 있습니까?

나를 잘못 이해하지 마십시오. 이것이 좋은 경우가 있습니다. 나는 논리가있는 클래스의 setter를 완전히 제거해야한다고 말하지 않습니다. 그러나 이것들은 예외가 아니라 규칙입니다. 그리고 그러한 경우에는 직접 액세스 할 수 있어야합니다.


1
나는이 사고 방식에 전적으로 동의 / 연습합니다. 또한 내 질문보다 사실 더 중요한 점을 제시한다고 생각합니다. 즉, 원래 질문에 직접 대답하는 것처럼 느끼지 않습니다. 당신이 말하지 않는 한, "당신의 질문은 중요하지 않은 사물의 제도에서". :)
Daniel Kaplan

@DanielKaplan : 정확히 말하고 있습니다. :) 나는 이것에 대한 대답과 의견 사이에서 찢어졌지만 더 큰 질문을하지 않는 정답이 있다고 생각하지 않습니다.
pdr

9

예, 클래스의 메소드는 getter 및 setter를 호출해야합니다. 게터와 세터를 작성하는 요점은 미래의 증거입니다. 모든 속성을 필드로 만들고 데이터를 클래스의 사용자에게 직접 노출 할 수 있습니다. getter와 setter를 빌드하는 이유는 복잡한 논리가 있기 때문에 꼭 필요한 것은 아니지만 나중에 인터페이스를 추가해야 인터페이스가 중단되지 않기 때문입니다.


1
첫 문장과 나머지 문장 사이의 관계가 보이지 않습니다. 첫 번째 문장은 클래스가 자체 getter 및 setter를 호출해야한다고 말합니다 . 이 단락의 나머지 부분에서는 클라이언트 코드 (예 : 클래스를 사용하는 코드)가 필드에 직접 액세스하는 대신 getter 및 setter를 사용해야하는 이유를 설명합니다 . 그러나 클래스가 자체 필드에 직접 액세스해서는 안되는 이유를 알 수 없습니다 .
Daniel Kaplan

1
@DanielKaplan 내 요점은 이유가 하나이고 같다는 것입니다. 나중에 setter 로직을 추가하면 잠재적으로 외부 코드만큼 내부 코드에 영향을 미칩니다.
Michael

2
@Michael : 클래스가 자체 getter / setter를 사용하지 않는 이유는 종종 있습니다. 하나의 일반적인 시나리오는 양식의 많은 세터가있는 someField=newValue; refresh(); 경우입니다. 메소드가 여러 필드를 설정할 수있는 경우 해당 필드를 작성하기 위해 세터를 호출하면 중복 "새로 고침"조작이 발생합니다. 모든 필드를 작성하고 한 refresh()번만 호출 하면보다 효율적이고 부드럽게 작동 할 수 있습니다.
supercat

6

한마디로 질문에 대답하기 위해 그렇습니다.

클래스에 자체 getter 및 setter를 호출하면 확장 성이 추가되고 향후 코드를위한 더 나은 기반이 제공됩니다.

다음과 같은 것이 있다고 가정하십시오.

public class Vehicle
{
    private int year;
    private String make;

    public Vehicle(int year, String make)
    {
        setYear(year);
        setMake(make);
    }

    public void setYear(int year)
    {
        this.year = year;
    }

    public void setMake(String make)
    {
        this.make = make;
    }
}

1 년 동안 setter를 호출하고 현재 make는 기능을 추가하지 않을 수 있지만 setter에 입력 유효성 검증과 같은 것을 추가하려면 어떻게해야합니까?

public class Vehicle
{
    private int year;
    private String make;

    public Vehicle(int year, String make)
    {
        setYear(year);
        setMake(make);
    }

    public void setYear(int year)
    {
        if(year > 0)
        {
            this.year = year;
        }
        else
        {
            System.out.println(year + " is not a valid year!");
        }
    }

    public void setMake(String make)
    {
        this.make = make;
    }
}

5

언급되지 않은 한 가지는 getter 및 setter (모든 메소드)가 Java에서 가상이라는 것입니다. 이렇게하면 코드에서 항상 사용할 수있는 다른 기능이 추가됩니다. 다른 사용자가 클래스를 확장하여 게터와 세터를 덮어 쓸 수 있습니다. 그러면 기본 클래스는 자체 클래스 대신 서브 클래스의 데이터를 사용합니다. 가상 함수를 명시 적으로 표시하는 언어에서는이를 수행 할 수있는 함수를 예측하고 선언 할 수 있으므로 훨씬 편리합니다. Java에서는 항상 알아야 할 사항입니다. 원하는 동작이라면 코드에서 사용하는 것이 좋습니다. 그렇지 않으면 그렇게 많이하지 않습니다.


3

공용 인터페이스에서 제공하는 것을 달성하려는 경우 getter / setter를 사용하십시오.

그러나 강의의 소유자 / 개발자로서 강의 내에서 코드의 개인 섹션에 액세스 할 수는 있지만 위험을 완화 할 책임도 있습니다.

따라서 내부 목록을 반복하는 게터가 있고 반복기를 늘리지 않고 현재 값을 얻으려고합니다. 이 경우 개인 변수를 사용하십시오.

public class MyClass
{
    private int i;
    private List<string> list;
    public string getNextString()
    {
        i++;
        return list[i];
    }

    private void getString()
    {
        // Do not increment
        string currentString = list[i];

        // Increment
        string nextString = getNextString();
    }
}

이것에 대한 추론을 줄 수 있습니까?
Daniel Kaplan

1

예. 게터와 세터는 상태를 나타내므로이 질문을 돌리십시오. 필요한 경우가 아니라면 동일한 방법으로 객체 상태를 변경하는 여러 가지 방법을 추적해야합니까?

더 잘 추적해야 할 것이 적을수록 불변의 객체를 다루기가 더 쉬워집니다.

공공 장소와 공공 게터 / 세터를 둘 다 막는 데는 아무런 어려움이 없습니다.하지만 무엇을 얻을 것입니까?

계기로 될 수있다 바람직 당신은 무슨 일이 생기면 것을 멀리 부끄러워하지 말아야 직접 하나 이상의 이유로 필드에 액세스 할 수 또는 필요. 그러나 정의 된 이점이있는 경우에만 그렇게해야합니다.


내 질문의 요점은 같은 클래스의 필드에 직접 액세스하는 것만 요구 한다는 것 입니다. 클라이언트 코드에 대한 getter 및 setter의 목적을 이미 이해하고 있습니다.
Daniel Kaplan

@DanielKaplan : 나는 그것을 이해하고 있으며, 내가 말하는 것은 실제로 가능한 한 동일하게 취급해야한다는 것입니다.
jmoreno

@DanielKaplan : 하나 이상의 개인 세터와 하나의 공개 세터를 가질 수 있습니다. 최소한 숙달에 대해 동일한 결과 (모든 부작용은 동일)가 있지만 물건을 발산시킬 가능성 이외의 다른 이점은 무엇입니까? 이 시나리오와 당신이 설명의 차이는 것을 피할 수 있다는 것입니다 게터 / 세터의 외부 상태에 액세스 할 수 있지만 실제로 그렇게 피할 수 있습니다. 필요한 경우가 아니면 코드를 복잡하게 만들지 마십시오.
jmoreno

1

두 방법 모두 유스 케이스가 있습니다. 퍼블릭 세터는 필드 값 (및 / 또는 바운드 값)의 일관성을 유지하므로 메소드 논리가이 일관성 논리를 방해하지 않는 경우 세터를 사용해야합니다. "속성"을 설정 한 경우 setter를 사용하십시오. 반면에 일부 설정에 직접 액세스해야하는 상황이 있습니다 (예 : 무거운 세터를 사용한 대량 작업 또는 세터 개념이 너무 간단한 작업).

일관된 상태를 유지하는 것은 귀하의 책임입니다. Setter는 정의에 따라이 작업을 수행하지만 복잡한 경우는 다루지 않습니다.


1

나는 아니오라고 말할 것입니다.

게터 / 세터가 단지 게으른 초기화, 검사 없음 등을 얻고 설정 한 경우 변수를 사용하십시오. 나중에 getter / setter를 변경하면 변경되는 methodWithLogic()클래스 때문에 매우 잘 변경할 수 있으며 직접 할당 대신 getter / setter를 호출 할 수 있습니다. getter / setter에 대한이 호출을 문서화 할 수 있습니다 (나머지 클래스 코드가 변수를 직접 사용하는 경우 getter / setter를 호출하는 것이 이상 할 수 있음).

JVM은 getter / setter에 대한 빈번한 호출을 인라인합니다. 따라서 결코 성능 문제가 아닙니다. 변수 사용의 이점은 가독성과 IMHO입니다.

도움이 되었기를 바랍니다..

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