게터나 세터는 디자인이 좋지 않은가요?모순된 조언이 표시됨
저는 현재 자바에서 몇 가지 다른 모드로 간단한 게임을 만들고 있습니다.주요 논리를 다른 클래스에 포함시키기 위해 메인 게임 클래스를 확장했습니다.그럼에도 불구하고 메인 게임 클래스는 여전히 꽤 많다.
내 코드를 잠깐 살펴본 결과, 게임의 논리에 정말 필요한 나머지 부분과 비교하여 Getters와 Setters(60%)가 가장 많았다.
몇몇 구글 검색에서는 Getters와 Setters가 악하다고 주장하는 반면, 다른 검색에서는 그것들이 좋은 OO 관행과 훌륭한 프로그램을 위해 필요하다고 주장했습니다.
그럼 어떻게 해야 하죠?어떤 게 좋을까요?개인 변수에 맞게 Getters와 Setters를 변경해야 합니까? 아니면 그대로 유지해야 합니까?
또한 대부분의 경우 setters를 사용하면 의미 없는 값을 설정할 수 있으므로 캡슐화가 해제됩니다.아주 명백한 예로서, 만약 당신이 게임에서 점수 카운터를 가지고 있다면, 오직 올라간다는 것 대신에,
// 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에 대해 논의하는 것은 종종 사물이 서로의 내부 상태를 친밀한 방식으로 조작하고 따라서 너무 밀접하게 결합되어 있다는 더 큰 문제를 모호하게 한다는 것입니다.
하고 싶은 일을 직접 할 수 있는 방법을 만드는 것이 아이디어입니다.예를 들면, 적의 「alive」상태를 설정하는 방법이 있습니다.setAlive(boolean alive) 메서드가 필요할 수 있습니다.대신 다음과 같은 것이 필요합니다.
private boolean alive = true;
public boolean isAlive() { return alive; }
public void kill() { alive = false; }
그 이유는 실장을 변경하여 더 이상 "활용" 부울값이 아닌 "히트 포인트" 값을 갖게 되면 앞에서 기술한2가지 방법의 계약을 파기하지 않고 변경할 수 있기 때문입니다.
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와 setters는 실제로 필요한 곳에만 사용할 수 있습니다.타입을 다른 타입에 의해 조작되는 상태의 저장소로 취급하는 것이 아니라, 그 스테이트를 사용하는 「더 큰」동작을 타입이 나타내도록 합니다.
상황에 따라 다르겠지만, 때로는 멍청한 데이터 객체만 원할 수도 있습니다.
당신은 이미 이 문제에 대해 많은 좋은 답을 얻었으니까, 저는 제 의견을 말할게요.게터나 세터들은 아주, 아주 사악해요기본적으로 오브젝트의 내부 상태를 숨기는 척할 수 있습니다.대부분의 경우 내부 상태를 숨기는 데 아무런 도움이 되지 않는 중복 코드로 처리됩니다.단순한 POJO의 경우 getName() 및 setName()을 obj.name = "Tom"으로 대체하지 못할 이유가 없습니다.
메서드 호출이 단순히 할당을 대체하는 경우 메서드 호출을 선호함으로써 얻을 수 있는 것은 코드 블러트뿐입니다.유감스럽게도 이 언어는 JavaBeans 사양에 getters와 setters의 사용을 포함시키고 있기 때문에 Java 프로그래머들은 이 방법이 전혀 말이 되지 않을 때에도 그것들을 사용하도록 강요받고 있습니다.
다행히 Eclipse(및 다른 IDE도 포함)를 사용하면 자동으로 생성할 수 있습니다.재미있는 프로젝트를 위해 XSLT에서 코드 생성기를 만든 적이 있습니다.하지만 자바에서 한 가지 없애야 할 것이 있다면, 그것은 바로 getter와 setter에 대한 과도한 의존이다.
getters와 setters는 객체 지향 프로그래밍에서 캡슐화 개념을 적용합니다.
사물의 상태를 외부로부터 숨김으로써, 사물은 진정으로 자신을 책임지고 있으며 의도하지 않은 방식으로 변경될 수 없습니다.개체를 조작할 수 있는 유일한 방법은 getter 및 setter와 같은 노출된 공개 메서드를 사용하는 것입니다.
getter와 setter를 사용하면 다음과 같은 이점이 있습니다.
1. 변경된 클래스를 사용하는 코드를 수정하지 않고 나중에 변경할 수 있습니다.
getter와 setter를 사용하는 가장 큰 장점 중 하나는 공개 방법이 정의되고 나면 기본 구현을 변경해야 할 때(예를 들어 수정이 필요한 버그 발견, 성능 향상을 위한 다른 알고리즘 사용 등) 게터와 setter를 조작하는 유일한 방법이라는 것입니다.오브젝트: 기존 코드가 파손되지 않고 변경 후에도 정상적으로 동작합니다.
예를 들어, 예를 들어,setValue
를 설정하는 방법value
개체 내 개인 변수:
public void setValue(int value)
{
this.value = value;
}
하지만, 그 때, 그 횟수를 추적해야 하는 새로운 요건이 있었다.value
변경되었습니다.세터를 배치하면 변경은 매우 간단합니다.
public void setValue(int value)
{
this.value = value;
count++;
}
이 경우,value
필드가 공개되어 있기 때문에 나중에 돌아와 값이 변경된 횟수를 추적하는 카운터를 추가할 수 있는 쉬운 방법은 없습니다.따라서, getter와 setter를 가지는 것은, 나중에 일어날지도 모르는 변화에 대해서, 클래스를 「미래에 대비하는」 방법의 하나입니다.
2. 물체를 조작할 수 있는 수단을 강구한다.
getters와 setters가 편리한 또 다른 방법은 오브젝트를 조작할 수 있는 방법을 적용하는 것입니다.따라서 오브젝트는 자신의 상태를 제어할 수 있습니다.개체의 공용 변수가 노출되면 개체가 쉽게 손상될 수 있습니다.
예를 들어,ImmutableArray
오브젝트에는int
호출된 배열myArray
어레이가 퍼블릭필드일 경우 불변은 없습니다.
ImmutableArray a = new ImmutableArray();
int[] b = a.myArray;
b[0] = 10; // Oops, the ImmutableArray a's contents have been changed.
진정한 불변의 어레이를 구현하기 위해서는 어레이의 getter(게터)가 필요합니다.getArray
method)는 어레이의 복사본을 반환하도록 작성해야 합니다.
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와 setters는 다른 사람이 사용하는 API의 일부인 클래스에서 더 중요하다고 생각합니다.이는 API를 그대로 유지하면서 기본 구현을 변경할 수 있기 때문입니다.
getters와 setters의 모든 장점이 설명되었듯이, getter가 단순히 private 변수의 값을 반환하고 setter가 단순히 값을 받아들여 private 변수에 할당하는 경우 getters와 setters는 단지 무관하고 실제로 낭비되는 것으로 보입니다.클래스가 다른 사용자가 사용하지 않는 응용 프로그램에 의해 내부용으로만 사용되는 경우 getters와 setters를 광범위하게 사용하는 것은 공용 API를 작성할 때만큼 중요하지 않을 수 있습니다.
그들은 완전히 사악하다.
@coobird 그들은 결코 "캡슐화 개념에 얽매이지 않는다"고 생각하지 않는다.그것들은, 실제로는, 메서드의 과대망상을 수반하는 속성을 개입시켜 데이터를 캡슐화하고 있다고 생각하게 하는 것뿐이다.getter/setter가 공공장소에서 할 수 있는 것은 무엇이든지 좋다.
우선, 공개 데이터를 필요로 하는 경우는, 공개해 주세요.게터나 세터 방식을 사용하지 않고, 클라이언트에 의한 조작 방법의 수를 삭감해, 클라이언트의 가치 변경을 인지적으로 용이하게 합니다.
object.field = value;
보다 인지적으로 강한 대신
object.setField(value);
여기서 클라이언트는 getter/setter 메서드에 부작용이 없는지 확인해야 합니다.
둘째, 이 메서드에서 다른 작업을 수행해야 하는 경우 단순히 취득하거나 설정하는 것보다 더 많은 책임이 있는데 왜 get/set 메서드를 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/setters를 제거하는 방법을 명명하는 것입니다.getter/setters 없이 문제가 있는 경우, 다른 클래스에서 다른 클래스로 작업하려고 하지 말고 자신의 클래스 내에서 자신의 더러운 작업을 하도록 오브젝트에게 지시하십시오.
이것으로 나의 고함소리는 끝났다.미안하다;)
그것은 미끄러운 경사면이다.
단순한 전송 객체(또는 파라미터 객체)는 일부 필드를 유지하고 필요에 따라 값을 제공하는 유일한 목적을 가질 수 있습니다.단, 그 퇴보적인 경우에도 오브젝트는 불변해야 한다고 주장할 수 있습니다.- 컨스트럭터에서 설정되고 노출만 됩니다.get
...방법들.
또한 일부 "컨트롤 노브"를 노출하는 클래스의 경우도 있습니다. 자동차 라디오의 UI는 아마도 다음과 같은 것을 노출하는 것으로 이해될 수 있습니다.getVolume
,setVolume
,getChannel
,그리고.setChannel
하지만, 그것의 진짜 기능은 신호를 수신하고 소리를 내는 것입니다.그러나 이 노브에서는 구현에 대한 자세한 내용은 알 수 없습니다.이 인터페이스 기능에서는 무선이 트랜지스터, 소프트웨어 또는 진공관 중 어느 쪽인지 알 수 없습니다.
오브젝트를 문제 영역 태스크의 액티브한 참가자로 생각하기 시작하면 생각할수록 오브젝트의 내부 상태를 알려달라고 요구하거나 다른 코드가 이러한 값으로 무언가를 할 수 있도록 데이터를 요구하는 것이 아니라 오브젝트에 대해 무언가를 요구한다고 생각할 수 있습니다.
그럼... "악마"?사실 그렇지 않아요.하지만 당신이 가치를 부여하고 두 가지를 모두 드러내는 경향이 있을 때마다get
...그리고.set
...그 가치에 대한 방법, 그 이유와 그 객체의 책임성이 무엇인지 자문해 보십시오."나를 위해 이 가치를 유지하는 것"이라고 대답할 수 밖에 없다면, 여기서 OO 이외의 일이 벌어지고 있는 것일지도 모른다.
당신의 게임 클래스는 아마도 god object antiftern을 따라가고 있을 것입니다.getters와 setters에는 문제가 없습니다(Java에서의 장황함은 다소 귀찮을 수 있지만). 각 클래스가 명확하게 분리된 기능을 가진 잘 설계된 앱에서는 한 클래스에 수십 개가 필요하지 않습니다.
편집: getters와 setters의 요점이 game classe를 구성하는 것이라면 getters는 필요없을 것입니다(get method를 사용하지 않고 클래스가 자신의 private 변수에 액세스해도 문제없습니다).많은 setters를 get methods를 사용하지 않고 그룹 setters로 정리할 수 있습니다.개념적으로 함께 속하는 변수입니다.
getter와 setter의 존재는 설계상의 문제가 있음을 나타내는 경향이 있습니다(초등학생용 언어에 관심이 있는 경우 '냄새').하찮은 게터나 세터는 공공장소와 거의 구별되지 않는다.일반적으로 데이터상에서 동작하는 코드는 다른 클래스, 즉 캡슐화 불량, 그리고 프로그래머가 OO에 대해 불편해 할 것으로 예상할 수 있습니다.
경우에 따라서는 getter와 setter가 정상입니다.그러나 일반적으로 getter와 setter가 모두 있는 유형은 설계상의 문제를 나타냅니다.Getters는 불변성을 위해 일하고, setters는 "묻지마"를 위해 일한다.겹치는 스타일로 적용되지 않는 한 불변성과 "묻지마"는 둘 다 좋은 설계 선택입니다.
제 의견은 getters와 setters는 좋은 프로그램을 위한 필수 조건이라는 것입니다.불필요한 getter/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
설정되었습니다.그럼, 그냥 세터를 오버라이드 시키지 그래?
def my_value=(value)
@my_value = value
@count++
end
아름다운 코드에는 찬성이지만 인정해야 할 것은 산더미 같은 자바 클래스를 훑어보고 말 그대로 수천 줄의 코드만 보면 아무것도 아닌 기본적인 getter/setter는 보기 흉하고 귀찮다는 것입니다.
제가 C# 풀타임으로 개발했을 때는 항상 공공재산을 사용하고 필요할 때만 커스텀게터/세터를 했습니다.마법처럼 작동했고 아무것도 깨지지 않았어요.
항상 그렇듯이 유일한 답은 상황에 따라 다르다.만약 당신이 유일하게 코드를 만진다면 지름길을 포함해 당신이 편한 모든 것을 할 수 있습니다.
세터를 사용하면 코드 내의 한 위치에서만 검사를 수행할 수 있다는 장점이 있습니다.
이러한 방법을 통해 실제로 무엇을 가져오고 설정하는지 좀 더 자세히 살펴보는 것이 좋습니다.상수 값에 대한 액세스를 제공하기 위해 이러한 값을 사용하는 경우 상수를 사용하는 것이 더 나을 수 있습니다.
이는 해당 프로그래밍 언어에 따라 달라집니다.당신의 질문은 Java의 맥락에서 작성되어 있습니다.여기서 getter와 setter는 일반적으로 좋은 것으로 생각됩니다.
이와는 대조적으로 Python 세계에서는 일반적으로 나쁜 스타일로 간주되며, 실제로 기능을 추가하지 않고 코드에 행을 추가합니다.Python 프로그래머는 필요할 때 메타프로그래밍을 사용하여 오브젝트 속성을 가져오거나 설정할 수 있습니다.
In Java (at least the version of Java I learned slightly a decade ago), that was not possible. Thus, in Java it is usually best to use getters and setters religiously, so that if you need to, you can override access to the variables.
(This doesn't make Python necessarily better than Java, just different.)
Just FYI: In addition to all the excellent answers in this thread, remember that of all reasons you can come up with for or against getters/setters, performance isn't one (as some might believe). The JVM is smart enough to inline trivial getters/setters (even non-final
ones, as long as they aren't actually overridden).
You may want to replace some of your classes by value classes. This will allow you to remove the getter and avoid problems when the content is changed from under you.
If you need external access to individual values of fields, use getters and/ or setters. If not, don't. Never use public fields. It's as simple as that! (Ok, it's never that simple, but it's a good rule of thumb).
In general you should also find that you need to supply a setter much less often than a getter - especially if you are trying to make your objects immutable - which is a Good Thing (but not always the best choice) - but even if not.
I've been programming in java for few monts ago, and I've learned that we should use getters & setters only when it's necessary for the application
have fun :)
ReferenceURL : https://stackoverflow.com/questions/565095/are-getters-and-setters-poor-design-contradictory-advice-seen
'source' 카테고리의 다른 글
char 배열에 저장된 머신 코드를 호출하려면 어떻게 해야 합니다. (0) | 2022.08.15 |
---|---|
어떻게 sprintf을 사용하여 문자열을 추가할 수 있는? (0) | 2022.08.15 |
v-for, 클릭된 목록 항목을 여는 방법 (0) | 2022.08.15 |
어떻게 전체 JAR 파일을 디컴파일 할 수 있죠? (0) | 2022.08.15 |
왜 내 배열이 아닌 옵저버가 있는 거죠? (0) | 2022.08.15 |