리팩토링 - 냄새 6. 가변 데이터
들어가기
해당 포스팅은 인프런 백기선님의 '리팩토링'을 학습 후 정리한 내용입니다.
냄새 6. 가변 데이터
Mutable Data
- 데이터를 변경하다보면 예상치 못했던 결과나 해결하기 어려운 버그가 발생하기도 한다.
- 함수형 프로그래밍 언어는 데이터를 변경하지 않고 복사본을 전달한다. 하지만 그밖의 프로그래밍 언어는 데이터 변경을 허용하고 있다. 따라서 변경되는 데이터 사용 시 발생할 수 있는 리스크를 관리할 수 있는 방법을 적용하는 것이 좋다.
- 관련 리팩토링
- “변수 캡슐화하기 (Encapsulate Variable)”를 적용해 데이터를 변경할 수 있는 메소드를 제한하고 관리할 수 있다.
- “변수 쪼개기 (Split Variable)”을 사용해 여러 데이터를 저장하는 변수를 나눌 수 있다.
- “코드 정리하기 (Slide Statements)”를 사용해 데이터를 변경하는 코드를 분리하고 피할 수 있다.
- “함수 추출하기 (Extract Function)”으로 데이터를 변경하는 코드로부터 사이드 이팩트가 없는 코드를 분리할 수 있다.
- “질의 함수와 변경 함수 분리하기 (Separate Query from Modifier)”를 적용해서 클라이언트가 원하는 경우에만 사이드 이팩트가 있는 함수를 호출하도록 API를 개선할 수 있다.
- 가능하다면 “세터 제거하기 (Remove Setting Method)”를 적용한다.
- 계산해서 알아낼 수 있는 값에는 “파생 변수를 질의 함수로 바꾸기 (Replace Derived Variable with Query)”를 적용할 수 있다.
- 변수가 사용되는 범위를 제한하려면 “여러 함수를 클래스로 묶기 (Combine Functions into Class)”또는 “여러 함수를 변환 함수로 묶기 (Combine Functions into Transform)”을 적용할 수 있다.
- “참조를 값으로 바꾸기 (Change Reference to Value)”를 적용해서 데이터 일부를 변경하기 보다는 데이터 전체를 교체할 수 있다.
변수 쪼개기
Split Variable
- 어떤 변수가 여러번 재할당 되어도 적절한 경우
- 반복문에서 순회하는데 사용하는 변수 또는 인덱스
- 값을 축적시키는데 사용하는 변수
- 그밖에 경우에 재할당 되는 변수가 있다면 해당 변수는 여러 용도로 사용되는 것이며 변수를 분리해야 더 이해하기 좋은 코드를 만들 수 있다.
- 변수 하나 당 하나의 책임(Responsibility)을 지도록 만든다.
- 상수를 활용하자. (자바스크립트의 const, 자바의 final)
예제코드
public class Order {
public double discount(double inputValue, int quantity) {
if (inputValue > 50) inputValue = inputValue - 2;
if (quantity > 100) inputValue = inputValue - 1;
return inputValue;
}
}
냄새
매개변수인 inputValue 의 값을 그대로 활용한다
해결
변수를 쪼개보자!
리팩토링 후
public class Order {
public double discount(double inputValue, int quantity) {
double result = inputValue;
if (inputValue > 50) result -= 2;
if (quantity > 100) result -= 1;
return result;
}
}
설명
inputValue 를 변수화 하여 사용한다.
질의 함수와 변경 함수 분리하기
Separate Query from Modifier
- “눈에 띌만한” 사이드 이팩트 없이 값을 조회할 수 있는 메소드는 테스트 하기도 쉽고, 메소
드를 이동하기도 편하다.
- 명령-조회 분리 (command-query separation) 규칙:
- 어떤 값을 리턴하는 함수는 사이드 이팩트가 없어야 한다.
- “눈에 띌만한 (observable) 사이드 이팩트”
- 가령, 캐시는 중요한 객체 상태 변화는 아니다. 따라서 어떤 메소드 호출로 인해, 캐시 데이터를 변경하더라도 분리할 필요는 없다
예제코드
public class Billing {
private Customer customer;
private EmailGateway emailGateway;
public Billing(Customer customer, EmailGateway emailGateway) {
this.customer = customer;
this.emailGateway = emailGateway;
}
public double getTotalOutstandingAndSendBill() {
double result = customer.getInvoices().stream()
.map(Invoice::getAmount)
.reduce((double) 0, Double::sum);
sendBill();
return result;
}
private void sendBill() {
emailGateway.send(formatBill(customer));
}
private String formatBill(Customer customer) {
return "sending bill for " + customer.getName();
}
}
냄새
getTotalOutstandingAndSendBill 함수의 호출할 경우 sendBill() 불필요한 함수를 호출한다.
해결
조회 함수와 명렴 함수를 분리하자!
리팩토링 후
public class Billing {
private Customer customer;
private EmailGateway emailGateway;
public Billing(Customer customer, EmailGateway emailGateway) {
this.customer = customer;
this.emailGateway = emailGateway;
}
public double getTotalOutstanding() {
return customer.getInvoices().stream()
.map(Invoice::getAmount)
.reduce((double) 0, Double::sum);
}
public void sendBill() {
emailGateway.send(formatBill(customer));
}
private String formatBill(Customer customer) {
return "sending bill for " + customer.getName();
}
}
설명
getTotalOutstanding() 함수는 조회만하고 senBill() 함수는 따로 호출하여 명령과 조회를 분리한다.
세터 제거하기
Remove Setting Method
해당 포스팅은 인프런 백기선님의 '리팩토링'을 학습 후 정리한 내용입니다.
Mutable Data
- 데이터를 변경하다보면 예상치 못했던 결과나 해결하기 어려운 버그가 발생하기도 한다.
- 함수형 프로그래밍 언어는 데이터를 변경하지 않고 복사본을 전달한다. 하지만 그밖의 프로그래밍 언어는 데이터 변경을 허용하고 있다. 따라서 변경되는 데이터 사용 시 발생할 수 있는 리스크를 관리할 수 있는 방법을 적용하는 것이 좋다.
- 관련 리팩토링
- “변수 캡슐화하기 (Encapsulate Variable)”를 적용해 데이터를 변경할 수 있는 메소드를 제한하고 관리할 수 있다.
- “변수 쪼개기 (Split Variable)”을 사용해 여러 데이터를 저장하는 변수를 나눌 수 있다.
- “코드 정리하기 (Slide Statements)”를 사용해 데이터를 변경하는 코드를 분리하고 피할 수 있다.
- “함수 추출하기 (Extract Function)”으로 데이터를 변경하는 코드로부터 사이드 이팩트가 없는 코드를 분리할 수 있다.
- “질의 함수와 변경 함수 분리하기 (Separate Query from Modifier)”를 적용해서 클라이언트가 원하는 경우에만 사이드 이팩트가 있는 함수를 호출하도록 API를 개선할 수 있다.
- 가능하다면 “세터 제거하기 (Remove Setting Method)”를 적용한다.
- 계산해서 알아낼 수 있는 값에는 “파생 변수를 질의 함수로 바꾸기 (Replace Derived Variable with Query)”를 적용할 수 있다.
- 변수가 사용되는 범위를 제한하려면 “여러 함수를 클래스로 묶기 (Combine Functions into Class)”또는 “여러 함수를 변환 함수로 묶기 (Combine Functions into Transform)”을 적용할 수 있다.
- “참조를 값으로 바꾸기 (Change Reference to Value)”를 적용해서 데이터 일부를 변경하기 보다는 데이터 전체를 교체할 수 있다.
변수 쪼개기
Split Variable
- 어떤 변수가 여러번 재할당 되어도 적절한 경우
- 반복문에서 순회하는데 사용하는 변수 또는 인덱스
- 값을 축적시키는데 사용하는 변수
- 그밖에 경우에 재할당 되는 변수가 있다면 해당 변수는 여러 용도로 사용되는 것이며 변수를 분리해야 더 이해하기 좋은 코드를 만들 수 있다.
- 변수 하나 당 하나의 책임(Responsibility)을 지도록 만든다.
- 상수를 활용하자. (자바스크립트의 const, 자바의 final)
예제코드
public class Order {
public double discount(double inputValue, int quantity) {
if (inputValue > 50) inputValue = inputValue - 2;
if (quantity > 100) inputValue = inputValue - 1;
return inputValue;
}
}
냄새
매개변수인 inputValue 의 값을 그대로 활용한다
해결
변수를 쪼개보자!
리팩토링 후
public class Order {
public double discount(double inputValue, int quantity) {
double result = inputValue;
if (inputValue > 50) result -= 2;
if (quantity > 100) result -= 1;
return result;
}
}
설명
inputValue 를 변수화 하여 사용한다.
질의 함수와 변경 함수 분리하기
Separate Query from Modifier
- “눈에 띌만한” 사이드 이팩트 없이 값을 조회할 수 있는 메소드는 테스트 하기도 쉽고, 메소
드를 이동하기도 편하다.
- 명령-조회 분리 (command-query separation) 규칙:
- 어떤 값을 리턴하는 함수는 사이드 이팩트가 없어야 한다.
- “눈에 띌만한 (observable) 사이드 이팩트”
- 가령, 캐시는 중요한 객체 상태 변화는 아니다. 따라서 어떤 메소드 호출로 인해, 캐시 데이터를 변경하더라도 분리할 필요는 없다
예제코드
public class Billing {
private Customer customer;
private EmailGateway emailGateway;
public Billing(Customer customer, EmailGateway emailGateway) {
this.customer = customer;
this.emailGateway = emailGateway;
}
public double getTotalOutstandingAndSendBill() {
double result = customer.getInvoices().stream()
.map(Invoice::getAmount)
.reduce((double) 0, Double::sum);
sendBill();
return result;
}
private void sendBill() {
emailGateway.send(formatBill(customer));
}
private String formatBill(Customer customer) {
return "sending bill for " + customer.getName();
}
}
냄새
getTotalOutstandingAndSendBill 함수의 호출할 경우 sendBill() 불필요한 함수를 호출한다.
해결
조회 함수와 명렴 함수를 분리하자!
리팩토링 후
public class Billing {
private Customer customer;
private EmailGateway emailGateway;
public Billing(Customer customer, EmailGateway emailGateway) {
this.customer = customer;
this.emailGateway = emailGateway;
}
public double getTotalOutstanding() {
return customer.getInvoices().stream()
.map(Invoice::getAmount)
.reduce((double) 0, Double::sum);
}
public void sendBill() {
emailGateway.send(formatBill(customer));
}
private String formatBill(Customer customer) {
return "sending bill for " + customer.getName();
}
}
설명
getTotalOutstanding() 함수는 조회만하고 senBill() 함수는 따로 호출하여 명령과 조회를 분리한다.
세터 제거하기
Remove Setting Method
- 반복문에서 순회하는데 사용하는 변수 또는 인덱스
- 값을 축적시키는데 사용하는 변수
- 변수 하나 당 하나의 책임(Responsibility)을 지도록 만든다.
- 상수를 활용하자. (자바스크립트의 const, 자바의 final)
public class Order {
public double discount(double inputValue, int quantity) {
if (inputValue > 50) inputValue = inputValue - 2;
if (quantity > 100) inputValue = inputValue - 1;
return inputValue;
}
}
매개변수인 inputValue 의 값을 그대로 활용한다
변수를 쪼개보자!
public class Order {
public double discount(double inputValue, int quantity) {
double result = inputValue;
if (inputValue > 50) result -= 2;
if (quantity > 100) result -= 1;
return result;
}
}
inputValue 를 변수화 하여 사용한다.
Separate Query from Modifier
- “눈에 띌만한” 사이드 이팩트 없이 값을 조회할 수 있는 메소드는 테스트 하기도 쉽고, 메소
드를 이동하기도 편하다. - 명령-조회 분리 (command-query separation) 규칙:
- 어떤 값을 리턴하는 함수는 사이드 이팩트가 없어야 한다.
- “눈에 띌만한 (observable) 사이드 이팩트”
- 가령, 캐시는 중요한 객체 상태 변화는 아니다. 따라서 어떤 메소드 호출로 인해, 캐시 데이터를 변경하더라도 분리할 필요는 없다
예제코드
public class Billing {
private Customer customer;
private EmailGateway emailGateway;
public Billing(Customer customer, EmailGateway emailGateway) {
this.customer = customer;
this.emailGateway = emailGateway;
}
public double getTotalOutstandingAndSendBill() {
double result = customer.getInvoices().stream()
.map(Invoice::getAmount)
.reduce((double) 0, Double::sum);
sendBill();
return result;
}
private void sendBill() {
emailGateway.send(formatBill(customer));
}
private String formatBill(Customer customer) {
return "sending bill for " + customer.getName();
}
}
냄새
getTotalOutstandingAndSendBill 함수의 호출할 경우 sendBill() 불필요한 함수를 호출한다.
해결
조회 함수와 명렴 함수를 분리하자!
리팩토링 후
public class Billing {
private Customer customer;
private EmailGateway emailGateway;
public Billing(Customer customer, EmailGateway emailGateway) {
this.customer = customer;
this.emailGateway = emailGateway;
}
public double getTotalOutstanding() {
return customer.getInvoices().stream()
.map(Invoice::getAmount)
.reduce((double) 0, Double::sum);
}
public void sendBill() {
emailGateway.send(formatBill(customer));
}
private String formatBill(Customer customer) {
return "sending bill for " + customer.getName();
}
}
설명
getTotalOutstanding() 함수는 조회만하고 senBill() 함수는 따로 호출하여 명령과 조회를 분리한다.
세터 제거하기
Remove Setting Method
• 세터를 제공한다는 것은 해당 필드가 변경될 수 있다는 것을 뜻한다.
• 객체 생성시 처음 설정된 값이 변경될 필요가 없다면 해당 값을 설정할 수 있는 생성자를 만들고 세터를 제거해서 변경될 수 있는 가능성을 제거해야 한다.
예제코드
public class Person {
private String name;
private int id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
냄새
회원을 식별하는 필드인 id 는 변경을 하면 안되지만, setter 를 사용한다.
해결
setter 메서드를 없앤다.
파생 변수를 질의 함수로 바꾸기
Replace Derived Variable with Query
- 변경할 수 있는 데이터를 최대한 줄이도록 노력해야 한다.
- 계산해서 알아낼 수 있는 변수는 제거할 수 있다.
- 계산 자체가 데이터의 의미를 잘 표현하는 경우도 있다.
- 해당 변수가 어디선가 잘못된 값으로 수정될 수 있는 가능성을 제거할 수 있다.
- 계산에 필요한 데이터가 변하지 않는 값이라면, 계산의 결과에 해당하는 데이터 역시 불변 데이터기 때문에 해당 변수는 그대로 유지할 수 있다.
예제코드
public class ProductionPlan {
private double production;
private List<Double> adjustments = new ArrayList<>();
public void applyAdjustment(double adjustment) {
this.adjustments.add(adjustment);
this.production += adjustment;
}
public double getProduction() {
return this.production;
}
}
냄새
applyAdjustment() 함수는 매개변수의 값을 list에 넣어줌과 동시에 총 합을 profuction 필드에 저장을 하는데, 이는 list 에서 총합을 알 수 있는 불필요한 변수이다.
해결
production 필드를 제거 후 list 에 저장된 총합을 return 하도록 한다.
리팩토링 후
public class ProductionPlan {
private List<Double> adjustments = new ArrayList<>();
public void applyAdjustment(double adjustment) {
this.adjustments.add(adjustment);
}
public double getProduction() {
return adjustments.stream().mapToDouble(Double::valueOf).sum();
}
}
설명
불필요한 production 필드 제거 후, getProduction 에서 총합을 계산한다.
여러 함수를 변환 함수로 묶기
Combine Functions into Transform
- 관련있는 여러 파생 변수를 만들어내는 함수가 여러곳에서 만들어지고 사용된다면 그러한 파생 변수를 “변환 함수 (transform function)”를 통해 한 곳으로 모아둘 수 있다.
- 소스 데이터가 변경될 수 있는 경우에는 “여러 함수를 클래스로 묶기 (Combine Functions into Class)”를 사용하는 것이 적절하다.
- 소스 데이터가 변경되지 않는 경우에는 두 가지 방법을 모두 사용할 수 있지만, 변환 함수를 사용해서 불변 데이터의 필드로 생성해 두고 재사용할 수도 있다.
객체 통쨰로 넘기기(preserve whole method) 와 같은 방식을 사용한다.
참조를 값으로 바꾸기
-Change Reference to Value
- 레퍼런스 (Reference) 객체 vs 값 (Value) 객체
- https://martinfowler.com/bliki/ValueObject.html
- “Objects that are equal due to the value of their properties, in this case their x and y coordinates, are called value objects.”
- 값 객체는 객체가 가진 필드의 값으로 동일성을 확인한다.
- 값 객체는 변하지 않는다.
- 어떤 객체의 변경 내역을 다른 곳으로 전파시키고 싶다면 레퍼런스, 아니라면 값 객체를 사용한다.
예제코드
private TelephoneNumber officeTelephoneNumber;
public String getOfficeAreaCode() {
return this.officeTelephoneNumber.getAreaCode();
}
public void setOfficeAreaCode(String areaCode) {
this.officeTelephoneNumber.setAreaCode(areaCode);
}
public String getOfficeNumber() {
return this.officeTelephoneNumber.getNumber();
}
public void setOfficeNumber(String number) {
this.officeTelephoneNumber.setNumber(number);
}
냄새
TelephoneNumber 객체를 레퍼런스 객체가 아닌 값 객체로 사용할 경우 set
해결
setter 를 통해 수정하지 않고 새로운 값 객체를 만들어준다.
리팩토링 후
Person
public class Person {
private TelephoneNumber officeTelephoneNumber;
public String getOfficeAreaCode() {
return this.officeTelephoneNumber.getAreaCode();
}
public String getOfficeNumber() {
return this.officeTelephoneNumber.getNumber();
}
public void setOfficeAreaCode(String areaCode) {
this.officeTelephoneNumber = new TelephoneNumber(areaCode, this.getOfficeNumber());
}
public void setOfficeNumber(String number) {
this.officeTelephoneNumber = new TelephoneNumber(this.getOfficeAreaCode(), number);
}
}
TelephoneNumber
public class TelephoneNumber {
private final String areaCode;
private final String number;
public TelephoneNumber(String areaCode, String number) {
this.areaCode = areaCode;
this.number = number;
}
public String getAreaCode() {
return areaCode;
}
public String getNumber() {
return number;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TelephoneNumber that = (TelephoneNumber) o;
return Objects.equals(areaCode, that.areaCode) && Objects.equals(number, that.number);
}
@Override
public int hashCode() {
return Objects.hash(areaCode, number);
}
}
값 객체이기 때문에 setter 를 없애고 equals, hashCode 메서드를 각 구현해준다.
Author And Source
이 문제에 관하여(리팩토링 - 냄새 6. 가변 데이터), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://velog.io/@coconenne/리팩토링-냄새-6.-가변-데이터
저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
- 계산 자체가 데이터의 의미를 잘 표현하는 경우도 있다.
- 해당 변수가 어디선가 잘못된 값으로 수정될 수 있는 가능성을 제거할 수 있다.
public class ProductionPlan {
private double production;
private List<Double> adjustments = new ArrayList<>();
public void applyAdjustment(double adjustment) {
this.adjustments.add(adjustment);
this.production += adjustment;
}
public double getProduction() {
return this.production;
}
}
applyAdjustment() 함수는 매개변수의 값을 list에 넣어줌과 동시에 총 합을 profuction 필드에 저장을 하는데, 이는 list 에서 총합을 알 수 있는 불필요한 변수이다.
production 필드를 제거 후 list 에 저장된 총합을 return 하도록 한다.
public class ProductionPlan {
private List<Double> adjustments = new ArrayList<>();
public void applyAdjustment(double adjustment) {
this.adjustments.add(adjustment);
}
public double getProduction() {
return adjustments.stream().mapToDouble(Double::valueOf).sum();
}
}
불필요한 production 필드 제거 후, getProduction 에서 총합을 계산한다.
Combine Functions into Transform
- 관련있는 여러 파생 변수를 만들어내는 함수가 여러곳에서 만들어지고 사용된다면 그러한 파생 변수를 “변환 함수 (transform function)”를 통해 한 곳으로 모아둘 수 있다.
- 소스 데이터가 변경될 수 있는 경우에는 “여러 함수를 클래스로 묶기 (Combine Functions into Class)”를 사용하는 것이 적절하다.
- 소스 데이터가 변경되지 않는 경우에는 두 가지 방법을 모두 사용할 수 있지만, 변환 함수를 사용해서 불변 데이터의 필드로 생성해 두고 재사용할 수도 있다.
객체 통쨰로 넘기기(preserve whole method) 와 같은 방식을 사용한다.
참조를 값으로 바꾸기
-Change Reference to Value
- 레퍼런스 (Reference) 객체 vs 값 (Value) 객체
- https://martinfowler.com/bliki/ValueObject.html
- “Objects that are equal due to the value of their properties, in this case their x and y coordinates, are called value objects.”
- 값 객체는 객체가 가진 필드의 값으로 동일성을 확인한다.
- 값 객체는 변하지 않는다.
- 어떤 객체의 변경 내역을 다른 곳으로 전파시키고 싶다면 레퍼런스, 아니라면 값 객체를 사용한다.
예제코드
private TelephoneNumber officeTelephoneNumber;
public String getOfficeAreaCode() {
return this.officeTelephoneNumber.getAreaCode();
}
public void setOfficeAreaCode(String areaCode) {
this.officeTelephoneNumber.setAreaCode(areaCode);
}
public String getOfficeNumber() {
return this.officeTelephoneNumber.getNumber();
}
public void setOfficeNumber(String number) {
this.officeTelephoneNumber.setNumber(number);
}
냄새
TelephoneNumber 객체를 레퍼런스 객체가 아닌 값 객체로 사용할 경우 set
해결
setter 를 통해 수정하지 않고 새로운 값 객체를 만들어준다.
리팩토링 후
Person
public class Person {
private TelephoneNumber officeTelephoneNumber;
public String getOfficeAreaCode() {
return this.officeTelephoneNumber.getAreaCode();
}
public String getOfficeNumber() {
return this.officeTelephoneNumber.getNumber();
}
public void setOfficeAreaCode(String areaCode) {
this.officeTelephoneNumber = new TelephoneNumber(areaCode, this.getOfficeNumber());
}
public void setOfficeNumber(String number) {
this.officeTelephoneNumber = new TelephoneNumber(this.getOfficeAreaCode(), number);
}
}
TelephoneNumber
public class TelephoneNumber {
private final String areaCode;
private final String number;
public TelephoneNumber(String areaCode, String number) {
this.areaCode = areaCode;
this.number = number;
}
public String getAreaCode() {
return areaCode;
}
public String getNumber() {
return number;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TelephoneNumber that = (TelephoneNumber) o;
return Objects.equals(areaCode, that.areaCode) && Objects.equals(number, that.number);
}
@Override
public int hashCode() {
return Objects.hash(areaCode, number);
}
}
값 객체이기 때문에 setter 를 없애고 equals, hashCode 메서드를 각 구현해준다.
Author And Source
이 문제에 관하여(리팩토링 - 냄새 6. 가변 데이터), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://velog.io/@coconenne/리팩토링-냄새-6.-가변-데이터
저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
- https://martinfowler.com/bliki/ValueObject.html
- “Objects that are equal due to the value of their properties, in this case their x and y coordinates, are called value objects.”
- 값 객체는 객체가 가진 필드의 값으로 동일성을 확인한다.
- 값 객체는 변하지 않는다.
private TelephoneNumber officeTelephoneNumber;
public String getOfficeAreaCode() {
return this.officeTelephoneNumber.getAreaCode();
}
public void setOfficeAreaCode(String areaCode) {
this.officeTelephoneNumber.setAreaCode(areaCode);
}
public String getOfficeNumber() {
return this.officeTelephoneNumber.getNumber();
}
public void setOfficeNumber(String number) {
this.officeTelephoneNumber.setNumber(number);
}
TelephoneNumber 객체를 레퍼런스 객체가 아닌 값 객체로 사용할 경우 set
setter 를 통해 수정하지 않고 새로운 값 객체를 만들어준다.
public class Person {
private TelephoneNumber officeTelephoneNumber;
public String getOfficeAreaCode() {
return this.officeTelephoneNumber.getAreaCode();
}
public String getOfficeNumber() {
return this.officeTelephoneNumber.getNumber();
}
public void setOfficeAreaCode(String areaCode) {
this.officeTelephoneNumber = new TelephoneNumber(areaCode, this.getOfficeNumber());
}
public void setOfficeNumber(String number) {
this.officeTelephoneNumber = new TelephoneNumber(this.getOfficeAreaCode(), number);
}
}
public class TelephoneNumber {
private final String areaCode;
private final String number;
public TelephoneNumber(String areaCode, String number) {
this.areaCode = areaCode;
this.number = number;
}
public String getAreaCode() {
return areaCode;
}
public String getNumber() {
return number;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TelephoneNumber that = (TelephoneNumber) o;
return Objects.equals(areaCode, that.areaCode) && Objects.equals(number, that.number);
}
@Override
public int hashCode() {
return Objects.hash(areaCode, number);
}
}
값 객체이기 때문에 setter 를 없애고 equals, hashCode 메서드를 각 구현해준다.
Author And Source
이 문제에 관하여(리팩토링 - 냄새 6. 가변 데이터), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@coconenne/리팩토링-냄새-6.-가변-데이터저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)