《重构:改善既有代码的设计》 重新组织数据 之 8
《重构:改善既有代码的设计》中提到过很多重构方法,关于重新组织数据的方法有16种。本文介绍:
将对象之间的关联由双向改为单向 change bidirectional association to unidirectional
- 名称:将对象之间的关联由双向改为单向 change bidirectional association to unidirectional
- 概要:两个类之间有双向关联,但其中一个类如今不再需要另一个类的特性。去除不必要的关联。
- 动机:双向关联使两个类有了依赖
- 做法:
- 找出保存“你想去除的指针”的字段,检查它的每一个用户,判断是否可以去除该指针。不但要检查直接访问点,也要检查调用这些直接访问点的函数。考虑有无可能不通过指针取得被引用对象。如果有可能,就可以对取值函数使用substitute algorithm ,从而让客户在没有指针的情况下也可以使用该取值函数。对于使用该字段的所有函数,考虑将被引用对象作为参数传进去。
- 如果客户使用了取值函数,先运用self encapsulate field将待删除字段自我封装起来,然后使用 substitute algorithm对付取值函数,令它不再使用该字段。然后编译,测试
- 如果客户并没有使用取值函数,就可以直接修改待删除字段的所有被引用点:改以其他途径获得该字段所保存的对象,每次修改完,编译并测试
- 如果已经没有任何函数使用待删除字段,移除所有对该字段的更新逻辑,然后移除该字段。
- 编译,测试
- 代码演示
修改之前的代码:
/////////////////////////.h
#ifndef MAINWINDOWTEST_H
#define MAINWINDOWTEST_H
#include <QMainWindow>
#include <QSet>
class order;
class customer
{
public:
QSet<order *> FriendOrders();
void AddOrder(order * porder);
double getDiscount();
double getPriceFor(order *porder);
private:
QSet<order *> m_pOrderSet;
};
class order
{
public:
void setCustomer(customer *customer);
customer* getCustomer() const;
double getDiscountedPrice();
private:
customer *m_pcustomer;
};
#endif // MAINWINDOWTEST_H
//////////////////////////.cpp
void order::setCustomer(customer *customer)
{
if (m_pcustomer != nullptr)
{
m_pcustomer->FriendOrders().remove(this);
}
m_pcustomer = customer;
if (m_pcustomer != nullptr)
{
m_pcustomer->FriendOrders().insert(this);
}
}
customer* order::getCustomer() const
{
return m_pcustomer;
}
double order::getDiscountedPrice()
{
return 100 * (1 - m_pcustomer->getDiscount());
}
QSet<order *> customer::FriendOrders()
{
return m_pOrderSet;
}
void customer::AddOrder(order * porder)
{
//希望在customer中也可以修改
m_pOrderSet.insert(porder);
porder->setCustomer(this);
}
double customer::getDiscount()
{
return 0.95;
}
double customer::getPriceFor(order *porder)
{
return porder->getDiscountedPrice();
}
现在问题来了,如果没有customer对象,就不会存在order对象,所以我想将从order到customer的连接移除掉。
1) 将order中的m_pcustomer移除掉,使用该变量的地方,直接传递参数
随软移除了双向关联,但两者之间还是有互相依赖。后续继续重构
修改之后的代码:
/////////////////////////.h
#ifndef MAINWINDOWTEST_H
#define MAINWINDOWTEST_H
#include <QMainWindow>
#include <QSet>
class order;
class customer
{
public:
QSet<order *> FriendOrders();
void AddOrder(order * porder);
double getDiscount();
double getPriceFor(order *porder);
private:
QSet<order *> m_pOrderSet;
};
class order
{
public:
// void setCustomer(customer *customer);
// customer* getCustomer() const;
double getDiscountedPrice(customer *customer);
private:
//customer *m_pcustomer;
};
#endif // MAINWINDOWTEST_H
//////////////////////////.cpp
//void order::setCustomer(customer *customer)
//{
// if (m_pcustomer != nullptr)
// {
// m_pcustomer->FriendOrders().remove(this);
// }
// m_pcustomer = customer;
// if (m_pcustomer != nullptr)
// {
// m_pcustomer->FriendOrders().insert(this);
// }
//}
//customer* order::getCustomer() const
//{
// return m_pcustomer;
//}
double order::getDiscountedPrice(customer *customer)
{
return 100 * (1 - customer->getDiscount());
}
QSet<order *> customer::FriendOrders()
{
return m_pOrderSet;
}
void customer::AddOrder(order * porder)
{
//希望在customer中也可以修改
m_pOrderSet.insert(porder);
//porder->setCustomer(this);
}
double customer::getDiscount()
{
return 0.95;
}
double customer::getPriceFor(order *porder)
{
return porder->getDiscountedPrice(this);
}