在Objective-C中对一组相互依赖的类进行子类化并确保类型安全
我已经实现了一个基本的图形类(不像“绘图”那样,而是像“网络”中那样!),这将用于基本的图形理论任务. (参见下面的摘要头文件片段)
除了通用图形功能外,它还实现了3D空间中节点定位的功能.这个扩展的3D功能我想分离成一个子类,导致: >轻量级通用类(MyGenericGraph, 从理论上讲,到目前为止一切顺利. 问题: 我必须确保(并且最好在编译时)不能将通用的MyGenericGraphNodes添加到特定的My3DGraph中,因为它高度依赖于My3DGraphNode中添加的3D逻辑. (虽然通用MyGenericGraph根本不关心.) 核心问题很简单:我不能从MyGenericGraph中覆盖这些方法: - (void)addNode:(MyGenericGraphNode *)aNode; - (void)removeNode:(MyGenericGraphNode *)aNode; 在我的子类My3DGraph中使用这些方法: - (void)addNode:(My3DGraphNode *)aNode; - (void)removeNode:(My3DGraphNode *)aNode; 到目前为止,我已经提出了三个可能的解决方案,但在选择其中任何一个之前,我想听听他们的一些意见. (并希望在我的路上省去一些不可预见的麻烦) 我想知道是否还有另外一个优秀的解决方案或设计模式,我错过了?或者如果不是:我会选择哪种解决方案? 可能的解决方案1 >添加一个抽象类MyAbstractGraph,它基本上与我当前MyGenericGraph实现的通用部分相同(见下文),但缺少任何节点添加/删除方法.然后,MyGenericGraph和My3DGraph将成为MyAbstractGraph的子类.虽然MyGenericGraph只实现缺少节点添加/删除方法,但My3DGraph将进一步实现所有3D空间功能.两者都需要各自的节点类类型. (同样适用于MyGenericGraphNode和MyGenericGraphEdge及其3D对应物) 这个解决方案的问题:它会给一个相当简单的问题增加大量的复杂性. - (void)addNode:(MyAbstractGraphNode *)aNode;` 但My3DGraph的方法如下: - (void)addNode:(My3DGraphNode *)aNode; 同样,除了我的通用图形,它不会接受3d节点.这会不必要地暴露抽象类. 可能的解决方案2 真正简单的子类将MyGenericGraphNode / My3DGraphNode分配权移动到MyGenericGraph / My3DGraph中,得到类似于: – (MyGenericGraphNode *)newNode;,它将分配并返回正确类型的节点并立即将其添加到图形中.然后可以摆脱 – (void)addNode:(MyGenericGraphNode *)aNode;完全没有机会添加节点而不是从图本身内添加节点(从而确保适当的类成员资格). 这个解决方案的问题:虽然它不会给类增加任何值得注意的复杂性,但另一方面它会让我再次陷入同样的??困境,只要我说 – 想要为我的My3DGraph添加功能来移动一个节点从一个图形到另一个图形.一个类应该能够处理一个对象,无论是谁创建它以及为什么. 可能的解决方案3 真正简单的子类为3D节点添加专用方法并禁用泛型方法,如下所示: - (void)addNode:(MyGenericGraphNode *)aNode { [self doesNotRecognizeSelector:_cmd]; } - (void)add3DNode:(My3DGraphNode *)aNode { //bla } 这个解决方案的问题:通用[a3DGraph addNode:aNode]方法仍会出现在Xcode的自动完成中,在编译时静默传递,但在运行时意外抛出异常.经常出现头痛. 可能的解决方案4 我的图的真实和简单的子类,只是节点和边的泛型类,但在节点类中有一个额外的ivar指针My3DUnit * dimensionUnit:默认为MyGraph的nil,它实现了所有的逻辑和属性,并为它提供了3D功能.节点类. My3DUnit可以简单地以静默方式创建(例如,位置(0,0))并附加到通用节点,以防它们被添加到3d图形中,从而使其兼容.反之亦然,如果将具有DL3DUnitgets的节点添加到通用图中,则只需将其保持连接并添加节点. 头文件 以下是我的类的(缩短的)标题: @interface MyGraph : NSObject { // properties: NSMutableSet *nodes; //... //extended 3D properties: double gravityStrength; //... } // functionality: - (void)addNode:(MyGraphNode *)aNode; - (void)removeNode:(MyGraphNode *)aNode; //... //extended 3D functionality: - (double)kineticEnergy; //... @end @interface MyGraphNode : NSObject { // properties: MyGraph *graph; NSMutableSet *edges; //... //extended 3D properties: My3DVector position; //... } // properties: @property (nonatomic,readonly) MyGraph *graph; @property (nonatomic,readonly) NSSet *edges; @property (nonatomic,readonly) NSSet *neighbors; @property (nonatomic,readonly) NSUInteger degree; //... //extended 3D properties @property (nonatomic,assign) My3DVector position; //... // functionality: - (void)attachToGraph:(MyGraph *)aGraph; - (void)detachFromGraph; - (void)addNeighbor:(MyGraphNode *)aNode; - (void)removeNeighbor:(MyGraphNode *)aNode; - (BOOL)hasNeighbor:(MyGraphNode *)aNode; - (NSSet *)neighbors; - (NSUInteger)degree; //... //extended 3D functionality: - (double)distanceToNode:(DLGraphNode *)aNode; //... @end @interface MyGraphEdge : NSObject { // properties: MyGraphNode *predecessor; MyGraphNode *successor; //... } // properties: @property (nonatomic,readonly) MyGraphNode *predecessor; @property (nonatomic,readonly) MyGraphNode *successor; //... // functionality: - (id)initWithPredecessorNode:(MyGraphNode *)predecessorNode successorNode:(MyGraphNode *)successorNode; + (MyGraphEdge *)edgeWithPredecessorNode:(MyGraphNode *)predecessorNode successorNode:(MyGraphNode *)successorNode; - (BOOL)hasNeighbor:(MyGraphNode *)aNode; - (BOOL)hasSuccessor:(MyGraphNode *)aNode; - (BOOL)hasPredecessor:(MyGraphNode *)aNode; @end 这基本上就是我的图表现在的实现方式.显然还有很多,但你应该明白这个想法. (正如您可能已经注意到MyGenericGraphEdge目前没有实现3D空间功能,但它可能在未来,例如计算其中心点,例如,因此我将它包括在这里.) [编辑:添加解决方案4灵感来自ughoavgfhw;修复了解决方案1中的错误,抱歉:(] 解决方法
解决方案,快速而肮脏:
在重新分析了我的课程结构,并在我计划的图表类系列中找到了未来发展中潜在陷阱的几个以前不可预见的含义后,我得出的结论与我提出的解决方案4相当,但伴随着一些重大的重组(见附简化ER图).我的计划是,不是拥有繁重的多用途超级类,而是有几个单一用途的组件(如果构造良好)可以组合成各种特殊用途(和相对轻量级)的工具集. 简单继承的潜在缺陷: 如果我在MyGenericGraph的子类中实现维度特征集,那么这使我基本上不可能轻松地创建更具体的图子类(例如专用树),可以是轻量级和通用的(如MyGenericGraph)或维度(如My3DGraph) .对于MyGenericTree类(例如用于树分析),我必须继承MyGenericGraph.对于My3DTree(例如树形显示),我必须继承My3DGraph.因此My3DTree不能从MyGenericTree继承任何逻辑.我已经冗余地实现了维度功能.坏.很糟糕. 建议的类结构体系结构: >完全摆脱任何“维度风味”课程.使用基本和必需的逻辑保持类严格准确的数据结构. (简体)实体关系模型: (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |