Ich starte ein Schulgruppenprojekt in Java mit Swing. Es ist eine unkomplizierte grafische Benutzeroberfläche der Database Desktop App.
Der Professor gab uns den Code aus dem letztjährigen Projekt, damit wir sehen konnten, wie er die Dinge macht. Mein erster Eindruck ist, dass der Code weitaus komplizierter ist, als er eigentlich sein sollte, aber ich stelle mir vor, dass Programmierer dies oft denken, wenn sie sich Code ansehen, den sie nicht nur geschrieben haben.
Ich hoffe Gründe zu finden, warum sein System gut oder schlecht ist. (Ich fragte den Professor und er sagte, ich würde später sehen, warum es besser ist, was mich nicht zufriedenstellt.)
Um eine Kopplung zwischen seinen beständigen Objekten, Modellen (Geschäftslogik) und Ansichten zu vermeiden, wird grundsätzlich alles mit Zeichenfolgen ausgeführt. Die persistenten Objekte, die in der Datenbank gespeichert werden, sind Hashtabellen von Zeichenfolgen, und die Modelle und Ansichten "abonnieren" sich gegenseitig und stellen Zeichenfolgenschlüssel für die "Ereignisse" bereit, die sie abonnieren.
Wenn ein Ereignis ausgelöst wird, sendet die Ansicht oder das Modell eine Zeichenfolge an alle Abonnenten, die entscheiden, was für dieses Ereignis zu tun ist. Zum Beispiel in einer der Listener-Methoden für Ansichtenaktionen (ich glaube, dies setzt das bicycleMakeField nur auf das persistable-Objekt):
else if(evt.getSource() == bicycleMakeField)
{
myRegistry.updateSubscribers("BicycleMake", bicycleMakeField.getText());
}
Dieser Aufruf ruft schließlich diese Methode im Fahrzeugmodell auf:
public void stateChangeRequest(String key, Object value) {
... bunch of else ifs ...
else
if (key.equals("BicycleMake") == true)
{
... do stuff ...
Der Professor sagt, dass diese Art, Dinge zu tun, erweiterbarer und wartbarer ist, als wenn die Ansicht einfach eine Methode für ein Geschäftslogikobjekt aufruft. Er sagt, dass es keine Kopplung zwischen den Ansichten und Modellen gibt, weil sie nicht von der Existenz der anderen wissen.
Ich denke, dies ist eine schlechtere Art der Kopplung, da Ansicht und Modell die gleichen Zeichenfolgen verwenden müssen, um zu funktionieren. Wenn Sie eine Ansicht oder ein Modell entfernen oder einen Tippfehler in einer Zeichenfolge machen, werden keine Kompilierungsfehler angezeigt. Es macht den Code auch viel länger, als ich denke, dass es sein muss.
Ich möchte dies mit ihm besprechen, aber er nutzt seine Branchenerfahrung, um jedem Argument entgegenzuwirken, das ich als unerfahrener Student vorbringe. Hat sein Ansatz einen Vorteil, den ich vermisse?
Um dies zu verdeutlichen, möchte ich den obigen Ansatz mit der Tatsache vergleichen, dass die Sichtweise offensichtlich an das Modell gekoppelt ist. Sie können beispielsweise das Fahrzeugmodellobjekt an die Ansicht übergeben und anschließend die "Marke" des Fahrzeugs ändern:
vehicle.make = bicycleMakeField.getText();
Dies würde 15 Codezeilen, die derzeit NUR verwendet werden, um die Marke des Fahrzeugs an einer Stelle festzulegen, auf eine einzige lesbare Codezeile reduzieren. (Und da diese Art von Operation hunderte Male in der gesamten App ausgeführt wird, wäre dies meiner Meinung nach ein großer Gewinn für die Lesbarkeit und Sicherheit.)
Aktualisieren
Mein Teamleiter und ich haben das Framework mithilfe der statischen Typisierung so umstrukturiert, wie wir es wollten, den Professor informiert und ihm schließlich eine Demo gegeben. Er ist so großzügig, dass wir unser Framework nutzen können, solange wir ihn nicht um Hilfe bitten und wenn wir den Rest unseres Teams auf dem Laufenden halten können - was uns fair erscheint.
Antworten:
Der Ansatz, den Ihr Professor vorschlägt, lässt sich am besten als strikt getippt beschreiben und ist auf fast jeder Ebene falsch.
Die Kopplung lässt sich am besten durch Abhängigkeitsinversion reduzieren , die durch eine polymorphe Verteilung erfolgt, anstatt eine Reihe von Fällen fest zu verdrahten.
quelle
Ihr Professor macht es falsch . Er versucht, die Ansicht und das Modell vollständig zu entkoppeln, indem er die Kommunikation dazu zwingt, über eine Zeichenkette in beide Richtungen zu wandern (Ansicht hängt nicht vom Modell ab und Modell hängt nicht von der Ansicht ab) , was den Zweck von objektorientiertem Design und MVC völlig zunichte macht. Anstatt Klassen zu schreiben und eine OO-basierte Architektur zu entwerfen, schreibt er unterschiedliche Module , die einfach auf textbasierte Nachrichten reagieren.
Um dem Professor gegenüber fair zu sein, versucht er, in Java eine Oberfläche zu erstellen, die der häufig verwendeten .NET-Schnittstelle sehr ähnlich ist
INotifyPropertyChanged
, die Abonnenten über Änderungsereignisse informiert, indem Zeichenfolgen übergeben werden, die angeben, welche Eigenschaft geändert wurde. Zumindest in .NET wird diese Schnittstelle hauptsächlich für die Kommunikation von einem Datenmodell zum Anzeigen von Objekten und GUI-Elementen verwendet (Bindung).Wenn es richtig gemacht , diesen Ansatz können einige benefits¹ haben:
events
In Java müssten Sie jedoch Klassen oder Objekte erstellen und für jedes Ereignis einen Code zum Abonnieren / Abbestellen schreiben.Kurz gesagt (und um Ihre Frage zu beantworten), es ist möglich, aber der Ansatz Ihres Professors ist schuld daran, dass er nicht mindestens eine einseitige Abhängigkeit zwischen Ansicht und Modell zulässt. Es ist einfach nicht praktisch, zu akademisch und kein gutes Beispiel für die Verwendung der vorhandenen Tools.
¹ Durchsuchen Sie Google
INotifyPropertyChanged
nach einer Million Möglichkeiten, um zu versuchen, bei der Implementierung die Verwendung magischer Zeichenfolgen zu vermeiden .quelle
enum
s (oderpublic static final String
s) sollten anstelle von magischen Zeichenfolgen verwendet werden.Ihr Professor versteht OO nicht . Zum Beispiel mit einer konkreten Fahrzeugklasse?
Und damit diese Klasse die Marke eines Fahrrads versteht?
Das Fahrzeug sollte abstrakt sein und es sollte eine konkrete Unterklasse namens Bike geben. Ich würde nach seinen Regeln spielen, um eine gute Note zu bekommen und dann seinen Unterricht vergessen.
quelle
Ich denke, Sie haben einen guten Punkt, die magischen Saiten sind schlecht. Jemand in meinem Team musste vor ein paar Wochen ein Problem beheben, das durch magische Strings verursacht wurde (aber es war in ihrem eigenen Code, den sie geschrieben hatten, also hielt ich den Mund). Und es ist passiert ... in der Industrie !!
Der Vorteil seines Ansatzes ist, dass es möglicherweise schneller ist, Code zu erstellen, insbesondere für kleine Demo-Projekte. Nachteile sind, dass es zu Tippfehlern kommt und je öfter die Zeichenfolge verwendet wird, desto größer ist die Wahrscheinlichkeit, dass ein Tippfehler die Sache durcheinander bringt. Und wenn Sie jemals eine magische Zeichenfolge ändern möchten, ist das Umgestalten von Zeichenfolgen schwieriger als das Umgestalten von Variablen, da Umgestaltungswerkzeuge möglicherweise auch Zeichenfolgen berühren, die die magische Zeichenfolge enthalten (als Teilzeichenfolge), aber selbst nicht die magische Zeichenfolge sind, und nicht berührt werden sollten. Außerdem müssen Sie möglicherweise ein Wörterbuch oder einen Index der magischen Zeichenfolgen führen, damit neue Entwickler nicht zum selben Zweck neue magische Zeichenfolgen erfinden und keine Zeit damit verschwenden, nach vorhandenen magischen Zeichenfolgen zu suchen.
In diesem Zusammenhang sieht es so aus, als ob ein Enum besser wäre als magische Zeichenfolgen oder sogar globale Zeichenfolgenkonstanten. Außerdem bieten IDEs häufig eine Art Code-Unterstützung (automatische Vervollständigung, Umgestaltung, Suche nach allen Referenzen usw.), wenn Sie konstante Zeichenfolgen oder Aufzählungen verwenden. Eine IDE bietet nicht viel Hilfe, wenn Sie magische Zeichenfolgen verwenden.
quelle
Die Verwendung von Branchenerfahrung ist ein schlechtes Argument. Ihr Professor muss sich ein besseres Argument einfallen lassen :-).
Wie andere bereits gesagt haben, ist die Verwendung von magischen Zeichenfolgen mit Sicherheit verpönt. Die Verwendung von Aufzählungen wird als weitaus sicherer angesehen. Eine Aufzählung hat Bedeutung und Umfang , magische Zeichenfolgen nicht. Abgesehen davon wird die Art und Weise, in der Ihr Professor Bedenken entkoppelt, als eine ältere und fragilere Technik angesehen, als sie heute verwendet wird.
Ich sehe, dass @backtodos dies behandelt hat, während ich darauf geantwortet habe, und daher möchte ich meiner Meinung nach hinzufügen, dass Sie mit Inversion of Control (bei dem es sich bei Dependency Injection um ein Formular handelt, das Sie in der Industrie in Kürze durch das Spring-Framework führen werden). ..) gilt als modernere Möglichkeit, mit dieser Art der Entkopplung umzugehen.
quelle
Lassen Sie uns ganz klar sein; Da ist unvermeidlich eine gewisse Kopplung drin. Die Tatsache, dass es ein solches abonnierbares Thema gibt, ist ebenso wie die Art des Rests der Nachricht (z. B. „einzelne Zeichenfolge“) ein Kopplungspunkt. Vor diesem Hintergrund stellt sich dann die Frage, ob die Kopplung größer ist, wenn dies über Zeichenfolgen oder Typen erfolgt. Die Antwort darauf hängt davon ab, ob Sie über eine zeitlich oder räumlich verteilte Kopplung besorgt sind: ob die Nachrichten in einer Datei aufbewahrt werden sollen, bevor sie später eingelesen werden, oder ob sie an einen anderen Prozess gesendet werden (insbesondere wenn Das ist nicht in der gleichen Sprache geschrieben. Die Verwendung von Strings kann die Sache viel einfacher machen. Der Nachteil ist, dass es keine Typprüfung gibt. Fehler werden erst zur Laufzeit erkannt (und manchmal auch dann nicht).
Eine Strategie zur Minderung / Beeinträchtigung von Java kann darin bestehen, eine typisierte Schnittstelle zu verwenden, wobei sich diese typisierte Schnittstelle jedoch in einem separaten Paket befindet. Es sollte nur aus Java
interface
s und Grundwerttypen bestehen (z. B. Aufzählungen, Ausnahmen). In diesem Paket sollten keine Schnittstellen implementiert sein. Dann implementiert jeder etwas dagegen, und wenn es erforderlich ist, die Nachrichten auf komplexe Weise zu übermitteln, kann eine bestimmte Implementierung eines Java-Delegaten bei Bedarf magische Zeichenfolgen verwenden. Es macht es auch viel einfacher, den Code in eine professionellere Umgebung wie JEE oder OSGi zu migrieren, und hilft auch bei kleinen Dingen wie dem Testen.quelle
Was Ihr Professor vorschlägt, ist die Verwendung von "magischen Ketten". Während es Klassen "locker" miteinander koppelt, was einfachere Änderungen ermöglicht, handelt es sich um ein Anti-Pattern. strings sollten sehr, SEHR selten verwendet werden, um Codeanweisungen zu enthalten oder zu steuern, und wenn dies unbedingt erforderlich ist, sollte der Wert der Zeichenfolgen, die Sie zur Steuerung der Logik verwenden, zentral und ständig definiert werden, damit EINE Berechtigung für den erwarteten Wert von besteht eine bestimmte Zeichenfolge.
Der Grund dafür ist sehr einfach; Zeichenfolgen werden nicht vom Compiler auf Syntax oder Konsistenz mit anderen Werten überprüft (bestenfalls werden sie auf korrekte Form in Bezug auf Escapezeichen und andere sprachspezifische Formatierungen in der Zeichenfolge überprüft). Sie können alles in eine Zeichenfolge einfügen, was Sie wollen. Als solches können Sie einen hoffnungslos kaputten Algorithmus / Programm kompilieren lassen, und erst wenn er ausgeführt wird, tritt ein Fehler auf. Betrachten Sie den folgenden Code (C #):
... Der gesamte Code wird beim ersten Versuch kompiliert, aber der Fehler wird beim zweiten Versuch offensichtlich. Es gibt zahlreiche Beispiele für diese Art der Programmierung, und alle unterliegen dieser Art von Fehlern, AUCH WENN Sie Zeichenfolgen als Konstanten definieren (da Konstanten in .NET in das Manifest jeder Bibliothek geschrieben werden, in der sie verwendet werden, und das muss Dann werden alle neu kompiliert, wenn der definierte Wert geändert wird, damit sich der Wert "global" ändert. Da der Fehler zur Kompilierungszeit nicht abgefangen wird, muss er während der Laufzeitprüfung abgefangen werden. Dies ist nur bei einer Codeabdeckung von 100% in Komponententests mit ausreichender Code-Übung gewährleistet, die normalerweise nur bei der absolutesten Ausfallsicherheit auftritt Echtzeit-Systeme.
quelle
Tatsächlich sind diese Klassen immer noch eng miteinander verbunden. Außer jetzt sind sie so eng miteinander verbunden, dass der Compiler Ihnen nicht sagen kann, wann die Dinge kaputt sind!
Wenn jemand "BicycleMake" in "BicyclesMake" ändert, wird niemand feststellen, dass die Dinge bis zur Laufzeit kaputt sind.
Laufzeitfehler sind weitaus teurer zu beheben als Fehler bei der Kompilierung - dies ist einfach alles Mögliche.
quelle