Reconstruct a complicated data structure

Source: Internet
Author: User

During the development of the gix4 project, a complicated data structure is encountered. Complicated because it has many restrictions. My job is to add new features in the existing system and refactor some of the old features in the process.Code.

Constraints and requirements

The following constraints are necessary in the system and cannot be bypassed for code development.

1.There are many entity classes in the project that contain a multi-tree relationship and logic.

2.These entities have a tree-like relationship. At runtime, there is only a key relationship, but no corresponding entity reference relationship.
Because gix4 is a data analysis software, the data volume is large. It takes a long time to establish a relationship, so the server is only responsible for data. In this way, the data obtained by the client is just a simple collection of objects.

3.Only one specific operation can be used to sort all objects in an object set: void move (Object item, int32 index ).
This constraint is generated mainly because: 1. csla is used as the framework for implementing distributed applications. All entity sets must inherit businesslistbase. Operations on entities in this set often change the state of the entity. 2. In the current openexpressapp framework, the entity must be directly bound to the presentation layer, it cannot be converted, for example, "viewmodel ". Of course, a large amount of data processing also requires that the data should not be converted every time.

4.Businesses require that entities can be sorted. (This is called "logical sequence number" and "logical sorting ".) These sequence numbers will be persisted into the database.

5.Objects in the set should be sorted by the "logical sequence number. (Hereinafter referred to as "physical serial number" and "physical sorting ")

6.The child node set of each node in the tree should also be physically sorted by the "logical serial number.

7.All the above operations are implemented in the openexpressapp framework, rather than the application layer.

Original code

I. tree structure definition has been defined and widely used in the old system. It is a curing factor and cannot be modified. Definition:

 /// <Summary> ///  Tree node  /// </Summary>  Public interface  Itreenode { /// <Summary> /// All child nodes  /// </Summary>  Ilist < Itreenode > Childrennodes { Get ;} /// <Summary> ///  Parent node corresponding to this node  /// </Summary>  Itreenode Parentnode { Get ; Set ;} /// <Summary> ///  Key of the current node /// </Summary>  Object Id { Get ;} /// <Summary> ///  Key of the parent node  /// </Summary>  Object PID { Get ;}}

The data structure represented by this interface is the node of the tree, but it is restricted by the 2nd point constraint in the above article: When an instance of this interface is obtained, its PID has a value and indicates the id value of the parent node, but at the same time, parentnode may be null because it does not reference the object. Similarly, although this node has many child nodes, the set obtained by childrennodes may be a null set.

2. The object set object inherits from the gbusinesslistbase <T, C> generic set. Only one operation on its elements is required: Move (C item, int index ).

 
 

Interface Definition

Based on the original code, I first added the following interfaces to clarify complex concepts:

Isimplemovablecollection. CS

 /// <Summary> ///  A set of simple move operations  /// </Summary>  Internal interface  Isimplemovablecollection : Icollection { /// <Summary> ///  Move the elements at the corresponding position on oldindex to newindex.  ///  All the elements at the target location and in the middle move to the oldindex direction. /// </Summary> /// <Param name = "oldindex"> </param> /// <Param name = "newindex"> </param>  Void Move ( Int Oldindex, Int Newindex ); /// <Summary> ///  Move the item to newindex.  ///  All the elements at the target location and in the middle move to the oldindex direction.  /// </Summary> /// <Param name = "item">  An element in this set  </Param> /// <Param name = "newindex"> </param> Void Move ( Object Item, Int Newindex );} Internal interface  Isimplemovablecollection <T>: Isimplemovablecollection { /// <Summary> ///  Move the item to newindex.  ///  All the elements at the target location and in the middle move to the oldindex direction.  /// </Summary> /// <Param name = "item"> </param> /// <Param name = "newindex"> </param>  Void Move (T item, Int Newindex );}

The move method definition in the interface is mainly from the methods in the original system: gbusinesslistbase <T, C>. Move (). Isimplemovablecollection This set is different from other sets listed below and does not inherit from ilist. This is because it has no sort operations except move. If it is inherited from ilist, it will also have insert, remove, and other methods. It should be noted that although the ilist interface has the isreadonly attribute to determine whether it is a read-only set, if this value is false, but the move operation can be executed, logically, it is incorrect. Therefore, this set is directly inherited from icollection.

Generic isimplemovablecollection also does not implement icollection <t>, because generic icollection <t> also has the operation to change the collection.

In addition, the set I defined here is a wildcard and a non-generic combination. This is because the implementation of the code is in the openexpressapp framework, while the operations of the entity classes in the framework are sometimes for generic entities, but sometimes for non-generic entities. So we have to define non-generic versions together.

 

 
Iorderedobject. CS
/// <Summary> ///Objects with logical order numbers/// </Summary>Public interfaceIorderedobject{/// <Summary> ///GS logical order number///Logicindex/// </Summary>IntOrderno {Get;Set;}// Event eventhandler ordernochanged;}

Iorderedobject indicates an object that can be sorted by logic. You can directly set its logical order number. This serial number is also the value that will be persisted to the database. In this way, the next time you extract data from the database, you can simply perform physical sorting based on the Logical number, reducing the time consumption.

 
 
 
 
Iorderedobjectcollection. CS
 /// <Summary> ///  A set of objects that are logically ordered by orderno.  /// </Summary> /// <typeparam name = "T"> </typeparam>  Public interface  Iorderedobjectcollection : Ilist { /// <Summary> ///  G. You can use this sorting number to next a new object.  /// </Summary>  Int Nextorderno { Get ;}/// <Summary> ///  Move the specified node up/down  /// </Summary> /// <Param name = "Node"> </param> /// <Param name = "ISUP"> </param>  Void Movenode ( Iorderedobject Node, Bool ISUP ); /// <Summary> ///  Sort by orderno  /// </Summary>  Void Sortbyorderno (); /// <Summary> ///  Set all orderno according to the physical location. /// </Summary>  Void Setordernobyindex ();} Public interface  Iorderedobjectcollection <T>: Iorderedobjectcollection , Ilist <T> Where T: Iorderedobject {}

Iorderedobjectcollection <t> indicates the set of iorderedobject. It not only maintains the logical sequence number, but also maintains the physical location. Note that the definition of this set has nothing to do with Tree operations.

 
 
 
 
 
Itreenodecollection. CS

/// <Summary> ///General traversal type/// </Summary>Public EnumTreenodetraveltype{/// <Summary> ///Depth first/// </Summary>Depthfirst,/// <Summary> ///Breadth First/// </Summary>Scopefirst}

 /// <Summary> ///  Treenode set  //////  The element in it is an anemia Tree node (itreenode: Although there is a PID, there is not necessarily a parentnode object. That is to say, there are not necessarily entity references ......) /// </Summary>  Public interface  Itreenodecollection : Ilist { /// <Summary> ///  Whether it is deep sorting or wide sorting  /// </Summary>  Treenodetraveltype Sorttype { Get ; Set ;} /// <Summary> ///  Whether the treenode in the set has been sorted by link  /// </Summary> Bool Sorted { Get ;} /// <Summary> ///  Whether the node in the set has been associated with parennode and childrennodes according to the PID  /// </Summary>  Bool Objectrelationsruilt { Get ;} /// <Summary> ///  Re-establish the parennode and childrennodes associations  /// </Summary>  Void Rebuildobjectrelations (); /// <Summary> /// Ensure that the parennode and childrennodes associations are established.  /// </Summary>  Void Ensureobjectrelations (); /// <Summary> ///  Sort by sorttype  /// </Summary>  Void Sortbytree (); /// <Summary> ///  Ensure sorted  /// </Summary>  Void Ensuresorted (); /// <Summary> ///  Upgrade/downgrade a specified Node /// </Summary> /// <Param name = "Node"> </param> /// <Param name = "ISUP"> </param>  Void Changenodelevel ( Itreenode Node, Bool ISUP ); /// <Summary> ///  Add a new node based on the specified node.  /// </Summary> /// <Param name = "targetnode">  Standard Node  </Param> /// <Param name = "insertaschild">  Whether the new node is a child node of targetnode. (If not, it is a sibling node .) </Param> /// <Param name = "createaschild"> ///  If a sibling node is added, true indicates that the node is placed before targetnode, and false indicates that the node is placed behind the node.  ///  If a child node is added, "true" indicates that the new node is the first child, and "false" indicates that the new node is the first child.  /// </Param> /// <returns> </returns>  Itreenode Createnode ( Itreenode Targetnode, Bool Createaschild, Bool Beforefirst ); /// <Summary> ///  Add the specified node and all its subnodes to the collection. /// </Summary> /// <Param name = "Node"> </param>  Void Addnode ( Itreenode Node, Bool Recursivlyaddchildren ); /// <Summary> ///  Find the previous sibling node in the list  /// </Summary> /// <Param name = "Node"> </param> /// <returns> </returns>  Itreenode Findprevsibling ( Itreenode Node ); /// <Summary> ///  Find the last sibling node in the list /// </Summary> /// <Param name = "Node"> </param> /// <returns> </returns>  Itreenode Findnextsibling ( Itreenode Node ); /// <Summary> ///  Search for all root nodes (nodes without fathers)  /// </Summary> /// <returns> </returns>  Itreenode [] Findroots ();
}Public interfaceItreenodecollection<T>:Itreenodecollection,Ilist<T>WhereT:Itreenode{}

The itreenodecollection <t> set is the set of itreenode. Similar to iorderedobjectcollection <t>, it also has nothing to do with iorderedobject.

Every itreenode in this set can find all its relational nodes in this set. It is found in the set because itreenode. parentnode and itreenode. childrennodes do not necessarily have entity references. When we see the findroots method, we should think that this collection does not necessarily contain only one tree.

 
 
 
 
 
Iorderedtreenodecollection. CS
 /// <Summary> ///  An element set //////  Integrate two sets of different modes: itreenodecollection and iorderedobjectcollection  /// </Summary>  Public interface  Iorderedtreenodecollection : Itreenodecollection , Iorderedobjectcollection , Ilist { /// <Summary> ///  Assign a value to orderno again in the tree order  ///  Here, orderno is set for each root node through deep traversal.  /// </Summary> Void Setordernobytree (); /// <Summary> ///  Ensure that the logical and physical indexes are equal.  ///  And the recursive order of the tree is the same.  /// </Summary>  Void Ensureindices ();} Public interface  Iorderedtreenodecollection <T>: Iorderedtreenodecollection , Itreenodecollection <T>, Iorderedobjectcollection <T>,Ilist <T> Where T: Iorderedobject , Itreenode {}

Iorderedtreenodecollection <t> is the set to be applied in the system. The elements in the set must implement both the iorderedobject and itreenode interfaces. Therefore, we can design the logic sequence number: setordernobytree. An operation is also available: ensureindices.

Partial implementation code

First, we need to implement the tree traversal operation first. Here we use two static methods to traverse the tree with established relationships. One depth traversal uses the stack, and the other breadth traversal uses the queue. The code will not be pasted, which occupies too much space.

The following gbusinesstreelistbase <t, t> class inherits from the original gbusinesslistbase <t, C> class. Considering the impact of a deep hierarchy on performance, all the preceding interfaces are directly implemented in this class. But it is logically separated. First look at the Code:

Note that the inheritance level of the preceding interface is as follows:

However, when the gbusinesstreelistbase <t, t> class implements all interfaces,Logically, Can be simply understood as the following form:

The arrow direction is the inheritance direction in the logic and the dependency direction in the implementation. The region implemented by each interface in gbusinesstreelistbase <t, t> can be considered as a simple class. It is just to integrate them into a class. As follows:

Isimplemovablecollection <C> Implementation:

Iorderedobjectcollection <C> Implementation:

Itreenodecollection <C> Implementation:

Iorderedtreenodecollection <C> Implementation:

 

Remarks

Careful readers may find that the movenode method in the iorderedobjectcollection <t> Implementation calls the movenode method in the iorderedtreenodecollection <t> implementation. The createnode method should come out in the itreenodecollection <t> implementation, but it is placed in the iorderedobjectcollection <t> implementation.

Who can tell why? Is this one-way dependency? :)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.