게터와 세터는 디자인이 좋지 않습니까? 모순 된 조언이 보임 [중복]
이 질문에는 이미 답변이 있습니다.
- 게터와 세터 / 액세서를 사용하는 이유는 무엇입니까? 답변 38 개
나는 현재 여러 가지 모드로 Java로 간단한 게임을하고 있습니다. 메인 로직을 다른 클래스에 포함시키기 위해 메인 게임 클래스를 확장했습니다. 그럼에도 불구하고, 주요 게임 클래스는 여전히 꽤 무겁습니다.
내 코드를 잠깐 살펴본 후 게임 논리에 실제로 필요한 나머지 코드와 비교하여 대부분 Getters and Setters (60 %)였습니다.
몇몇 구글 검색은 게터와 세터가 악하다고 주장하는 반면, 다른 사람들은 좋은 OO 연습과 훌륭한 프로그램에 필요하다고 주장했다.
그래서 내가 무엇을해야하니? 어느 것이되어야합니까? 개인 변수에 대해 Getter 및 Setter를 변경해야합니까, 아니면 계속 사용해야합니까?
대부분의 경우 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);
이것은 아마도 약간 쉬운 예입니다. 내가 말하려는 것은 게터 / 세터와 공공 장소를 논의하는 것은 종종 서로의 내부 상태를 친밀한 방식으로 조작하여 너무 밀접하게 연결된 객체와 관련하여 더 큰 문제를 모호하게한다는 것입니다.
아이디어는 원하는 일을 직접 수행하는 방법을 만드는 것입니다. 예를 들어 적의 "살아있는"상태를 설정하는 방법이 있습니다. setAlive (boolean alive) 메소드를 사용하고 싶을 수도 있습니다. 대신에 다음이 있어야합니다.
private boolean alive = true;
public boolean isAlive() { return alive; }
public void kill() { alive = false; }
그 이유는 더 이상 "alive"boolean이 아니라 "hit points"값을 갖는 구현을 변경하면 이전에 작성한 두 가지 방법의 계약을 위반하지 않고 변경 할 수 있기 때문입니다.
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; }
- 매우 악 : 공공 장소.
- 다소 악한 : 게터와 세터가 필요하지 않은 곳.
- 좋은 점 : Getter와 Setter는 실제로 필요한 경우에만 유형을 지정합니다. 유형을 다른 유형에서 조작 할 상태의 저장소로 취급하지 않고 상태 를 사용 하는 "더 큰"동작을 노출시킵니다 .
가끔은 정말 - 정말하지만 상황에 따라 달라집니다 않습니다 단지 바보 같은 데이터 객체를 원한다.
당신은 이미 이것에 대해 많은 좋은 답변을 얻었으므로 2 센트를 줄 것입니다. 게터와 세터는 매우 악합니다. 기본적으로 대부분의 시간이 내부 상태를 숨기지 않는 중복 코드로 던져 질 때 객체의 내부를 숨기는 척 할 수 있습니다. 간단한 POJO의 경우 getName () 및 setName ()을 obj.name = "Tom"으로 바꿀 수없는 이유가 없습니다.
메소드 호출이 단순히 할당을 대체하는 경우 메소드 호출을 선호함으로써 얻은 모든 것은 코드 팽창입니다. 불행히도이 언어는 JavaBeans 사양에서 getter 및 setter를 사용하도록 명시되어 있으므로 Java 프로그래머는 아무 의미가없는 경우에도이를 사용해야합니다.
다행히 Eclipse (및 아마도 다른 IDE도 가능)를 통해 자동으로 생성 할 수 있습니다. 재미있는 프로젝트를 위해 XSLT에서 코드 생성기를 만들었습니다. 그러나 Java에서 제거해야 할 것이 있다면 게터와 세터에 대한 과도한 의존성입니다.
게터와 세터 는 객체 지향 프로그래밍에서 캡슐화 개념을 시행합니다 .
대상의 상태를 외부 세계에 숨겨두면 대상 자체가 실제로 책임이 있으며 의도하지 않은 방식으로 변경할 수 없습니다. 객체를 조작 할 수있는 유일한 방법은 getter 및 setter와 같은 노출 된 공개 메소드를 사용하는 것입니다.
게터와 세터를 사용하면 몇 가지 장점이 있습니다.
1. 수정 된 클래스를 사용하는 코드를 수정하지 않고 향후 변경을 허용합니다.
게터와 세터를 사용하는 것의 가장 큰 장점 중 하나는 일단 퍼블릭 메서드가 정의되고 기본 구현을 변경해야 할 때가 생긴다는 것입니다 (예 : 성능 향상을 위해 다른 알고리즘을 사용하여 수정해야하는 버그 찾기) getter 및 setter를 사용하여 오브젝트를 조작 할 수있는 유일한 방법을 사용하면 기존 코드가 중단되지 않고 변경 후에도 예상대로 작동합니다.
예를 들어 객체에 private 변수 setValue
를 설정 하는 메소드 가 있다고 가정 해 봅시다 value
.
public void setValue(int value)
{
this.value = value;
}
그러나 value
변경 횟수를 추적해야하는 새로운 요구 사항이 있었습니다. 세터를 사용하면 변경이 매우 간단합니다.
public void setValue(int value)
{
this.value = value;
count++;
}
은 IF value
필드가 공개했다, 나중에 다시 와서 값이 변경 횟수를 추적 카운터를 추가하는 쉬운 방법이 없습니다. 따라서 게터와 세터를 갖는 것이 나중에 발생할 수있는 변경 사항에 대해 클래스를 "미래 방지"하는 방법 중 하나입니다.
2. 물체를 조작 할 수있는 수단을 시행하십시오.
게터와 세터가 편리하게 사용할 수있는 또 다른 방법은 객체를 조작 할 수있는 방식을 적용하는 것이므로 객체가 자체 상태를 제어합니다. 객체의 공개 변수가 노출되면 쉽게 손상 될 수 있습니다.
예를 들어, ImmutableArray
객체는이라는 int
배열을 포함합니다 myArray
. 배열이 퍼블릭 필드라면 변경할 수 없습니다.
ImmutableArray a = new ImmutableArray();
int[] b = a.myArray;
b[0] = 10; // Oops, the ImmutableArray a's contents have been changed.
진정한 불변 배열을 구현하려면 배열의 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
참으로 변경할 수 없습니다. 객체의 변수를 노출하면 의도하지 않은 방식으로 객체를 조작 할 수 있지만 특정 방식 (게터 및 세터) 만 노출하면 객체를 의도 한 방식으로 조작 할 수 있습니다.
기본 구현의 변경을 허용하면서 API를 그대로 유지하고 변경하지 않고도 다른 사람이 사용할 API의 일부인 클래스에 게터와 세터를 갖는 것이 더 중요하다고 생각합니다.
게터와 세터의 모든 장점에 따르면, 게터가 단순히 개인 변수의 값을 반환하고 세터가 단순히 값을 수락하고 개인 변수에 할당하는 경우 게터와 세터는 외견 상이며 실제로는 낭비. 클래스가 다른 사람이 사용하지 않을 응용 프로그램에서 내부 용으로 사용하려는 경우 getter 및 setter를 광범위하게 사용하는 것은 공용 API를 작성할 때만 큼 중요하지 않을 수 있습니다.
그들은 절대적으로 악하다.
@coobird 불행히도 그들은 "캡슐화의 개념을 강요하지 않는다"고 절대로하지 않습니다. 실제로 메소드 웅장 함을 무시한 속성을 통해 데이터를 노출 할 때 데이터를 캡슐화한다고 생각하기 만하면됩니다. 게터 / 세터가 퍼블릭 필드를 수행하는 모든 것이 더 좋습니다.
먼저 공개 데이터를 원한다면 공개하고 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를 따르고 게터 / 세터를 제거하는 방법을 명명하는 것입니다. getter / setter가없는 문제가있는 경우 다른 클래스에서 작업을 수행하는 대신 객체를 자체 클래스 내부에서 더티 작업을 수행하도록 지시하십시오.
여기에 내 고난이 끝납니다.
미끄러운 경사입니다.
간단한 Transfer 객체 (또는 Parameter 객체)는 일부 필드를 유지하고 필요에 따라 값을 제공하기위한 목적으로 만 사용할 수 있습니다. 그러나 그 퇴보 된 경우에도 객체는 변경 불가능해야한다고 주장 할 수 있습니다-생성자에서 구성되고 get
... 메소드 만 노출시킵니다 .
일부 "컨트롤 노브"를 노출하는 클래스의 경우도 있습니다. 자동차 라디오의 UI가 아마 같은 것을 노출로 이해 될 수있다 getVolume
, setVolume
, getChannel
,하고 setChannel
있지만 실제 기능은 신호를 수신 및 방출되는 소리. 그러나 이러한 노브는 구현 세부 정보를 많이 노출하지 않습니다. 라디오가 트랜지스터, 대부분 소프트웨어 또는 진공 튜브인지 여부를 인터페이스 기능에서 알 수 없습니다.
문제 영역 작업에서 객체를 적극적인 참여자로 생각하기 시작할수록 내부 상태에 대해 말하거나 요청하는 대신 무언가 를 하도록 요구하는 관점에서 더 많이 생각 하게됩니다. 다른 코드 가 그 값으로 무언가를 할 수 있도록 데이터 .
그래서 ... "악"? 실제로는 아닙니다. 그러나 가치를 부여하고 그 가치에 대해 get
... 및 set
... 방법을 모두 노출하려는 경향이있을 때마다 그 이유와 그 객체의 책임이 무엇인지 스스로에게 물어보십시오. (가) 만 자신이 줄 수있는 대답하면, "나를 위해이 값을 누르고"다음 어쩌면 OO 이외의 무언가가 여기에 것입니다.
게임 클래스가 많은 변수를 노출하면 아마도 신 객체 반 패턴을 따르고있을 것입니다 . 게터와 세터에는 아무런 문제가 없습니다 (자바에서 자세한 설명은 약간 성가시다). 각 클래스마다 명확하게 분리 된 기능이있는 잘 설계된 앱에서는 단일 클래스에 수십 개가 필요하지 않습니다.
편집 : 게터와 세터의 주요 요점이 게임 클래스를 "구성"하는 것이라면 (귀하의 의견을 이해합니다), 아마 게터가 필요하지 않을 것입니다 (클래스가 자체 개인 변수에 액세스하는 것이 완벽하게 좋습니다) get 메소드를 사용하지 않고) 여러 setter를 개념적으로 함께 속하는 여러 변수를 설정하는 "group setter"로 축소 할 수 있습니다.
게터와 세터의 존재는 디자인 문제가 있음을 나타내는 경향이 있습니다 (초등학교 언어에 속하면 "냄새"). 사소한 게터와 세터는 공개 필드와 거의 구별 할 수 없습니다. 일반적으로 데이터에서 작동하는 코드는 캡슐화가 불량하고 프로그래머가 기대하지 않는 OO 클래스와는 다른 클래스에 있습니다.
어떤 경우에는 게터와 세터가 좋습니다. 그러나 일반적으로 게터와 세터가 모두있는 유형은 설계 문제를 나타냅니다. 게터는 불변성을 위해 작동합니다. 세터는 "말하지 말아라"를 위해 작동합니다. 불변성과 "tell do n't ask"는 겹치는 스타일로 적용되지 않는 한 좋은 디자인 선택입니다.
내 의견은 게터와 세터가 좋은 프로그램의 요구 사항이라는 것입니다. 그것들을 고수하지만 불필요한 게터 / 세터를 쓰지 마십시오-모든 변수를 직접 처리 해야하는 것은 아닙니다.
나는 그들이 악하다고 생각하지 않습니다. 그러나 나는 정말로 필요하지 않는 한 절대 사용하지 않아도되는 세상에 살고 싶습니다.
위에서 읽은 한 가지 예는 future-proofing
귀하의 코드입니다. 예를 들면 다음과 같습니다.
public void setValue(int value)
{
this.value = value;
}
그런 다음 요구 사항이 변경되고 값이 몇 번 설정되었는지 추적해야합니다.
그래서:
public void setValue(int value)
{
this.value = value;
count++;
}
이것은 아름답다. 알겠습니다 그러나 Ruby에서 다음과 같은 목적을 달성하지 못합니까?
someobject.my_value = 100
나중에 my_value
설정 한 횟수를 추적해야합니다 . 그럼, 당신은 단지 세터을 무시할 수없는 THEN 만 THEN ?
def my_value=(value)
@my_value = value
@count++
end
나는 아름다운 코드를 원하지만 우리가 가지고있는 Java 클래스의 산을 살펴보고 문자 그대로 수천 줄의 코드 줄을 보지 못하지만 기본 게터 / 세터는 추악하고 성가시다.
C # 풀 타임으로 개발 할 때 항상 공용 속성을 사용하고 필요할 때만 사용자 지정 getter / setter를 수행했습니다. 매력처럼 일했고 아무것도 깨지 않았습니다.
항상 유일한 대답은 다음과 같습니다. 당신이 코드를 만지는 유일한 페론이라면, 단축키를 포함하여 편안하게 무엇이든 할 수 있습니다.
setter를 사용하면 코드의 한 위치에서만 검사를 수행 할 수 있다는 이점이 있습니다.
실제로 이러한 방법으로 얻고 설정하는 것에 더주의를 기울이고 싶을 수도 있습니다. 상수 값에 액세스하기 위해 이들을 사용하는 경우 상수를 사용하는 것이 좋습니다.
이것은 해당 프로그래밍 언어에 따라 다릅니다. 귀하의 질문은 Java와 관련되어 있으며 게터와 세터는 일반적으로 좋은 것으로 생각됩니다.
반대로 파이썬 세계에서는 일반적으로 잘못된 스타일로 간주됩니다. 실제로 기능을 추가하지 않고 코드에 줄을 추가합니다. 파이썬 프로그래머는 메타 프로그래밍을 사용하여 객체 속성을 가져 오거나 설정할 수 있습니다.
Java (최소한 10 년 전에 배운 Java 버전)에서는 불가능했습니다. 따라서 Java에서는 일반적으로 getter 및 setter를 종교적으로 사용하는 것이 가장 좋으므로 필요한 경우 변수에 대한 액세스를 대체 할 수 있습니다.
(이것으로 파이썬이 반드시 Java보다 더 나은 것은 아닙니다. 단지 다릅니다.)
참고로이 스레드의 모든 훌륭한 답변 외에도 게터 / 세터에 대해 또는 반대 할 수있는 모든 이유 중에서 성능이 하나도 아니라는 점을 기억하십시오. JVM은 사소한 게터 / 세터 ( final
실제로 재정의되지 않는 한 비 게터)를 인라인하기에 충분히 영리 합니다.
일부 클래스를 가치 클래스로 대체 할 수 있습니다. 이를 통해 게터를 제거하고 컨텐츠가 아래에서 변경 될 때 문제를 피할 수 있습니다.
개별 필드 값에 대한 외부 액세스가 필요한 경우 getter 및 / 또는 setter를 사용하십시오. 그렇지 않다면하지 마십시오. 공공 장소를 사용하지 마십시오. 그렇게 간단합니다! (OK, 그렇게 간단하지는 않지만 좋은 경험입니다.)
일반적으로 게터보다 세터를 훨씬 덜 자주 제공해야합니다. 특히 객체를 불변으로 만들려고하는 경우-항상 좋은 선택이지만 항상 그렇지는 않습니다.
나는 몇 달 전에 자바로 프로그래밍 해 왔으며 응용 프로그램에 필요할 때만 getter 및 setter를 사용해야한다는 것을 배웠습니다.
재미있게 보내세요 :)
'Programing' 카테고리의 다른 글
안드로이드 리소스 / 값에 부동 소수점 값 추가 (0) | 2020.04.20 |
---|---|
ROR 마이그레이션 중에 열 유형을 Date에서 DateTime으로 변경 (0) | 2020.04.20 |
프록시 뒤에서 Ruby Gems를 업데이트하는 방법 (ISA-NTLM) (0) | 2020.04.20 |
Angular 1.2 이상에서 ng-bind-html-unsafe를 복제하기 위해 $ sce.trustAsHtml (string)을 어떻게 사용합니까? (0) | 2020.04.20 |
iPhone에서 SOAP 서비스에 액세스하는 방법 (0) | 2020.04.20 |