C++ 如何删除/重构a«;朋友»;依赖项声明是否正确?
这个问题的背景是基于一个实际示例,我想从一对用于管理对共享资源的读/写锁定访问的类中删除一个«friend»依赖项 以下是该场景的原始结构设计的抽象: 用红色标记,我想从设计中删除这个丑陋的«friend»依赖项 简言之,我为什么会有这样的东西:C++ 如何删除/重构a«;朋友»;依赖项声明是否正确?,c++,refactoring,friend,C++,Refactoring,Friend,这个问题的背景是基于一个实际示例,我想从一对用于管理对共享资源的读/写锁定访问的类中删除一个«friend»依赖项 以下是该场景的原始结构设计的抽象: 用红色标记,我想从设计中删除这个丑陋的«friend»依赖项 简言之,我为什么会有这样的东西: ClassA提供者在多个域上共享对ClassA的引用 并发访问客户端实例 客户端实例应仅通过ClassA接受器helper类访问ClassA 管理内部的 ClassA将所有拟用于受保护的ClassA Accessor的方法隐藏起来 因此ClassA可
ClassA提供者
在多个域上共享对ClassA
的引用
并发访问客户端
实例客户端
实例应仅通过ClassA接受器
helper类访问ClassA
管理内部的ClassA
将所有拟用于受保护的ClassA Accessor
的方法隐藏起来ClassA
可以确保Client
需要使用ClassA accessor
实例ClassA
的实例保留在
定义状态,如果客户端操作退出(例如,由于未捕获的异常)。想想
ClassA
提供(内部可见)成对操作,如lock()
/unlock()
或open()
/close()
在任何情况下都应该调用(状态)反转操作,尤其是当客户端由于错误而崩溃时
例外情况。
这可以通过classa访问器的生命周期行为(析构函数)安全地处理
实施可以确保这一点。
以下序列图说明了预期的行为:
另外,只要使用
C++作用域块:
// ...
{
ClassAAccessor acc(provider.getClassA());
acc.lock();
// do something exception prone ...
} // safely unlock() ClassA
// ...
到目前为止一切正常,但是出于一些好的原因,应该删除ClassA
和ClassA接受者之间的«friend»依赖关系
在UML2.2上层结构中,C.2节“对以前的UML的更改”中说:下表列出了UML1.x的预定义标准元素,这些元素现在已经过时了。。。«朋友»…
我见过的大多数编码规则和指导原则都禁止或强烈反对使用friend,以避免将类导出到friends时的紧密依赖性。这会带来一些严重的维护问题
正如我的问题标题所说
如何正确删除/重构好友声明(最好从类的UML设计开始)?让我们先设置一些重构约束:
ClassaaAccessor的公共可见接口不应以任何方式更改
ClassA内部操作不应在公众中可见/可访问
不应损害原始设计的整体性能和占地面积
步骤1:引入抽象接口
第一步,我分解了«friend»原型,并用一个类(接口)替换它
内部接口
和适当的关系
构成«friend»依赖关系的内容被分解为一个简单的依赖关系(蓝色)和
针对新InternalInterface
元素的«调用»依赖项(绿色)
步骤2:将构成«调用»依赖项的操作移动到接口
下一步是使«调用»依赖关系成熟。为此,我将图表更改如下:
- «调用»依赖项从转换为定向关联
ClassAAccessor
到内部接口
(即ClassAAccessor
包含
一个私有变量internalInterfaceRef
)
- 相关操作已从
ClassA
移动到InternalInterface
InternalInterface
通过受保护的构造函数进行扩展,在继承中非常有用
只是
ClassA
与内部接口的«泛化»关联
标记为受保护
,
所以它被公开化了
步骤3:将实施中的所有内容粘合在一起
在最后一步中,我们需要建模ClassAAccessor
如何获得对InternalInterface
的引用。由于泛化不公开可见,ClassA访问器
无法再从构造函数中传递的ClassA
引用对其进行初始化。但是ClassA
可以访问InternalInterface
,并使用ClassA访问程序中引入的额外方法setInternalInterfaceRef()
传递引用:
这是C++实现:
class ClassAAccessor {
public:
ClassAAccessor(ClassA& classA);
void setInternalInterfaceRef(InternalInterface & newValue) {
internalInterfaceRef = &newValue;
}
private:
InternalInterface* internalInterfaceRef;
};
当新引入的方法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.
}
因此,ClassA Accessor的构造函数可以按以下方式重写:
ClassAAccessor::ClassAAccessor(ClassA& classA)
: internalInterfaceRef(0) {
classA.attachAccessor(*this);
}
最后,通过引入另一个InternalClientInterface
,您可以进一步解耦实现:
至少有必要提到,与使用friend
声明相比,这种方法有一些缺点:
这使代码更加复杂
friend
不需要引入抽象接口(这可能会影响封装外形,因此约束3.未完全实现)
protected
泛化关系SIP没有得到UML表示的很好支持(我不得不使用该约束)
依赖关系不涉及属性或操作的访问。依赖关系用于表示模型元素之间的定义依赖关系!
如何从您的系统中删除所有依赖项