Ich erstelle ein Objektmodell für ein Gerät mit mehreren Kanälen. Die zwischen dem Klienten und mir verwendeten Substantive sind Channel
und ChannelSet
. ("Menge" ist semantisch nicht genau, weil es geordnet ist und eine richtige Menge nicht. Aber das ist ein Problem für eine andere Zeit.)
Ich benutze C #. Hier ist ein Anwendungsbeispiel für 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
Alles ist gut. Die Clients sind jedoch keine Programmierer und werden durch die Nullindizierung absolut verwirrt - der erste Kanal ist für sie Kanal 1. Aus Gründen der Konsistenz mit C # möchte ich jedoch den ChannelSet
Index von Null halten .
Dies wird sicher einige Verbindungsabbrüche zwischen meinem Entwicklerteam und den Clients verursachen, wenn diese interagieren. Schlimmer noch, jegliche Inkonsistenz in der Handhabung innerhalb der Codebasis ist ein potenzielles Problem. Hier ist zum Beispiel ein UI-Bildschirm, in dem der Endbenutzer ( der an 1 Index denkt ) Kanal 13 bearbeitet:
Dieser Save
Knopf wird irgendwann einen Code ergeben. Wenn ChannelSet
1 indiziert ist:
channels.GetChannel(13).SomeProperty = newValue; // notice: 13
oder dies, wenn es null indiziert ist:
channels.GetChannel(12).SomeProperty = newValue; // notice: 12
Ich bin mir nicht sicher, wie ich damit umgehen soll. Ich halte es für eine gute Praxis, eine geordnete, ganzzahlig indizierte Liste von Dingen zu führen, die ChannelSet
mit allen anderen Array- und Listenschnittstellen im C # -Universum konsistent sind (durch Null-Indizierung ChannelSet
). Aber dann muss jeder Code zwischen der Benutzeroberfläche und dem Backend übersetzt werden (abzüglich 1), und wir alle wissen, wie heimtückisch und häufig Fehler sind, die nur einmal vorkommen.
Hat Sie eine solche Entscheidung jemals gebissen? Soll ich einen Index oder einen Nullindex haben?
quelle
Antworten:
Es fühlt sich an, als würdest du den Bezeichner für
Channel
mit seiner Position innerhalb von in Konflikt bringenChannelSet
. Das Folgende ist meine Visualisierung, wie Ihr Code / Ihre Kommentare im Moment aussehen würden:Es fühlt sich an, als hätten Sie sich entschieden , dass
Channel
s innerhalb von aChannelSet
durch Zahlen identifiziert werden, die eine obere und untere Schranke haben. Sie müssen Indizes sein und daher auf C #, 0 basieren. Wenn die natürliche Art, auf jeden der Kanäle zu verweisen, eine Zahl zwischen 1 und X ist, verweisen Sie auf sie mit einer Zahl zwischen 1 und X. Versuchen Sie nicht, sie als Indizes zu erzwingen.Wenn Sie wirklich eine Möglichkeit bereitstellen möchten, über einen 0-basierten Index auf sie zuzugreifen (welchen Vorteil bietet dies Ihrem Endbenutzer oder Entwicklern, die den Code verwenden?), Implementieren Sie einen Indexer :
quelle
Zeigen Sie die Benutzeroberfläche mit Index 1 an, verwenden Sie Index 0 im Code.
Trotzdem habe ich mit Audiogeräten wie diesen gearbeitet und Index 1 für die Kanäle verwendet und den Code so entworfen, dass er niemals "Index" oder Indexer verwendet, um Frustrationen zu vermeiden. Einige Programmierer haben sich immer noch beschwert, also haben wir es geändert. Dann haben sich andere Programmierer beschwert.
Einfach eins auswählen und dabei bleiben. Es gibt größere Probleme zu lösen, wenn es darum geht, Software aus der Tür zu bekommen.
quelle
Option Base
dumm gehalten habe, mochte ich die Funktion, die in einigen Sprachen angeboten wird, Arrays die Möglichkeit zu geben, willkürliche Untergrenzen individuell festzulegen. Wenn man beispielsweise ein Array von Daten pro Jahr hat,[firstYear..lastYear]
kann es besser sein , über die Fähigkeit hinaus ein Array zu dimensionieren , als immer auf das Element zugreifen zu müssen[thisYear-firstYear]
.Verwende beide.
Mischen Sie die Benutzeroberfläche nicht mit Ihrem Kerncode. Intern (als Bibliothek) sollten Sie "ohne zu wissen" codieren, wie jedes Element im Array vom Endbenutzer aufgerufen wird. Verwenden Sie die "natürlichen" 0-indizierten Arrays und Auflistungen.
Der Teil des Programms, der die Daten mit der Benutzeroberfläche verbindet, die Ansicht, sollte darauf achten, dass die Daten zwischen dem mentalen Modell des Benutzers und der Bibliothek, die die eigentliche Arbeit leistet, korrekt übersetzt werden.
Warum ist das besser?
quelle
Sie können die Sammlung aus zwei verschiedenen Blickwinkeln betrachten.
(1) Es ist in erster Linie eine reguläre sequentielle Sammlung , wie ein Array oder eine Liste. Der Index von
0
ist dann offensichtlich die richtige Lösung, wenn man die Konvention befolgt. Sie ordnen den Indizes genügend Einträge zu und ordnen die Kanalnummer zu, was trivial ist (einfach subtrahieren)1
).(2) Ihre Sammlung ist im Wesentlichen eine Zuordnung zwischen Kanalbezeichnern und Kanalinformationsobjekten. Es kommt nur vor, dass Kanalbezeichner ein sequentieller Bereich von ganzen Zahlen sind. morgen könnte es so etwas wie sein
[1, 2, 3, 3a, 4, 4.1, 6, 8, 13]
. Sie verwenden dieses geordnete Set als Zuordnungsschlüssel.Wählen Sie einen der Ansätze, dokumentieren Sie ihn und halten Sie sich daran. Unter dem Gesichtspunkt der Flexibilität würde ich mit (2) fortfahren, da sich die Darstellung der Kanalnummer (zumindest des angezeigten Namens) in Zukunft wahrscheinlich ändern wird.
quelle
channels[int]
) wird Null indiziert ganze Zahlen, und die Get - AccessorenGetChannelByFrequency
,GetChannelByName
,GetChannelByNumber
wird flexibel sein.Dictionary
oder verwendenSortedDictionary
.operator [] (int index)
dass 0-basiert sein sollte, währendoperator [] (IOrdered index)
dies nicht der Fall wäre. (Entschuldigung für die ungefähre Syntax, mein C # ist sehr rostig.)[]
in einer Sprache überladen sind, die diese Überladung für das Nachschlagen mit beliebigen Schlüsseln verwendet, die Programmierer nicht davon ausgehen dürfen, dass die Schlüssel von0
einander ausgehen und aufeinander folgen, und diese Angewohnheit schärfer werden sollten. Sie können von0
oder1
oder1000
oder der Zeichenfolge ausgehen. Dies"Channel1"
ist der springende Punkt bei der Verwendung eines Operators[]
mit beliebigen Schlüsseln. OTOH, wenn dies C wäre und jemand sagen würde "sollte ich ein Element0
in einem Array ungenutzt lassen, um von vorne zu beginnen1
", dann würde ich nicht "offensichtlich ja" sagen, es wäre ein enger Anruf, aber ich würde mich lehnen "Nein".Jeder und sein Hund verwenden nullbasierte Indizes. Wenn Sie in Ihrer Anwendung einseitige Indizes verwenden, treten für immer Wartungsprobleme auf.
Was Sie nun auf einer Benutzeroberfläche anzeigen, liegt ganz bei Ihnen und Ihrem Kunden. Zeigen Sie einfach i + 1 als Kanalnummer zusammen mit Kanal #i an, wenn dies Ihren Kunden glücklich macht.
Wenn Sie eine Klasse verfügbar machen, machen Sie sie Programmierern zugänglich. Leute, die Sie durch einen Null-basierten Index verwirren, sind keine Programmierer, daher gibt es hier eine Unterbrechung.
Sie scheinen sich Sorgen um die Konvertierung zwischen Benutzeroberfläche und Code zu machen. Wenn Sie sich Sorgen machen, erstellen Sie eine Klasse, die die Darstellung einer Kanalnummer auf der Benutzeroberfläche enthält. Ein Anruf, der die Nummer 12 in die UI-Darstellung "Channel 13" verwandelt, und ein Anruf, der "Channel 13" in die Nummer 12 verwandelt. Sie sollten dies trotzdem tun, falls der Kunde seine Meinung ändert, sodass nur zwei Codezeilen vorhanden sind wechseln. Und es funktioniert, wenn der Kunde nach römischen Ziffern oder Buchstaben von A bis Z fragt.
quelle
Sie verwechseln zwei Konzepte: Indizierung und Identität. Sie sind nicht dasselbe und sollten nicht verwechselt werden.
Was ist der Zweck der Indizierung? Schneller wahlfreier Zugriff. Wenn die Leistung kein Problem ist und Ihre Beschreibung es nicht ist, ist die Verwendung einer Auflistung mit einem Index unnötig und wahrscheinlich versehentlich.
Wenn Sie (oder Ihr Team) durch den Index mit der Identität verwechselt werden, können Sie dieses Problem lösen, indem Sie keinen Index haben. Verwenden Sie entweder ein Wörterbuch oder eine Aufzählung, und ermitteln Sie den Kanal nach Wert.
Die erste ist klarer, die zweite ist kürzer - sie können oder können nicht in die gleiche IL übersetzt werden, aber so oder so, wenn Sie dies für ein Dropdown verwenden, sollte es schnell genug sein.
quelle
Sie legen eine Schnittstelle in Ihrer
ChannelSet
Klasse offen, mit der Ihre Benutzer interagieren sollen. Ich würde es ihnen so natürlich wie möglich machen. Wenn Sie erwarten, dass Ihre Benutzer von 1 statt von 0 zählen, dann machen Sie diese Klasse und ihre Verwendung unter Berücksichtigung dieser Erwartung sichtbar.quelle
Die 0-basierte Indizierung war beliebt und wurde von wichtigen Personen verteidigt, da die Deklaration die Größe des Objekts angibt.
Ist bei modernen Computern und den Computern, die Ihre Benutzer verwenden, die Größe des Objekts überhaupt wichtig?
Wenn Ihre Sprache (C #) keine saubere Deklaration des ersten und letzten Elements eines Arrays unterstützt, können Sie einfach ein größeres Array deklarieren und deklarierte Konstanten (oder dynamische Variablen) verwenden, um den logischen Anfang und das logische Ende von zu identifizieren der aktive Bereich des Arrays.
Bei UI-Objekten können Sie es sich mit ziemlicher Sicherheit leisten, ein Dictionary-Objekt für Ihre Zuordnung zu verwenden (bei 10 Millionen Objekten liegt ein UI-Problem vor), und wenn sich herausstellt, dass das beste Dictionary-Objekt eine Liste mit ist Verschwendeter Platz an beiden Enden, Sie haben nichts Wichtiges verloren.
quelle