#c# #oop
#c# #ооп
Вопрос:
У меня есть набор из трех классов, которые все связаны друг с другом. В частности, передача, остановка и маршрут.
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).
Проблема, с которой я сталкиваюсь, заключается в том, как логически связать три класса, чтобы доступ к любому из них был максимально простым.
Каждый экземпляр класса имеет уникальный идентификатор (в пределах своего собственного типа) для ссылки, поэтому я сохраняю все в словарях, чтобы сделать возможным доступ к любому элементу по его идентификатору.
Связь, с которой я начал работать, упрощает выбор конкретного маршрута, но поскольку остановки и шаттлы содержатся в словарях внутри маршрутов. Я должен знать, на каком маршруте находится остановка или шаттл, чтобы ссылаться на него, что невозможно, потому что у меня есть только список доступных мне маршрутов, поэтому было бы необходимо перебирать каждый маршрут, пока я не найду правильную остановку / шаттл.
Каждая альтернатива, которую я придумал, сталкивается с похожими проблемами. Лучшее, что я придумал, это что-то вроде
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;
}
Однако это только лучшее из-за очень специфической работы кода на данном этапе. Он вычисляет ETA для каждой комбинации остановки / маршрута, которая может быть выполнена путем перебора шаттлов и вычисления времени, которое потребуется этому шаттлу, чтобы добраться до каждой остановки на его текущем маршруте.
Однако у меня есть другие места, где я хотел бы использовать эти классы, например, при отображении карты. Там эта структура ломается, потому что я хотел бы, чтобы при выборе остановки появлялся воздушный шар, показывающий маршруты, с которыми связана остановка. Очевидно, я не могу получить эту информацию напрямую, потому что Stop не знает маршрутов.
Ответ №1:
Вот способ сделать это. Двунаправленные ссылки между объектами требуют немного кода сопровождения для управления изменениями, но вы можете легко перейти от любого экземпляра к любому другому экземпляру.
// 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;
}
Например, все челноки удаляются на один маршрут.
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;
Комментарии:
1. Я действительно пытался сделать что-то похожее на это, но я узнал, что это называется циклической зависимостью, и создание такой зависимости, как правило, не одобряется. Я знаю, что всегда есть исключения, это одно из них?
2. У вас есть циклические отношения, например, шаттлы маршрутов остановок моего маршрута. Если вы сериализуете эти типы, вам придется установить IsReference= true для обработки циклов, но в остальном это не имеет большого значения.
3. @Mr.Неоднозначный — Это действительно циклическая зависимость, но если вы будете осторожны с ней, то все в порядке. Это действительно обычная практика в .NET. Как говорит DavidB, «требуется немного кода сопровождения для управления изменениями» — вам просто нужно быть осторожным, чтобы не попасть в бесконечный цикл Остановка-> Маршрут-> Остановка-> Маршрут-> Стоп-> Маршрут и т. Д
Ответ №2:
Измените свой класс контейнера, чтобы предоставить метод для получения всех маршрутов для данной остановки.
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;
}
Если вы работаете с действительно большими наборами данных или потенциально собираетесь выполнять этот вызов очень часто, вам может понадобиться что-то более эффективное, чем описанное выше. Например, вы делаете метод getRoutes закрытым и поддерживаете словарь, который сопоставляет идентификаторы остановок со списками маршрутов, и обновляете его всякий раз, когда добавляется новый маршрут или новая остановка, чтобы исключить необходимость вызывать getRoutes каждый раз, когда вам нужны маршруты остановки.
Я также предполагаю, что вашему приложению требуется только один экземпляр класса Container, поскольку он представляется просто сосудом для всех данных shuttle / route.