开发者

Implementing a logical class structure for many-to-many and one-to-many relationships?

I have a set of three classes that are all related to each other. Specifically, Shuttle, Stop, and Route.

Stops can lie on multiple Routes and therefore Routes contain Stops.
Shuttles can exist on one Route at a time, but Routes can contain multiple Shuttles.
A Stop will always exist on at least one Route.
A Shuttle may exist on no Route (though this is avoidable by discarding any Shuttles that are off-Route).

The problem I have is how to logically relate the three classes so that access to any of them is as simple as possible.

Every instance of a class has a u开发者_如何学编程nique ID (within its own type) to reference by, so I am storing everything in Dictionaries to make it possible to access any element by its ID.

The relationship I started to go with makes it easy to pick out a specific Route, but because Stops and Shuttles are contained in Dictionaries within Routes. I have to know what Route a Stop or Shuttle is on to reference it, which is impossible because I only have a list of Routes available to me, so it would be necessary to iterate through each Route until I locate the correct Stop/Shuttle.

Every alternative I've come up with runs into similar problems. The best one I've come up with is something like

class Container
{
    Dictionary<int, Shuttle> shuttles;
    Dictionary<int, Route> routes;
}

class Shuttle
{
    int shuttleId;
    int routeId;
}

class Route
{
    int routeId;
    Dictionary<string, Stop> stops;
}

class Stop
{
    string stopId;
}

However, this is only the best because of the very specific operation of the code at this point. It calculates ETAs for every Stop/Route combination which can be accomplished by iterating through the Shuttles and calculating the time it will take for that Shuttle to reach every stop on its current Route.

I have other places I want to use these classes though, such as on a map display. There, this structure breaks because I would want a balloon to appear when a Stop is selected, showing the Routes that the Stop is linked to. Obviously I cannot get that information directly because the Stop has no knowledge of Routes.


Here's a way to do it. The bidirectional references between entities do require a bit of maintenence code to manage changes, but you can easily go from any instance to any other instance.

// World knows about every entity in it.
// World cares not how entities are related to each other.
public class World
{
  Dictionary<int, Shuttle> shuttles;
  Dictionary<int, Route> routes;
  Dictionary<int, Stop> stops;
}

public class Shuttle
{
  Route CurrentRoute;
}

public class Stop
{
  Dictionary<int, Route> Routes;
}

public class Route
{
  Dictionary<int, Shuttle> Shuttles;
  Dictionary<int, Stop> Stops;
}

For example, all shuttles one route away.

from stop in World.routes[myRouteId].Stops.Values
from route in stop.Routes.Values
where route.Id != myRouteId
from shuttle in route.Shuttles 
select shuttle;


Modify your Container class to provide a method for getting all of the routes for a given stop.

public static class Container
{
    private static Dictionary<int, Shuttle> shuttles;
    private static Dictionary<int, Route> routes;

    /* Other stuff goes on to initialize shuttles and routes I  assume */

    public static List<Route> getRoutes(string stopId)
    {
        List<Route> stopRoutes = new List<Route>();

        foreach (int myKey in routes.Keys)
        {
             foreach (string str in routes[myKey].stops.Keys)
             {
                   if (routes[myKey].stops[str] == stopId)
                   {
                        stopRoutes.Add(routes[myKey]);
                        break;
                   }
             }
         }

         return stopRoutes;
      }

If you're operating on really large sets of data, or you are going to be potentially making that call very frequently, you might need something more efficient than the above. For example, you make the getRoutes method private and maintain a dictionary that maps stopIds to Route lists, and update it whenever a new route or a new stop is added to preclude the need to call getRoutes every time you need a stop's routes.

I'm also assuming that your application only requires one instance of the Container class since it appears to just be a vessel for all of the shuttle/route data.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜