본문 바로가기
개발 이것저것

게터(Getter)를 쓰지 않는다

by chanwoodev 2023. 7. 16.

객체지향 생활체조의 원칙을 보면

  • 규칙 9: 게터/세터/프로퍼티를 쓰지 않는다.

가 있습니다.

 

위의 규칙을 적용해보며 느낀점에 대해 이야기해보도록 할게요!

 

Getter을 사용한다면?

 

Getter을 쓴다는 것은 내부의 상태를 노출한다는 것입니다.

내부 필드를 밖으로 꺼내 로직을 구현한다면 어떻게 될까요?

class Car {

	private final Handle handle
    
   	...
    
    public getHandel(){
    	return handle;
    ]
}

class 외부 {
	...
	void moveRightCar(Car car) }{
    	Handel handle = car.getHandle();
        handle.turnRight(); 
    }
}

이해하기 쉬운 예시를 만들어보았습니다.

"차를 오른쪽으로 가기 위해 핸들을 꺾는다"를 적용했을 때 이 핸들의 움직임은 외부와 결합되는 것입니다.

 

만약 Car가 다양한 클라이언트(Car을 호출하는) 클래스와 결합이 된 상태에서 어느날 자율주행으로 차가 업그레이드 된다면??

차는 이제 핸들로 방향전환을 하지않고 인공지능의 오른쪽 신호로 방향을 전환합니다.

 

차를 오른쪽으로 움직이기 위해서 핸들을 꺾는 방식과 결합된 모든 외부의 코드를 수정해야합니다.

위 같은 경우 간단한 코드이지만 해당 로직이 클라이언트의 로직과 단단하게 결합이 되어버린다면 유지보수를 위한 Cost가 상승하게됩니다.

 

책임과 캡슐화 

Getter를 쓰지 않는다는 것은

  • 내부 클래스가 정말 적절한 책임을 가지고 있는가?
  • 내부 클래스가 정말 캡슐화 되어있는가?

라고 생각합니다.

 

위의 코드를 한번 바꿔 볼까요?

class Car {

	private final Handle handle
    
   	...
    
    private void moveRightCar() }{
        handle.turnRight(); 
    }
}

class 외부 {
	...
	void (Car car) {
    	..로직
    	car.moveRightCar()
        ..
    }
}

핸들을 바꾸는 책임을 Car이 가지게 되었으며 내부를 밖으로 노출하지도 않았습니다.

 

이제 갑자기 자율주행으로 기획이 변경되었다고 가정해보겠습니다.

class Car {

	private final SelfDrive selfDrive;    
   	...
    
    private void moveRightCar() }{
        selfDrive.turnRight(); 
    }
}

class 외부 {
	...
	void (Car car) {
    	..로직
    	car.moveRightCar()
        ..
    }
}

외부의 수정이 일어나지 않았습니다.

 

절대로 쓰지 말아야하나?

"왜 Getter을 쓰지말아야할까?" 를 생각해보면 조금 답을 알 수 있을 것 같습니다.

적절한 책임 할당, 캡슐화 부분에서 이상이 없다면 DTO 생성 등의 값을 활용하는 부분에서 사용해도 된다고 생각합니다.

어떤 규칙에 있어서 절대란 없으며 해당 규칙의 근본적 이유를 생각해보면 좋을 것 같습니다!

 

Getter 사용 시 주의사항

List, Set, Map 등을 getter을 통해 반환할 때 final로 선언하더라도 함수 호출을 통해 내부를 변경할 위험이 있습니다.

public class Cars {

    private final List<Car> cars;
	..
    
    public List<Car> getCars() {
        return cars;
    }
}


public class 외부 {

    void 변경(Cars cars) {
    	//Cars의 변경 위험이 있음
        cars.getCars().add(new Car());
    	
    }
}

 

Getter을 사용하는 경우 Collections의 unModifiable 메서드를 사용해서 변경을 불가능하게 만들면

외부에서의 내부 변경을 막을 수 있답니다!

public List<Car> geCars() {
        return Collections.unmodifiableList(this.cars);
}

 

참고

 

객체지향 생활체조 원칙 규칙 9

오브젝트 - 책임 할당하기 (제 글)