除了通用图形功能外,它还实现了3D空间中节点定位的功能.这个扩展的3D功能我想分离成一个子类,导致:
>轻量级通用类(MyGenericGraph,
MyGenericGraphNode,MyGenericGraphEdge)
>重量较重的专用子类
(My3DGraph,My3DGraphNode,
My3DGraphEdge)
从理论上讲,到目前为止一切顺利.
问题:
我必须确保(并且最好在编译时)不能将通用的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对应物)
这个解决方案的问题:它会给一个相当简单的问题增加大量的复杂性.
此外,由于My3DGraph应该能够处理My3DGraphNodes和MyGenericGraphNodes,我必须将MyGenericGraph的方法实现为:
- (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 g@R_301_6610@tyStrength; //...}// 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继承任何逻辑.我已经冗余地实现了维度功能.坏.很糟糕.
建议的类结构体系结构:
>完全摆脱任何“维度风味”课程.使用基本和必需的逻辑保持类严格准确的数据结构.
>介绍提供维度属性的MyVertex类.节点的方法(如果需要)(通过向MyGraphNode添加MyVertex *顶点ivar(默认为nil)).这也使得在MyVertexCloud中重新使用它们变得更加容易,MyVertexCloud是一个简单的点云容器,应该可以用来改进我的力驱动布局算法.
>将对图形数据结构不严格必要的任何逻辑委托给特殊目的帮助程序类.因此,MyGraphNodeClusterRelaxer将负责任何特定于可视图形布局的逻辑.
>借助我的单链继承链和模块化,子类化MyGraph将变得快速而简单.
>利用外部MyGraphNodeClusterRelaxer也可以让我放松一下图形节点的子集,而不仅仅是整个图形,就像My3DGraph所做的那样.
> MyGraphNodeCluster只不过是基本上是一组节点的包装器(所有相同的图形).它的子类在集群成员资格标准和算法中可以更具体.
>从整个图形中获取MyGraphNodeCluster就像调用(MyGraphNodeCluster *)[myGraph nodeCluster]一样简单;从那里你得到一个MyVertexCloud via(MyVertexCloud *)[myNodeCluster vertexCloud] ;.由于某些原因,反向(对于后者)是不可能的.
(简体)实体关系模型:
总结以上是内存溢出为你收集整理的在Objective-C中对一组相互依赖的类进行子类化并确保类型安全全部内容,希望文章能够帮你解决在Objective-C中对一组相互依赖的类进行子类化并确保类型安全所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)