基本情况
在程序员的修炼之道之中,说到:
这个建议能简单地应用到大多数场合。简单说就是,分配资源的函
数或对象,对释放资源应负有责任。
这其实就是我们常说的谁分配的就谁负责释放,这也是内存释放的一个原则,这一个原则,可以推而广之,就是谁分配的资源,就谁分配释放;这真是非常常用的东西,比如数据库存连接的分配与释放。
我写一个简单的例子说明这种情况,这一个例子就是单纯为了实现价格读出后,然后价格更改,再写入:
void Market::readCustomer()
{
fopen_s(&m_pf, "test.txt", "r+");
if (m_pf != nullptr)
{
CUSTOMER p = {0};
fscanf(m_pf, "%s %d", p.name, &p.price);
printf("%s %d\n", p.name, p.price);
}
}
void Market::writeCustomer()
{
if (m_pf != nullptr)
{
CUSTOMER p = { "zhangsan", m_money };
fprintf(m_pf, "%s %d\n", p.name, p.price);
printf("%s %d\n", p.name, p.price);
fclose(m_pf);
m_pf = nullptr;
}
}
void Market::updateCustomer(int money)
{
this->readCustomer();
m_money = money;
this->writeCustomer();
}
为了清楚其见,写下头文件的部分代码:
typedef struct Customer
{
char name[10];
int price;
}CUSTOMER;
private:
FILE* m_pf;
int m_money;
上面代码updateCustomer,看着是没问题的,但发现其耦合了变量 m_pf,从函数角度来看,的确是耦合这一个变量,不是一个好事;
后来加了些需要,要求100元以上,才更改价格,程序员,可能更改成下面这个样子:
void Market::updateCustomer(int money)
{
this->readCustomer();
m_money = money;
if(m_money > 100)
{
this->writeCustomer();
}
}
运行代码,不一会,就提示打开的文件过多,原来,那些小于100的客户,只打开了文件的链接,没有关闭文件链接,与是可能更改如下:
void Market::updateCustomer(int money)
{
this->readCustomer();
m_money = money;
if(m_money > 100)
{
this->writeCustomer();
}
else
{
fclose(m_pf);
}
}
现在问题是解决了,但是出现一个变量的三处耦合,最严重的是文件的状态变得混乱。
程序员修炼这样描述这种问题:
这个问题已修复——如果不考虑新的平衡,文件现在的确关闭了。
但是,这个修复方案意味着,三个例程因为共享变量m_pf耦合
在了一起,而且对文件何时是打开状态、何时是关闭状态的跟踪开始变
得混乱。我们正掉入一个陷阱,如果继续走这条路,情况将开始迅速恶
化。这是不平衡的!
那么,如果用有始有终的原则,则更改如下:
void Market::readCustomer(FILE *pf)
{
if (pf != nullptr)
{
CUSTOMER p = {0};
fscanf(pf, "%s %d", p.name, &p.price);
printf("%s %d\n", p.name, p.price);
}
}
void Market::writeCustomer(FILE *pf)
{
if (pf != nullptr)
{
CUSTOMER p = { "zhangsan", m_money };
fprintf(pf, "%s %d\n", p.name, p.price);
printf("%s %d\n", p.name, p.price);
}
}
void Market::updateCustomer(int money)
{
FILE *pf;
fopen_s(&pf, "test.txt", "r+");
this->readCustomer(pf);
m_money = money;
this->writeCustomer(pf);
fclose(pf);
pf = nullptr;
}
这样代码就清晰了很多:
我们修改了代码,将文件引用通过参数传进去,而不是在内部持有
引用[5]。现在,关于该文件的所有职责都在 updateCustomer例程中。
它打开文件,再(有始有终地)在返回之前关闭它。例程保持了文件使
用的平衡:打开和关闭在同一个位置,而且非常明显的是,每次对文件
的打开操作都有一个对应的关闭操作。重构还删除了一个丑陋的共享变
量。
总结
代码中时时处处都在遵守这一原则,代码才能清晰,代码才能简单。