리팩터링/리팩터링 기법
리팩터링 기법. 참조를 값으로 바꾸기(Change Reference to Value)
developer-tj
2023. 3. 16. 12:00
반응형
참조를 값으로 바꾸기(Change Reference to Value)는 객체를 참조로 전달하는 것이 아니라 복사해서 값으로 전달하는 방식으로 변경하는 리팩터링 기법입니다.
이 기법은 가변 데이터 문제를 해결할 수 있으며, 객체의 상태를 보호할 수 있습니다.
객체를 전달할 때 객체의 복사본을 전달하므로, 함수에서 객체의 값을 변경하더라도 원본 객체에는 영향을 주지 않습니다.
참조를 값으로 변경할 때는, 객체가 크거나 복사하는 데 많은 비용이 드는 경우를 제외하고는 크게 문제될 것이 없습니다.
객체가 커서 복사비용이 많이 든다면 참조로 전달하는 것이 더 효율적일 수 있습니다.
참조를 값으로 바꾸기를 적용하는 방법은 다음과 같습니다.
- 객체가 얕은 복사를 허용하는지 확인합니다. 객체가 얕은 복사를 허용하면 값으로 변경하기 쉽습니다.
- 객체가 깊은 복사를 필요로 하는 경우, 복사 생성자와 대입 연산자를 구현합니다.
- 해당 객체를 참조하던 변수를 값으로 변경합니다. 이때, 객체를 복사하거나, 객체를 직접 생성할 수 있습니다.
- 코드를 검증하고 테스트합니다. 변경된 코드가 기존 코드와 동작이 동일한지 검증합니다.
다음과 같은 예제 코드가 있습니다.
class Person {
public:
Person(const std::string& name) : name_(name) {}
std::string getName() const { return name_; }
void setName(const std::string& name) { name_ = name; }
private:
std::string name_;
};
class Order {
public:
Order(Person& person, double amount) : person_(person), amount_(amount) {}
double getAmount() const { return amount_; }
std::string getPersonName() const { return person_.getName(); }
private:
Person& person_;
double amount_;
};
int main() {
Person person("John");
Order order(person, 100.0);
std::cout << "Person name: " << order.getPersonName() << std::endl;
std::cout << "Order amount: " << order.getAmount() << std::endl;
// Person의 이름을 변경하면 Order에도 반영됩니다.
person.setName("Tom");
std::cout << "Person name: " << order.getPersonName() << std::endl;
return 0;
}
출력
Person name: John
Order amount: 100
Person name: Tom
위 코드에서 Order 클래스의 생성자에서 Person 객체를 참조로 전달받아서 Person 객체의 값이 변경되면 Order 객체의 값도 변경됩니다.
이를 방지하기 위해서는 Order 클래스의 Person& person_; 맴버를 Person person_; 변경하여 값으로 가지면 됩니다.
class Person {
public:
Person(const std::string& name) : name_(name) {}
std::string getName() const { return name_; }
void setName(const std::string& name) { name_ = name; }
private:
std::string name_;
};
class Order {
public:
Order(Person& person, double amount) : person_(person), amount_(amount) {}
double getAmount() const { return amount_; }
std::string getPersonName() const { return person_.getName(); }
private:
Person person_;
double amount_;
};
int main() {
Person person("John");
Order order(person, 100.0);
std::cout << "Person name: " << order.getPersonName() << std::endl;
std::cout << "Order amount: " << order.getAmount() << std::endl;
// Person의 이름을 변경해도 Order에도 반영되지 않습니다.
person.setName("Tom");
std::cout << "Person name: " << order.getPersonName() << std::endl;
return 0;
}
출력
Person name: John
Order amount: 100
Person name: John
Order 클래스 내부에서 Person 멤버 변수를 값으로 선언하여 사용하였습니다.
이를 통해 Order 객체는 Person 객체를 가지게 되어, Person 객체가 변경되어도 Order 객체의 값은 변하지 않습니다.