Tworzę model obiektowy dla urządzenia, które ma wiele kanałów. Rzeczowniki używane między klientem a mną to Channel
i ChannelSet
. („Zestaw” nie jest semantycznie dokładny, ponieważ jest uporządkowany, a prawidłowy zestaw nie. Ale to problem na inny czas.)
Używam C #. Oto przykład użycia ChannelSet
:
// load a 5-channel ChannelSet
ChannelSet channels = ChannelSetFactory.FromFile("some_5_channel_set.json");
Console.Write(channels.Count);
// -> 5
foreach (Channel channel in channels) {
Console.Write(channel.Average);
Console.Write(", ");
}
// -> 0.3, 0.3, 0.9, 0.1, 0.2
Wszystko jest eleganckie. Jednak klienci nie są programistami i absolutnie będą myleni przez indeksowanie zerowe - pierwszy kanał to dla nich kanał 1. Ale ze względu na spójność z C # chcę utrzymać ChannelSet
indeksowanie od zera .
To z pewnością spowoduje pewne rozłączenia między moim zespołem deweloperów a klientami podczas interakcji. Co gorsza, każda niespójność w sposobie postępowania w bazie kodu jest potencjalnym problemem. Oto na przykład ekran interfejsu użytkownika, na którym użytkownik końcowy ( który myśli o indeksowaniu 1 ) edytuje kanał 13:
Ten Save
przycisk ostatecznie spowoduje powstanie kodu. Jeśli ChannelSet
indeksowany jest 1:
channels.GetChannel(13).SomeProperty = newValue; // notice: 13
lub jeśli indeks jest zerowy:
channels.GetChannel(12).SomeProperty = newValue; // notice: 12
Nie jestem pewien, jak sobie z tym poradzić. Wydaje mi się, że dobrą praktyką jest utrzymywanie uporządkowanej, indeksowanej liczbami całkowitymi listy rzeczy (the ChannelSet
) zgodnych ze wszystkimi innymi interfejsami tablicowymi i listowymi we wszechświecie C # (przez indeksowanie zerowe ChannelSet
). Ale wtedy każdy fragment kodu między interfejsem użytkownika a backendem będzie wymagał tłumaczenia (odejmij 1), a wszyscy wiemy, jak podstępne i powszechne są już błędy podstępne.
Czy taka decyzja kiedykolwiek cię ugryzła? Czy powinienem zerować indeks czy jeden indeks?
źródło
Odpowiedzi:
Wygląda na to, że identyfikujesz identyfikator
Channel
z jego pozycją wChannelSet
. Oto moja wizualizacja tego, jak w tej chwili wyglądałby Twój kod / komentarze:Wydaje się, że zdecydowałeś, że ponieważ
Channel
w obrębieChannelSet
są identyfikowane przez liczby, które mają górną i dolną granicę, muszą być indeksami, a zatem ponieważ są oparte na C #, 0. Jeśli naturalnym sposobem odwoływania się do każdego z kanałów jest liczba od 1 do X, odnieś się do nich liczbą od 1 do X. Nie próbuj narzucać im indeksów.Jeśli naprawdę chcesz zapewnić sposób dostępu do nich za pomocą indeksu opartego na 0 (jakie korzyści daje to użytkownikowi końcowemu lub programistom korzystającym z kodu?), Wówczas zaimplementuj narzędzie indeksujące :
źródło
Pokaż interfejs użytkownika z indeksem 1, użyj indeksu 0 w kodzie.
To powiedziawszy, pracowałem z takimi urządzeniami audio i użyłem indeksu 1 dla kanałów i zaprojektowałem kod, aby nigdy nie używał „indeksu” lub indeksatorów, aby uniknąć frustracji. Niektórzy programiści wciąż narzekali, więc zmieniliśmy to. Potem narzekali inni programiści.
Wybierz jeden i trzymaj się go. Istnieją większe problemy do rozwiązania w wielkim schemacie wyprowadzania oprogramowania z domu.
źródło
Option Base
to głupie, podobała mi się funkcja niektórych języków, polegająca na umożliwieniu tablicom indywidualnego określania dowolnych dolnych granic. Na przykład, jeśli mamy tablicę danych według roku, wykraczanie poza tablicę[firstYear..lastYear]
może być ładniejsze niż konieczność zawsze dostępu do elementu[thisYear-firstYear]
.Używać obu.
Nie mieszaj interfejsu użytkownika z kodem podstawowym. Wewnętrznie (jako biblioteka) powinieneś kodować „nie wiedząc”, jak każdy element w tablicy będzie wywoływany przez użytkownika końcowego. Użyj „naturalnych” tablic i kolekcji z indeksowaniem 0.
Ta część programu, która łączy dane z interfejsem użytkownika, widok, powinna zadbać o prawidłowe tłumaczenie danych między modelem mentalnym użytkownika a „biblioteką”, która faktycznie działa.
Dlaczego to jest lepsze?
źródło
Możesz zobaczyć kolekcję pod dwoma różnymi kątami.
(1) Jest to przede wszystkim regularny zbiór sekwencyjny , taki jak tablica lub lista. Indeks z
0
jest oczywiście właściwym rozwiązaniem, zgodnie z konwencją. Przydzielasz wystarczającą liczbę wpisów i mapujesz numer kanału do indeksów, co jest banalne (wystarczy odjąć1
).(2) Twoja kolekcja jest zasadniczo mapowaniem między identyfikatorami kanałów a obiektami informacji o kanale. Zdarza się, że identyfikatory kanałów to sekwencyjny zakres liczb całkowitych; jutro może być coś takiego
[1, 2, 3, 3a, 4, 4.1, 6, 8, 13]
. Używasz tego uporządkowanego zestawu jako kluczy mapujących.Wybierz jedno z podejść, udokumentuj je i trzymaj się go. Z punktu widzenia elastyczności wybrałbym (2), ponieważ reprezentacja numeru kanału (przynajmniej wyświetlanej nazwy) prawdopodobnie zmieni się w przyszłości.
źródło
channels[int]
) będzie zerowe indeksowane liczbami całkowitymi, i akcesorów dostaćGetChannelByFrequency
,GetChannelByName
,GetChannelByNumber
będzie elastyczny.Dictionary
lubSortedDictionary
.operator [] (int index)
powinna być oparta na 0, aoperator [] (IOrdered index)
nie. (Przepraszamy za przybliżoną składnię, mój C # jest bardzo zardzewiały.)[]
w języku, który używa tego przeciążenia do wyszukiwania według dowolnego klucza, programiści nie mogą zakładać, że klucze zaczynają się od0
i są ciągłe, i powinni rzucić ten nawyk ostry. Mogą zaczynać się od0
, lub1
, lub1000
łańcucha"Channel1"
, to jest cały sens używania operatora[]
z dowolnymi kluczami. OTOH, gdyby to był C, a ktoś powiedziałby: „czy powinienem pozostawić element0
w tablicy nieużywany, aby zacząć od1
”, to nie powiedziałbym „oczywiście, tak”, byłoby to bliskie wezwanie, ale skłaniam się do "Nie".Wszyscy i ich pies używają indeksów zerowych. Korzystanie z indeksów opartych na jednostkach w aplikacji spowoduje problemy z konserwacją na zawsze.
Teraz to, co wyświetlasz w interfejsie użytkownika, zależy wyłącznie od Ciebie i Twojego klienta. Wystarczy wyświetlić i + 1 jako numer kanału wraz z kanałem #i, jeśli to uszczęśliwi twojego klienta.
Jeśli wystawisz klasę, wystawisz ją programistom. Ludzie, którzy są zdezorientowani indeksem zerowym, nie są programistami, więc tutaj jest rozłączenie.
Wygląda na to, że martwisz się konwersją interfejsu użytkownika i kodu. Jeśli to Cię martwi, utwórz klasę reprezentującą interfejs użytkownika numeru kanału. Jedno połączenie zamienia liczbę 12 w reprezentację interfejsu użytkownika „Kanał 13”, a jedno połączenie zamienia „Kanał 13” w numer 12. Powinieneś to zrobić tak czy inaczej, na wypadek, gdyby klient zmienił zdanie, więc są tylko dwa wiersze kodu zmienić. I działa, jeśli klient poprosi o cyfry rzymskie lub litery od A do Z.
źródło
Mieszacie dwie koncepcje: indeksowanie i tożsamość. Nie są tym samym i nie należy ich mylić.
Jaki jest cel indeksowania? Szybki losowy dostęp. Jeśli wydajność nie jest problemem, a biorąc pod uwagę Twój opis, nie jest, to użycie kolekcji z indeksem jest niepotrzebne i prawdopodobnie przypadkowe.
Jeśli Ty (lub Twój zespół) jesteś zdezorientowany przez indeks a tożsamość, możesz rozwiązać ten problem, nie mając indeksu. Użyj słownika lub wyliczenia i uzyskaj kanał według wartości.
Pierwszy jest bardziej przejrzysty, drugi jest krótszy - mogą zostać przetłumaczone na tę samą IL, ale w obu przypadkach, biorąc pod uwagę, że używasz tego do rozwijania, powinno to być wystarczająco szybkie.
źródło
Udostępniasz interfejs w swojej
ChannelSet
klasie, z którym oczekujesz, że użytkownicy będą wchodzić w interakcje. Zrobiłbym, aby korzystanie z nich było jak najbardziej naturalne. Jeśli oczekujesz, że Twoi użytkownicy zaczną liczyć od 1 zamiast 0, ujawnij tę klasę i jej użycie, mając na uwadze to oczekiwanie.źródło
Indeksowanie na podstawie 0 było popularne i bronione przez ważne osoby, ponieważ deklaracja pokazuje rozmiar obiektu.
Czy w przypadku nowoczesnych komputerów, z których będą korzystać Twoi użytkownicy, czy rozmiar obiektu jest w ogóle ważny?
Jeśli Twój język (C #) nie obsługuje czystego sposobu deklarowania pierwszego i ostatniego elementu tablicy, możesz po prostu zadeklarować większą tablicę i użyć zadeklarowanych stałych (lub zmiennej dynamicznej) do identyfikacji logicznego początku i końca aktywny obszar tablicy.
W przypadku obiektów interfejsu użytkownika prawie na pewno stać Cię na użycie obiektu słownika do mapowania (jeśli masz 10 milionów obiektów, masz problem z interfejsem użytkownika), a jeśli najlepszym obiektem słownika jest lista z zmarnowane miejsce na obu końcach, nie straciłeś nic ważnego.
źródło