Diskussion:Nullobjekt (Entwurfsmuster)

Letzter Kommentar: vor 10 Jahren von Rolf b in Abschnitt Abschnitt "Verwendung"

verstanden Bearbeiten

Nach dem Lesen des Artikels habe ich dieses Pattern noch immer nicht verstanden... Wird nun bei jedem nicht primitiven Datentyp zuerst die Variable auf das Nullobjekt gebogen? Und nach Instanzierung ist sie dann von ihrem eigentlichen Typ? Ein CodeSnippet in C++ wäre hier sehr hilfreich. -- 217.9.110.27 18:15, 16. Apr. 2009 (CEST)Beantworten

nein, die variable wird nicht auf "das nullobjekt gebogen". null ist ja eben gerade kein objekt. und kein objekt hat auch keine methoden, die man aufrufen könnte. ein nullobjekt dagegen ist eine instanz einer klasse mit methoden und allem was dazugehört. -- 22:29, 16. Apr. 2009 (CEST)Beantworten
ich hab den hauptteil mal neugeschrieben [1], ist das so verständlicher? wenn nicht, muß ich halt nochmal ran :) -- 22:48, 16. Apr. 2009 (CEST)Beantworten

Abschnitt "Verwendung" Bearbeiten

Probleme mit diesem Abschnitt:

  1. Beispielsweise werden nicht initialisierte Variablen häufig mit null vorbelegt. Der Versuch eines Zugriffs auf eine Eigenschaft des referenzierten Objekts führt dann zu einer „null pointer exception“, da kein Objekt auch keine Eigenschaften hat.
    → Das ist falsch. Eine Vorbelegung einer Integer-Variablen mit null führt zu keiner Exception.
  2. Dem Abschnitt liegt das Missverständnis zugrunde, das "Nullobjekt" habe etwas mit einem auf null initialisierten Zeiger zu tun. Das ist aber nur eine von mehreren Möglichkeiten. "Nullobjekt" kommt von der mathematischen null im Sinne des neutralen Elementes, das keinen Einfluss auf die Operation hat.
  3. Was soll eine dynamische Sprache sein?

--Caperu2009 22:43, 20. Sep. 2009 (CEST)Beantworten

Da kann ich dir nicht ganz zustimmen:
  1. Ich weiß jetzt nicht, auf welche Programmiersprache du dich beziehst. Aber wenn du beispielsweise in Java eine Membervariable vom Typ Integer anlegst, wird sie mit null initialisiert. Das führt dann in Folge zu einer „NullPointerException“. Falls du dich aber auf skalare Datentypen beziehst (beispielsweise int in Java), hat das nichts mehr mit objektorientierter Programmierung zu tun und fällt somit nicht in den Zuständigkeitsbereich dieses Musters. null ist auch semantisch etwas völlig anderes als der Zahlenwert 0.
  2. Deine mathematische Sicht auf dieses Entwurfsmuster scheint deiner Phantasie zu entspringen. In der im Artikel referenzierten Originalliteratur ist an keiner Stelle vom neutralen Element im mathematischen Sinne die Rede. Dort geht es explizit und ausschließlich um den Umgang mit Null-Referenzen. Hier sei mir die Frage gestattet: Welche Literatur zu diesem Entwurfsmuster hast du gelesen? (Offensichtlich andere als ich.)
  3. Der Satz mit der „dynamischen“ Sprache ist auch nach meiner Ansicht nicht nachvollziehbar, kann also entfernt bleiben.
--j ?! 20:20, 22. Sep. 2009 (CEST)Beantworten
Das Thema ist aber nicht Java, und es wird auch nicht in allen Programmiersprachen eine NullPointerException geworfen. Und meinst du, das Muster ist auf Programmiersprachen ohne Exceptions nicht anwendbar, oder auf Pascal, weil dort Zeiger mit nil markiert werden? Übrigens ist null eine andere Schreibweise für 0, so wie eins eine andere Schreibweise für 1 ist. --Caperu2009 04:00, 24. Sep. 2009 (CEST)Beantworten
Du bist jetzt leider nicht auf mein oben stehendes Argument eingegangen, dass das Entwurfsmuster sich ausschließlich mit Objektreferenzen befasst und nicht mit Zahlen. Offenbar siehst du das anders, bleibst aber den Beleg für deine Ansicht schuldig. --j ?! 09:47, 24. Sep. 2009 (CEST)Beantworten
Das Entwurfsmuster kannst du auch auf Callbackfunktionen anwenden. In dem Fall hat es nichts mit Objekten zu tun. --Sch0lap 22:32, 24. Sep. 2009 (CEST)Beantworten
Aber auch nicht mit Zahlen. --j ?! 17:47, 25. Sep. 2009 (CEST)Beantworten
Beispiel 1: int i; auto div = [] () { s = s/i; }; /*...*/ if (i_is_initialized) div();
Anstatt nun jedesmal zu schreiben if (i_is_initialized) div(); setzt du besser ggf. div = [] () {};
Beispiel 2: static int i; auto sq = [] () { s = sqrt(i); };
Im zweiten Beispiel wird das uninitialisierte i mit null vorbelegt (wegen static).
Alles ohne Objekte, Objektreferenzen und Null Pointer Exception.
--Sch0lap 01:44, 28. Sep. 2009 (CEST)Beantworten
Womit wir wieder bei meinem Punkt oben angelangt wären. Es ist ja schön, dass du so kreativ ist und natürlich lässt sich jedes Muster nach Belieben verbiegen. Aber das hat nichts mehr mit dem eigentlichen Entwurfsmuster zu tun. Dort werden ganz klar Klassen und ihre Rollen definiert. Wenn die nicht existieren, handelt es sich nicht um das beschriebene Entwurfsmuster. Anders gesagt: Es gibt einen Grund dafür, warum das Muster Null-Objekt heißt, und nicht „neutrales Element“ oder so ähnlich. --j ?! 21:59, 28. Sep. 2009 (CEST)Beantworten
Aber was hat das denn mit den Einwänden zu tun? Im Artikel darf nichts falsches stehen, dazu gehören natürlich auch unzulässige Verallgemeinerungen. Im Artikel wurde z. B. behauptet, es werde eine Exception geworfen, und das kann man nicht so stehen lassen. --Sch0lap 23:46, 28. Sep. 2009 (CEST)Beantworten

Die Diskussion ist schon älter, aber der Artikel ist aus meiner Sicht immer noch ziemlich dürftig. Der einleitende Abschnitt ist alles, was an Fleisch übrig geblieben ist, und ist in seiner Abstraktheit NUR für Experten verständlich. Ein Pattern-Einsteiger wird damit nur verwirrt. Der Behauptung, dass das Nullobjekt eine Art "neutrales Element" sei, kann ich mich ebenfalls nicht anschließen. Es geht um das algorithmische Problem, dass ein Programm einen Datenblock erhält und wissen muss, ob er verwendbar ist oder nicht. Historisch ist es üblich gewesen (ich sage nur COBOL), hier mit Gültigkeitskennzeichen zu arbeiten. In Umgebungen mit dynamischem Speicher, wo Referenzen auf Objekte (oder Strukturen) zum Einsatz kommen können, missbraucht man die Referenz gerne als Kennzeichen und verwendet einen speziellen Wert als Nullreferenz, um damit anzuzeigen, dass kein verwendbarer Datenblock existiert. Dieser Wert kann mit dem integer-Wert 0 binär identisch sein, das ist aber ein Implementierungsdetail und nicht allgemeingültig, deswegen darf man das nicht gleichsetzen. Caperus Einwand mit dem 0-Wert in einer integer-Variablen gehört nicht zum Thema, weil er damit auf skalare Typen abzielt. Das Nullobjekt-Pattern beschäftigt sich mit Referenztypen und der Gültigkeit von Objektreferenzen.

Verwendet man ein Gültigkeitskennzeichen, muss man es vor jedem Zugriff auf das zugehörige Objekt abfragen. Diese Abfragerei bläht das komplette Programm auf und widerspricht der Idee, zusammengehörige Dinge auch an einem Ort zu implementieren (DRY). Und es widerspricht der Separation Of Concerns Idee, weil jeder, der das Objekt verwendet, sich mit dem Problem herumschlagen muss, wie denn das Default-Verhalten bei einer ungültigen Objektreferenz sein soll.

Genau hier setzt das Nullobjekt Pattern an, mit der Idee, auf Gültigkeitskennzeichen komplett zu verzichten. Statt dessen stellt man IMMER einen gültigen Datenblock bereit, das Nullobjekt, und sorgt mit Polymorphie dafür, dass das richtige Verhalten genutzt wird. Dass man dieses Nullobjekt als Singleton erzeugt, spart Speicher und ermöglicht in Sonderfällen auch die Abfrage, ob man es mit dem Nullobjekt zu tun hat (was aber dem Pattern eigentlich nicht gerecht wird). Es hängt immer vom konkreten Fall ab, wie man ein Nullobjekt implementiert und wieviel Gewinn es bringt.

Bei Callbacks ist eine "Tue nichts" Funktion ein valider Einsatz des Nullobjekt-Patterns. Ob es performanter ist, ist eine andere Frage, weil eine Abfrage auf "bist du null" vermutlich schneller ist als das Aufrufen einer Dummy-Methode, aber um Performance geht es bei Patterns häufig nicht, sondern um sauberen Code und Einhaltung der SOLID Prinzipien.

Der Hinweis auf dynamische Sprachen ist nicht falsch gewesen, das sind Sprachen die vieles zur Laufzeit tun, was der klassische C-Compiler zur Build-Zeit tut, und wenn man hier den Method-Dispatch manipuliert kann man sicherlich das Handling von Methodenaufrufen auf ungültige Objektreferenzen zentralisieren. Wenn ich den englischen Eintrag zum Pattern richtig verstehe, kann man bspw. in LISP eine Funktion so definieren, dass der LISP Interpreter zur Laufzeit erkennt ob ich FUNC(x) oder FUNC(nil) aufrufe und dementsprechend die eine oder andere Funktionsdefinition nutzt. Das ist aber nicht das Nullobjekt-Pattern, sondern eine andere Lösung des zu Grunde liegenden Problems. Die Frage "Was soll eine dynamische Sprache sein" zu stellen, um damit einen Hinweis darauf zu disqualifizieren, ist aber nicht angemessen. Denn es gab schon 2009 einen Wikipedia-Eintrag dazu. Rolf b (Diskussion) 15:08, 17. Jan. 2014 (CET)Beantworten