πάν*_*ῥεῖ 14 c++ refactoring friend
这个问题的背景是基于一个实际的示例,我想从一对用于管理对共享资源的读/写锁定访问的类中删除«friend»依赖项.
这是该场景的原始结构设计的抽象:

标记为红色,我想从设计中删除这个丑陋的"朋友"依赖.
简而言之,为什么我在那里有这个东西:
ClassAProvider共享对ClassA多个并发访问Client实例的引用Client实例应该ClassA只通过ClassAAccessor管理内部的辅助类来访问ClassA将所有打算使用的方法隐藏起来ClassAAccessor.ClassA可以确保Client需要使用ClassAAccessor实例ClassA如果Client操作失败(因为例如未捕获的异常),则该模式主要用于确保将实例保留在已定义的状态.考虑
ClassA提供(内部可见的)配对操作,如lock()/ unlock()或open()/ close().
在任何情况下都应调用(state-)反转操作,尤其是当客户端由于异常而崩溃时.
这可以通过ClassAAcessor生命周期行为安全地处理,析构函数实现可以确保它.以下序列图说明了预期的行为:

此外,只需使用C++范围块,Client实例就可以ClassA轻松实现对访问的精确控制:
// ...
{
ClassAAccessor acc(provider.getClassA());
acc.lock();
// do something exception prone ...
} // safely unlock() ClassA
// ...
Run Code Online (Sandbox Code Playgroud)
到目前为止一切都很好,但由于一些很好的理由ClassA,ClassAAccessor应该删除之间的"朋友"依赖关系
The following table lists predefined standard elements for UML 1.x that are now obsolete. ... «friend» ... 正如我的问题标题所说
如何正确删除/重构朋友声明(最好从我的课程的UML设计开始)?
让我们首先为重构设置一些约束:
第1步:介绍一个抽象接口
对于第一次拍摄,我将"朋友"刻板印象排除在外,并将其替换为类(界面)
InternalInterface和适当的关系.

构成«朋友»依赖关系的内容被分成了一个简单的依赖关系(蓝色)和一个«call»依赖关系(绿色)对新InternalInterface元素.
步骤2:将构成«call»依赖关系的操作移动到接口
下一步是成熟«call»依赖.为此,我按如下方式更改图表:

ClassAAccessor到InternalInterface(即ClassAAccessor包含一个私有变量internalInterfaceRef).ClassA到了InternalInterface.InternalInterface 使用受保护的构造函数进行扩展,它仅在继承中有用.ClassA'«泛化»协会InternalInterface被标记为protected,因此它被公开隐形.第3步:在实现中将所有内容粘合在一起
在最后一步中,我们需要建模一种如何ClassAAccessor获得引用的方法InternalInterface.由于泛化不公开,ClassAAcessor因此无法再从ClassA构造函数中传递的引用初始化它.但是ClassA可以访问InternalInterface,并使用setInternalInterfaceRef()引入的额外方法传递引用ClassAAcessor:

这是C++实现:
class ClassAAccessor {
public:
ClassAAccessor(ClassA& classA);
void setInternalInterfaceRef(InternalInterface & newValue) {
internalInterfaceRef = &newValue;
}
private:
InternalInterface* internalInterfaceRef;
};
Run Code Online (Sandbox Code Playgroud)
当调用新引入的方法ClassA::attachAccessor()
方法时,实际调用此方法:
class ClassA : protected InternalInterface {
public:
// ...
attachAccessor(ClassAAccessor & accessor);
// ...
};
ClassA::attachAccessor(ClassAAccessor & accessor) {
accessor.setInternalInterfaceRef(*this); // The internal interface can be handed
// out here only, since it's inherited
// in the protected scope.
}
Run Code Online (Sandbox Code Playgroud)
因此,ClassAAccessor的构造函数可以通过以下方式重写:
ClassAAccessor::ClassAAccessor(ClassA& classA)
: internalInterfaceRef(0) {
classA.attachAccessor(*this);
}
Run Code Online (Sandbox Code Playgroud)
最后,你可以通过引入另一个InternalClientInterface这样的方式来解耦实现:

至少有必要提一下,这种方法与使用friend声明相比有一些缺点:
friend 不需要引入抽象接口(可能影响足迹,因此约束3.未完全实现)protected泛化relationsip没有很好地利用UML表示支持(我不得不使用限制)| 归档时间: |
|
| 查看次数: |
1174 次 |
| 最近记录: |