问题引入:
今天在做一个用来限制对象位置的功能类,要完成的任务就是当对象被拖动的时候,不允许超出工作区域多少距离。这个问题不好处理的地方就是这个工作区域的获取问题,因为无法知道工作区域发生更改,并且工作区域更改的地方也无法直接设置给对象,即使能设置,也无法设置给这么多对象。因此这就是一个简单的一对多问题,即一个变化需要引起多个的变化。
问题引出:
简化一下上述问题。有一个对象CSample,其内部有一个属性miCount需要根据一个系统相关的属性miSystemValue来进行计算。在无法直接接收到这个系统属性发生更改的前提下,如何让其所有实例化出来的对象都能重新进行计算呢?(注:下面的代码没进行编译,随便写了下例子方便说明。)
class CSample { public: CSample(); ~CSample(); int GetCount() { return miCount; } protected: MakeCount(){miCount = miValue + miSystem;} private: int miCount; int miValue; int miSystem; // 系统所提供的一个参数,全系统都唯一的 } int main() { CSample loSample1; CSample loSample2; CSample loSample3; cout << loSample1.GetCount << endl; cout << loSample2.GetCount << endl; cout << loSample3.GetCount << endl; // 假设这时候miSystem发生了变化 // 如何让上述三个对象重新计算其内部的miCount的值? return 0; }
解决办法:
1、主动索取方式。
所有实例化出来的对象,每次在计算的时候都直接主动去获取系统的这个参数,这样不管多少个实例,系统参数如何改变都能保证正确。假如GetSystemValue是获取系统参数的函数,则只需写成miCount = miValue + GetSystemValue()即可。
好,下面问题来了。
1、如果无法直接获取到系统参数怎么办?
2、如果这种计算效率很低,要求优化,怎么办?
问题1是这个方法最不好解决的地方,因为这个方法就是假设能直接获取的基础上,这里提出这个问题是方便后面的方法能考虑到这个问题。问题2有一定的优化方式,就是自己记住旧的系统参数,每次进行计算前进行判定需不需要重新计算,这样能避免每次都无厘头的进行计算,但是效率效果还不是很好。
2、提供静态函数。
类的静态函数只能操做静态变量,因此系统参数作为静态变量存储在类内部,所有实例化的类共享这个变量,注意要传进去类的实例化指针,才能操纵非静态成员变量。这里是重新计算miCount值。
对于上面提到的两个问题,这种方式都比较好的进行了解决。但是这中方法有个缺陷就是在获取到系统参数更改的地方,必须拥有所有实例化的对象指针,不然如何在这里调用这个静态函数的同时传入对象指针呢?因此,问题3来了。
如果实例化的对象位置无法预知,怎么办?
3、提供一个管理器。
上述3个问题,要想同时解决,那么需要满足的条件有:类需要提供函数去被动触发进行计算,不能任何时候都计算,以及需要将所有实例化的对象集中起来进行管理。一种好的解决方式是,提供一个全局的容器,在对象的构造函数内主动加入到容器中去,当系统参数发生更改的时候,遍历容器去调用触发计算的接口。
后记:本来看起来很简单的一个功能,在实际实现的时候才发现因素导致很多方法不适用,其实归根到底就是程序灵活性的问题。