Written by
Jiyun Wang
on
on
코드 리팩터링 2판, 6-6. 변수 캡슐화하기
하루에 한 챕터씩 읽고 정리해보기 도전!
6. 기본적인 리팩토링
6.6 변수 캡슐화하기
- 배경
- 짧은 함수 안의 임시 변수처럼 유효범위가 아주 좁은 데이터는 어려울 게 없지만, 유효범위가 넓어질수록 다루기가 어려워진다. 전역 데이터가 골칫거리인 이유가 바로 이것이다.
- 접근 할 수 있는 범위가 넓은 데이터를 옮길 때는 먼저 그 데이터로의 접근을 독점하는 함수를 만드는 식으로 캡슐화 하는 것이 가장 좋은 방법일 때가 많다. 데이터 재구성이라는 어려운 작업을 함수 재구성이라는 더 단순한 작업으로 변환하는 것이다.
- 데이터 캡슐화는 데이터를 변경하고 사용하는 코드를 감시할 수 있는 확실한 통로가 되어주기 때문에 데이터 변경 전 검증이나 변경 후 추가 로직을 쉽게 끼워 넣을 수 있다. 유효범위가 함수 하나보다 넓은 가변 데이터는 모두 이런 식으로 캡슐화해서 그 함수를 통해서만 접근하게 만들어야 한다. (데이터의 유효범위가 넓은수록 캡슐화하라) 그래야 자주 사용하는 데이터에 대한 결합도가 높아지는 일을 막을 수 있다.
- 객체 지향에서 객체의 데이터를 항상 private으로 유지해야한다.
- public 필드를 발견할 때마다 캡슐화해서 가시 범위를 제한한다.
- 불변 데이터는 가변 데이터보다 캡슐화할 이유가 적다. 데이터가 변경될 일이 없기 때문이다.
- 불변성은 강력한 방부제이다.
- 절차
- 변수로의 접근과 갱신을 전담하는 캡슐화 함수들을 만든다.
- 정적 검사를 수행한다.
- 정적 검사? 정적 분석이란 소스 코드의 실행 없이 정적으로 프로그램의 문제를 찾는 과정을 의미한다.
- 변수를 직접 참조하던 부분을 모두 적절한 캡슐화 함수 호출로 바꾼다. 하나씩 바끌 때마다 테스트 한다.
- 변수로의 접근 범위를 제한한다.
- 변수로의 직접 접근을 막을 수 없을 때는 변수 이름을 바꿔서 테스트해보면 해당 변수를 참조하는 곳을 쉽게 찾을 수 있다.
- 테스트 한다.
- 변수 값이 레코드라면 레코드 캡슐화하기를 적용할지 고려해본다.
-
예시 - setter, getter 활용
# 수정 전 target_goods_price = goods.price = 3000 target_goods_name = goods.name = "상품명인데" # 수정 후 # 함수를 통해서 값을 제어하고 접근할 수 있음. goods.set_price(3000) target_goods_price = goods.get_price() goods.set_name("상품명인데") target_goods_name = goods.get_name() # setter, getter 정의 class goods: __price = 1000 __name = "상품명" def set_price(price: int): self.__price = price def get_price(): return self.__price def set_name(name: str): self.__name = name def get_name(): return self.__name - 참고
- 캡슐화(Encapsulation)?
- 클래스 안에 서로 연관있는 속성과 기능들을 하나의 캡슐로 만들어 데이터를 외부로부터 보호하는 것
- 캡슐화를 하는 이유
- 데이터 보호(data protection) - 외부로부터 클래스에 정의된 속성과 기능들을 보호
- 데이터 은닉(data hiding) - 내부의 동작을 감추고 외부에는 필요한 부분만 노출!
- 예시
- 아플 때 먹는 캡슐약을 떠올려보면, 우리가 캡슐 안에 어떤 색의 내용물이 있는지 어떤 성분의 약이 들어있는지 알수 없다. 또한 그 안의 내용물은 캡슐을 통해서 외부로부터 오염되지 않고 안전하게 보호될 수 있다.
- 목적
- 외부로부터 클래스에 정의된 속성과 기능들을 보호하고 필요한 부분만 외부로 노출될 수 있도록 하여 각 객체 고유의 독립성과 책임 영역을 안전하게 지킨다.
- 구현하기 위한 방법
- 접근제어자 활용
- 클래스 또는 클래스의 내부의 멤버들에 사용되어 해당 클래스나 멤버들을 외부에서 접근하지 못하도록 접근을 제한하는 역할
- public(접근 제한 없음), default(동일 패키지 내), protected(동일 패키지 + 다른 패키지의 하위클래스), private(동일 클래스 내)
- 클래스 또는 클래스의 내부의 멤버들에 사용되어 해당 클래스나 멤버들을 외부에서 접근하지 못하도록 접근을 제한하는 역할
- getter/setter 함수 활용
- 클래스 내 모든 속성값들이 private 접근 제어자로 선언되어있고, getter/setter 메서더의 접근제어자만이 Public으로 열려있다. 따라서 선택적으로 외부에 접근을 허용할 속성과 그렇지 않을 속성을 getter/setter 메서드를 통해 설정해줄 수 있다.
- 객체 내부의 동작의 외부 노출을 최소화하여 각 객체의 자율성을 높이고, 이를 통해 객체 간 결합도를 낮추어 객체 지향의 핵심적인 이점을 잘 살리는 방법으로 프로그램을 설계할 수 있다.
- 참고 : https://www.codestates.com/blog/content/%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%ED%8A%B9%EC%A7%95
- 접근제어자 활용
- 캡슐화(Encapsulation)?