[Java] 2주차 스터디 - Getter와 Setter
1. 접근 제어자
해당 클래스 안에서 | 동일 패키지 안에서 | 동일 패키지 또는 자손 클래스 안에서 | 다른 패키지 포함 어느 곳에서든 | |
---|---|---|---|---|
public | ✅ | ✅ | ✅ | ✅ |
protected | ✅ | ✅ | ✅ | |
default | ✅ | ✅ | ||
private | ✅ |
1) 접근제어자를 왜 사용하는가? - GPT의 답변!
- 캡슐화: 클래스의 내부 데이터를 숨기고, 외부에서 직접 접근하지 못하게 함으로써 클래스의 안정성을 높입니다. 이를 통해 응집도를 높이고 결합도를 낮추어 코드의 유지 보수성을 향상시킵니다.
- 보안: 중요한 정보나 기능을 외부에서 접근할 수 없도록 보호합니다. 이를 통해 악의적인 사용자로부터 데이터를 보호할 수 있습니다.
- 모듈화: 코드를 모듈화하여 개발자가 더 작은 부분으로 작업할 수 있도록 합니다. 이는 대규모 프로젝트에서 여러 사람이 동시에 작업하는 경우 특히 중요합니다.
- 재사용성: 외부에서 접근할 수 있는 인터페이스를 제공하여 코드의 재사용성을 높입니다. 이는 객체 지향 프로그래밍의 핵심 개념 중 하나입니다.
- 유지 보수성: 코드를 관리하기 쉽고 유지 보수하기 쉽도록 만듭니다. 접근 제어자를 사용하여 클래스의 사용 방법을 명확히 정의함으로써 다른 개발자가 클래스를 이해하고 수정하는 데 도움을 줍니다.
2) private 접근 제어자
public class Player {
private final String name;
public Player(String playerName) {
this.name = playerName;
}
//...
}
▷ private로 선언되어 "인스턴스.필드" 방식으로는 접근 불가 || static으로 선언되어도 "클래스명.필드" 방식으로 접근 불가
// Main.java
Player player = new Player("pobi");
player.name = "woni" // ⚠️ 불가
▷ private 접근 제어자는 캡슐화와 보안과 관련이 깊다.
- 진짜로 `감추는’ 것이 아니다. - 코드로 확인 가능
- 중요한 데이터에 대한 접근을 제어하여 의도치 않은 데이터 변경 방지 - 작성자의 의도대로 사용하도록 하기 위함
2. Getter와 Setter
1) 왜 사용해?
- private로 선언하면 외부에서 접근 및 수정이 불가능
▷ getter와 setter를 정의하고 사용해 private로 선언된 필드에 접근 및 수정하기 위해서 사용됨.
2) 예시
public class Player {
private String name;
public Player(String playerName) {
this.name = playerName;
}
public String getPlayerName() {
return name;
}
public void setPlayerName(String name) {
this.name = name;
}
}
▷ getter: private로 선언된 필드에 접근하기 위해서 사용
▷ setter: private로 선언된 필드를 수정하기 위해서 사용
//getter, setter 기본모양
public <멤버 변수 자료형> get[필드명](){
return <멤버 변수명>;
}
public void set[필드명]( <멤버변수 자료형> <변수명> ){
this.멤버변수 = 매개변수;
}
직접 사용해보자.
public class Main {
public static void main(String[] args) {
Player player = new Player("pobi");
System.out.println(player.getPlayerName()); // pobi
player.setPlayerName("woni");
System.out.println(player.getPlayerName()); // woni
}
}
→ playerName에 대해 getPlayerName로 접근해 pobi를 출력했다.
→ setPlayerName을 통해 pobi 에서 woni로 이름을 변경했다.
3. 왜 Getter와 Setter의 사용을 지양하는가?
[출처 및 참고]
[OOP] Getter와 Setter는 지양하는게 좋다
목차 들어가기 전에 얼마 전 사내에서 Getter와 Setter를 함부로 사용하면 안되는 이유에 대한 세미나가 있었다. Setter에 대한 이야기는 워낙 많이 알려져있었지만 Getter에 대한 이야기는 잘 하지 않
colabear754.tistory.com
이유와 솔루션으로 정리하는 객체지향 생활체조 원칙
객체지향 생활체조 원칙 소트웍스 앤솔러지 표지 "어떤 멍청이라도 컴퓨터가 이해할 수 있는 코드는 작성할 수 있다. 좋은 프로그래머는 사람이 이해할 수 있는 코드를 작성한다. (Any fool can write
hudi.blog
1) Getter와 Setter를 지양하는 이유
간단하게 생각해보면 특정 필드를 private으로 선언한 이유가 있을 것이다. 그런데 public으로 선언된 getter와 setter 덕분(?) 때문(?)에 접근 및 수정이 가능해지면 우리가 private로 선언한 목적 - 필드를 감추고 클래스의 캡슐화 및 보안 유지 - 에 부합하는지 생각해볼 필요가 있다.
2) Getter와 Setter를 지양하는 이유 - Setter
특히 Setter는 왜 사용을 지양해야하는가에 대해서 쉽게 와닿는다. 위의 예시를 보면 pobi에서 woni로 setPlayerName을 통해서 name필드를 변경했다. 그런데 왜 변경했는지 의도가 쉽게 파악되지 않는다. 바꾼 나는 알겠지만 내 코드를 본 누군가는 왜 바꿨는가에 대해서 의문을 가질 가능성이 농후하다.
public class Main {
public static void main(String[] args) {
Player player = new Player("pobi");
System.out.println(player.getPlayerName()); // pobi
player.setPlayerName("woni"); // 왜 바꾸는데??
System.out.println(player.getPlayerName()); // woni
}
}
3) Getter와 Setter를 지양하는 이유 - Getter
Setter에 비해서 Getter를 지양하는 이유는 쉽게 와닿지 않는다. Getter는 Setter에 비해서 자유롭게 사용할 수 있다고 생각한다. 다만, 메서드의 인자로 넘길 값이 필요해서 사용하는 경우 외에 Getter로 조회한 값을 조작하는 경우가 적절하지 않다고 볼 수 있다.
class Player {
private String name;
private int strength;
public Player(String playerName, int strength) {
this.name = playerName;
this.strength = strength;
}
public String getPlayerName() {
return name;
}
public int getStrength() {
return strength;
}
}
class Main {
public static void main(String[] args) {
boolean drinkLuckyPotion = true;
Player player = new Player("pobi", 10);
System.out.println(player.getPlayerName()); // pobi
System.out.println(player.getStrength()); // 10
if (drinkLuckyPotion) {
int playerStrength = player.getStrength() * 2;
}
else{
int playerStrength = player.getStrength() / 2;
}
}
}
1) Getter메서드를 사용함으로써 Player의 내부 상태, 구현을 외부로 노출시키는 문제 발생!
▷ Main 클래스의 if-else 문에서 player의 strength를 가져와서 증가 또는 감소, 내부에 직접 접근하는 것과 동일
2) 럭키포션을 마셔서 힘을 조절하는 하는 행위는 Player 객체의 책임
4. Getter와 Setter
객체 내부에서 최대한 담당할 수 있도록 내부 메서드로 구현하자!
1) Setter
▷ 의도를 반영한 메서드를 구현! '우테코 공통 피드백 - 이름을 통해 의도를 드러낸다 / 축약하지 않는다.'을 통해서도 알 수 있듯이 나의 의도, 목적을 잘 드러내는 것이 매우 중요하기 때문에 Setter 대신 명확한 의도가 보이는 메서드로 구현하도함.
class Player {
private String name;
private int strength;
public Player(String playerName, int strength) {
this.name = playerName;
this.strength = strength;
}
public String getPlayerName() {
return name;
}
//...
public void changeName(String newName) {
this.name = newName;
}
}
class Main {
public static void main(String[] args) {
boolean drinkLuckyPotion = true;
Player player = new Player("pobi", 10);
System.out.println(player.getPlayerName()); // pobi
//...
if (isNameChangeEvent){
player.changeName("woni");
}
}
}
2) Getter
▷ Player 클래스 내부에 구현!. 이를 통해서 Player 내부에 직접 접근하지 않고 간접적으로 값을 변경할 수 있도록 함.
package boj;
class Player {
private String name;
private int strength;
public Player(String playerName, int strength) {
this.name = playerName;
this.strength = strength;
}
public String getPlayerName() {
return name;
}
public int getStrength() {
return strength;
}
public void adjustStrength(boolean drinkLuckyPotion) {
if (drinkLuckyPotion) {
this.strength *= 2; // strength를 2배로 증가
} else {
this.strength /= 2; // strength를 2로 나누어 감소
}
}
}
class Main {
public static void main(String[] args) {
boolean drinkLuckyPotion = true;
Player player = new Player("pobi", 10);
System.out.println(player.getPlayerName()); // pobi
System.out.println(player.getStrength()); // 10
player.adjustStrength(drinkLuckyPotion); // strength 조정 메서드 호출
System.out.println(player.getStrength()); // 변경된 strength 값 출력
}
}