문제

이 질문은 이미 여기에 답이 있습니다.

저는 현재 몇 가지 다른 모드로 Java의 간단한 게임 작업을하고 있습니다. 기본 게임 클래스를 확장하여 다른 클래스 내에 주요 논리를 넣었습니다. 그럼에도 불구하고, 메인 게임 클래스는 여전히 꽤 무겁습니다.

내 코드를 간단히 살펴본 후 대부분의 코드는 게임의 논리에 실제로 필요한 나머지와 비교하여 Getters and Setter (60%)였습니다.

Google 검색의 두 가지 검색은 Getters와 Setter가 악하다고 주장한 반면, 다른 사람들은 훌륭한 OO 연습과 훌륭한 프로그램에 필요하다고 주장했습니다.

그래서, 내가 뭘해야 해? 어느 것이되어야합니까? 개인 변수를 위해 내 getters와 setter를 변경해야합니까, 아니면 고수해야합니까?

도움이 되었습니까?

해결책

세터를 사용하여 대부분의 시간에 의미가없는 값을 설정할 수있게하여 캡슐화를 중단 시킨다는 관점도 있습니다. 매우 명백한 예로서, 게임에 대한 점수 카운터가 있다면

// Game
private int score;
public void setScore(int score) { this.score = score; }
public int getScore() { return score; }
// Usage
game.setScore(game.getScore() + ENEMY_DESTROYED_SCORE);

그것은해야한다

// Game
private int score;
public int getScore() { return score; }
public void addScore(int delta) { score += delta; }
// Usage
game.addScore(ENEMY_DESTROYED_SCORE);

이것은 아마도 약간의 용이 한 예일 것입니다. 내가 말하려는 것은 Getter/Setters vs Public Fields를 논의하는 것이 종종 서로의 내부 상태를 친밀한 방식으로 조작하여 너무 밀접하게 결합 된 개체의 더 큰 문제를 모호하게한다는 것입니다.

아이디어는 원하는 일을 직접 수행하는 방법을 만드는 것입니다. 예는 적의 "살아있는"상태를 설정하는 방법입니다. 당신은 세정 (부울) 방법을 갖고 싶은 유혹을받을 수 있습니다. 대신 : 당신은 다음과 같아야합니다.

private boolean alive = true;
public boolean isAlive() { return alive; }
public void kill() { alive = false; }

그 이유는 물건이 더 이상 "살아있는"부울이 아니라 "히트 포인트"값을 갖지 않는 구현을 변경하면 이전에 쓴 두 가지 방법의 계약을 중단하지 않고도이를 변경할 수 있기 때문입니다.

private int hp; // Set in constructor.
public boolean isAlive() { return hp > 0; } // Same method signature.
public void kill() { hp = 0; } // Same method signature.
public void damage(int damage) { hp -= damage; }

다른 팁

  • 매우 악 : 공공 분야.
  • 다소 악 : 필요하지 않은 곳에있는 getters and setter.
  • 양호 : 실제로 필요한 경우에만 getters and setter- 유형을 노출시켜 "더 큰"동작을 노출시킵니다. 사용 유형을 다른 유형에 의해 조작 할 상태의 저장소로 취급하는 것이 아니라 그 상태.

그것은 실제로 상황에 달려 있습니다 - 때로는 당신은 정말로 하다 바보 같은 데이터 객체를 원합니다.

당신은 이미 이것에 대해 많은 좋은 답변을 가지고 있었으므로 2 센트 만 줄 것입니다. getters와 setters는 매우, 매우 사악합니다. 그들은 본질적으로 당신이 한 모든 시간이 내부 상태를 숨기지 않는 중복 코드로 던져 질 때 객체의 내부를 숨기는 척합니다. 간단한 pojo의 경우 getName () 및 setName ()를 obj.name = "tom"으로 바꿀 수없는 이유가 없습니다.

메소드 호출이 단지 할당을 대체하는 경우, 메소드 호출을 선호하여 얻은 모든 것은 Code Bloat입니다. 불행히도, 언어는 Javabeans 사양에서 getters and setters의 사용을 모색 했으므로 Java 프로그래머는이를 사용해야합니다.

다행히도 Eclipse (및 다른 IDE도)를 사용하면 자동으로이를 생성 할 수 있습니다. 그리고 재미있는 프로젝트를 위해, 나는 한 번 XSLT에서 그들을 위해 코드-제너레이터를 만들었습니다. 그러나 Java에서 내가 제거 할 것이 있다면, 그 getters and setters에 대한 과도한 의존성입니다.

getters and setters는 개념을 시행합니다 캡슐화 객체 지향 프로그래밍에서.

대상의 상태가 외부 세계에서 숨겨져 있으면 대상은 진정으로 그 자체를 담당하며 의도하지 않은 방식으로 변경 될 수 없습니다. 객체를 조작 할 수있는 유일한 방법은 게터 및 세터와 같은 노출 된 공개 방법을 통해서입니다.

게터와 세터를 갖는 데 몇 가지 장점이 있습니다.

1. 수정 된 클래스를 사용하는 코드에 대한 수정없이 향후 변경을 허용합니다.

Getter and Setter를 사용하는 큰 장점 중 하나는 일단 공개 방법이 정의되고 기본 구현이 변경되어야 할 때가 발생한다는 것입니다 (예 : 성능 향상을 위해 다른 알고리즘을 사용하여 고정 해야하는 버그를 찾는 버그를 찾는 것입니다. 등), getters와 setter가 객체를 조작하는 유일한 방법이되면, 기존 코드가 깨지지 않고 변경 후에도 예상대로 작동합니다.

예를 들어, a가 있다고 가정 해 봅시다 setValue 설정하는 메소드 value 객체의 개인 변수 :

public void setValue(int value)
{
    this.value = value;
}

그러나 횟수를 추적 해야하는 새로운 요구 사항이있었습니다. value 변경되었습니다. 세터가 제정되면 변화는 상당히 사소합니다.

public void setValue(int value)
{
    this.value = value;
    count++;
}

만약 value 필드는 공개적이었고 나중에 다시 돌아올 수있는 쉬운 방법이없고 값이 변경된 횟수를 추적하는 카운터를 추가합니다. 따라서 게터와 세터를 갖는 것은 나중에 올 수있는 변화에 대한 클래스를 "미래 방지"하는 한 가지 방법입니다.

2. 물체를 조작 할 수있는 수단을 시행합니다.

getters와 setter가 편리하게 오는 또 다른 방법은 객체를 조작 할 수있는 방법을 시행하는 것입니다. 따라서 객체는 자체 상태를 제어합니다. 객체의 공개 변수가 노출되면 쉽게 손상 될 수 있습니다.

예를 들어, an ImmutableArray 객체에는 an이 포함되어 있습니다 int 배열이 호출되었습니다 myArray. 배열이 공공 분야라면 불변은 아닙니다.

ImmutableArray a = new ImmutableArray();
int[] b = a.myArray;
b[0] = 10;      // Oops, the ImmutableArray a's contents have been changed.

진정으로 불변의 배열을 구현하려면 배열을위한 getter (getArray 메소드)는 배열의 사본을 반환 할 수 있도록 작성해야합니다.

public int[] getArray()
{
    return myArray.clone();
}

그리고 다음이 발생하더라도 :

ImmutableArray a = new ImmutableArray();
int[] b = a.getArray();
b[0] = 10;      // No problem, only the copy of the array is affected.

그만큼 ImmutableArray 참으로 불변입니다. 객체의 변수를 노출 시키면 의도하지 않은 방식으로 조작 될 수 있지만 특정 방식 (getters and setters) 만 노출 할 수있게되면 객체는 의도 된 방식으로 조작 될 수 있습니다.

나는 Getters와 Setter가 다른 사람들이 사용할 API의 일부인 클래스에 더 중요 할 것이라고 생각합니다. 기본 구현의 변경을 허용하면서 API를 그대로 유지하고 변경하지 않도록 할 수 있기 때문입니다.

Getters and Setters의 모든 장점과 함께, Getter가 단순히 개인 변수의 가치를 반환하고 세터가 단순히 값을 받아들이고 개인 변수에 할당하는 경우, Getters와 Setter는 단지 외부인 것처럼 보입니다. 쓰레기. 클래스가 다른 사람이 사용하지 않을 애플리케이션으로 내부 사용을위한 경우, 공개 API를 작성할 때는 getters and setter를 광범위하게 사용하는 것이 중요하지 않을 수 있습니다.

그들은 절대적으로 악합니다.

불행히도 그들은 절대적으로 "캡슐화의 개념을 시행"하지 않습니다. 실제로 메서드 웅장한 망상으로 속성을 통해 데이터를 노출 할 때 데이터를 캡슐화한다고 생각하게됩니다. getter/setter가 공공 분야를 더 잘하는 것은 더 나은 것입니다.

먼저, 공개 데이터를 원한다면 공개적으로 공개하고, Getter & Setter 방법을 제거하여 클라이언트가 통과 해야하는 방법의 수를 줄이고 클라이언트가 예를 들어 클라이언트가 값을 변경하는 것이인지 적으로 더 간단하게 만듭니다.

object.field = value;

더인지 적으로 강렬한 대신

object.setField(value);

클라이언트가 이제 Getter/Setter 메소드를 확인하여 부작용이 있는지 확인해야합니다.

둘째, 방법에서 다른 작업을 수행해야한다면, 단순히 얻거나 설정하는 것보다 더 많은 책임이있는 경우 GET/SET 메소드라고 부르는 이유는 무엇입니까? SRP를 따르거나 실제로 알려주는 메소드를 호출하십시오. 전부의 방법은 그가 언급 한 Zarkonnen의 예를 좋아합니다.

public void kill(){
    isAlive = false;
    removeFromWorld(this);
}

대신에

public void setAlive(boolean isAlive){
    this.isAlive = isAlive;
    if (isAlive)
        addToWorld(this);
    else
        removeFromWorld(this);
}

setalive (boolean) 방법은 클라이언트에게 부작용으로 세상에서 객체를 제거 할 것이라고 말합니다. 고객이 Isalive 필드에 대한 지식이 있어야하는 이유는 무엇입니까? 또한 물체가 세상에 다시 구분되면 어떻게됩니까? 고객이 왜 그 중 어떤 것에 대해 관심을 가질까요?

IMHO 도덕은 자신이하는 일을 정확하게 말하고 SRP를 따르고 게터/세터를 제거하는 방법을 지명하는 것입니다. getters/setters가없는 문제가 있다면, 다른 수업에서 그들과 일을하려고하는 대신 자신의 수업 내에서 자신의 더러운 작업을 수행하도록 물체에 말하십시오.

여기에 내 분노가 끝나고, 죄송합니다;)

미끄러운 경사입니다.

간단한 전송 객체 (또는 매개 변수 개체)는 일부 필드를 보유하고 주문시 값을 제공하는 유일한 목적을 가질 수 있습니다. 그러나 그 퇴화 된 경우에도 객체는 불변이되어야한다고 주장 할 수 있습니다. 생성자에 구성되고 get... 방법.

"제어 손잡이"를 노출시키는 클래스의 경우도 있습니다. 자동차 라디오의 UI는 아마도 getVolume, setVolume, getChannel, 그리고 setChannel, 그러나 실제 기능은 신호를 받고 사운드를 방출하는 것입니다. 그러나 이러한 손잡이는 많은 구현 세부 사항을 노출시키지 않습니다. 라디오가 트랜지스터, 주로 소프트웨어 또는 진공 튜브인지 여부에 관계없이 이러한 인터페이스 기능에서 알 수 없습니다.

대상을 문제 도메인 과제에 적극적으로 참여할수록 더 많이 묻는 관점에서 더 많이 생각할 것입니다. 뭔가를하십시오 내부 상태에 대해 말해달라고 요청하거나 데이터를 요청하는 대신 다른 코드 그 가치로 무언가를 할 수 있습니다.

그래서 ... "사악한"? 설마. 그러나 당신이 가치를 높이고 두 가지를 노출시키는 경향이있을 때마다 get... 그리고 set... 그 값에 대한 방법, 그 이유와 그 객체의 반복성이 무엇인지 스스로에게 물어보십시오. 당신이 스스로 줄 수있는 유일한 대답이 "나를 위해이 가치를 유지하는 것"이라면, 아마도 OO 외에 무언가가 여기에서 진행되고 있습니다.

당신의 게임 클래스는 아마도 다음을 따르고있을 것입니다 신의 대상 많은 변수를 노출시키는 경우 antipattern. getters and setters에는 아무런 문제가 없습니다 (Java에서의 구두는 약간 성 가실 수 있습니다). 각 클래스에 명확하게 분리 된 기능이있는 잘 디자인 된 앱에서는 단일 클래스에서 수십 개가 필요하지 않습니다.

편집하다: Getters and Setters의 주요 요점이 게임 Classe를 "구성"하는 것이라면 (그런 식으로 귀하의 의견을 이해합니다), Getters가 필요하지 않을 것입니다 (클래스가 사용하지 않고 자신의 개인 변수에 액세스하는 것이 완벽합니다. 메소드를 얻습니다), 아마도 많은 세터를 개념적으로 함께 속하는 여러 변수를 설정하는 "그룹 세터"로 무너질 수 있습니다.

게터와 세터의 존재는 디자인 문제가 있음을 (이런 종류의 초등학교 언어에 있다면) ( "냄새")를 나타냅니다. 사소한 게터와 세터는 공공 분야와 거의 구별 할 수 없습니다. 일반적으로 데이터에서 작동하는 코드는 다른 클래스에 있습니다. 캡슐화가 열악하고 프로그래머가 OO로 쉽게 쉽게 쉽게 만들 수 없게됩니다.

어떤 경우에는 getter와 setter가 괜찮습니다. 그러나 원칙적으로 Getters와 Setters가있는 유형은 설계 문제를 나타냅니다. getters는 불변성을 위해 일합니다. 셋터는 "Tell Do n't Ask"에 대해 작동합니다. 불변성과 "Tell Do n't Ask"는 모두 겹치는 스타일로 적용되지 않는 한 좋은 디자인 선택입니다.

내 의견은 Getters와 Setter가 좋은 프로그램의 요구 사항이라는 것입니다. 그것들을 고수하지만 불필요한 getters/setters를 쓰지 마십시오. 모든 변수를 직접 처리 할 필요는 없습니다.

나는 그들이 실제로 악하다고 생각하지 않습니다. 그러나 나는 내가 정말로 필요하지 않으면 내가 그들을 사용할 필요가없는 세상에 살고 싶습니다.

내가 위에서 읽은 한 가지 예는 future-proofing 코드. 예를 들어:

public void setValue(int value)
{
    this.value = value;
}

그런 다음 요구 사항이 변경되고 값이 몇 배 설정되었는지 추적해야합니다.

그래서:

public void setValue(int value)
{
    this.value = value;
    count++;
}

이것은 아름답다. 나는 그것을 얻었다. 그러나 루비에서는 다음이 같은 목적을 달성하지 않습니까?

someobject.my_value = 100

나중에 시간 수를 추적해야합니다. my_value 설정되었습니다. 그럼, 당신은 단지 setter를 무시하지 않을 수 있습니까? 그 다음에 그리고 만 그 다음에?

def my_value=(value)
    @my_value = value
    @count++
end

나는 아름다운 코드를 위해 모두 인정해야하지만, 우리가 가진 Java 수업의 산을 살펴보고 말 그대로 수천, 수천 줄의 코드를 보는 것은 기본적인 getter/setters가 추악하고 성가신 것입니다.

C# 풀 타임으로 개발할 때, 우리는 항상 공개 속성을 사용했으며 필요할 때만 맞춤형 getters/setter를 사용했습니다. 매력처럼 일했고 아무것도 깨지 않았습니다.

항상 유일한 대답은 다음과 같습니다. 코드를 만지는 유일한 페론이라면 바로 가기를 포함하여 편안한 일을 할 수 있습니다.

세터 사용의 장점 중 하나는 코드의 한 위치에서만 검사를 수행해야한다는 것입니다.

이 방법에 의해 실제로 얻어지고 설정되는 것에 대해 더 많은주의를 기울일 수 있습니다. 상수 값에 대한 액세스를 제공하기 위해 사용하는 경우 상수를 사용하여 더 나을 것입니다.

이것은 문제의 프로그래밍 언어에 따라 다릅니다. 당신의 질문은 Java의 맥락에서 짜여져 있으며, 그곳에서 게터와 세터는 일반적으로 좋은 것으로 생각되는 것 같습니다.

대조적으로, 파이썬 세계에서는 일반적으로 나쁜 스타일로 간주됩니다. 실제로 기능을 추가하지 않고 코드에 선을 추가합니다. Python 프로그래머가 필요한 경우 메타 프로 그램을 사용하여 객체 속성을 얻거나 설정할 수 있습니다.

Java (적어도 10 년 전에 배운 Java의 버전)에서는 불가능했습니다. 따라서 Java에서는 일반적으로 종교적으로 게터와 세터를 사용하는 것이 가장 좋습니다. 따라서 필요한 경우 변수에 대한 액세스를 무시할 수 있습니다.

(이것은 파이썬이 Java보다 반드시 다른 것이 아니라는 것은 아닙니다.)

FYI :이 스레드의 모든 훌륭한 답변 외에도, 모든 이유에서 Getters/Setters를 위해 또는 반대 할 수있는 모든 이유를 기억하십시오. 성능은 하나가 아닙니다 (일부는 믿을 수 있듯이). JVM은 사소한 getters/setters를 인화 할 수있을 정도로 똑똑합니다 (심지어final 실제로 상체되지 않는 한).

일부 클래스를 가치 클래스로 교체 할 수 있습니다. 이렇게하면 내용이 아래에서 변경 될 때 게터를 제거하고 문제를 피할 수 있습니다.

필드의 개별 값에 대한 외부 액세스가 필요한 경우 getters 및/ 또는 세터를 사용하십시오. 그렇지 않다면. 공공 분야를 사용하지 마십시오. 그렇게 간단합니다! (좋아요, 결코 아닙니다 저것 단순하지만 좋은 경험 법칙입니다).

일반적으로, 당신은 또한 객체를 불변으로 만들려고하는 경우, 세트를 getter보다 훨씬 덜 자주 공급해야한다는 것을 알게되어야합니다. 이것은 좋은 일입니다 (항상 최선의 선택은 아닙니다).

나는 몇 안되는 몬트를 위해 Java로 프로그래밍 해 왔으며, 응용 프로그램에 필요한 경우에만 Getters & Setters를 사용해야한다는 것을 알게되었습니다.

재미있게 보내세요 :)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top