CONSTRUCTOR & Co. [Sammeln & Seltenes]

Die Objektorientierung mit ABAP®: Vererbung, Dynamische Programmierung, GUI Controls (u.a. ALV im OO).
43 Beiträge Seite 1 von 3 (current) Nächste
43 Beiträge Seite 1 von 3 (current) Nächste

CONSTRUCTOR & Co. [Sammeln & Seltenes]

Beitrag von ewx (Top Expert / 3972 / 164 / 368 ) » 2. Jan 2019 20:21

Hallo zusammen,
in der letzten Zeit sind vermehrt Themen und Diskussionen aufgetaucht, die sich um die "richtige" Definition und Instantiierung von Objekten dreht.
  • Singleton
  • Multiton
  • Factory
  • get_instance
  • Constructor-Parameter (ja, nein, wie viele?)
  • usw
Es geht immer wieder darum, wann wie warum welche Sachen beachtet werden müssen.


Ich würde alles, was an diesem Thema hängt gerne mal irgendwie ordnen und zusammen fassen, da ich auch immer wieder unsicher bin, wann welche Methode die beste ist.

Mit einer Mindmap habe ich mal angefangen:

Bild

Da ist natürlich noch kein Coding dran und es ist auch nicht die ideale Darstellung für so ein komplexes Thema.
Ich würde aber trotzdem gerne eine Möglichkeit finden, wie man die einzelnen Aspekte einigermaßen kompakt darstellen kann.

Mann kann alles zu den einzelnen Themen nachlesen. Oft ist aber kein Beispiel vorhanden oder keines für ABAP oder ein völlig unrealistisches. Häufig wird auch nur beschrieben was etwas macht, aber nicht warum man es verwenden sollte oder wann nicht.
  • Was sind die Vorteile, wenn ein CONSTRUCTOR keine/wenige/viele Parameter hat?
  • Was sind die Nachteile?
  • Wie verhält es sich bei Erweiterungen, also wenn Parameter hinzukommen müssten?
  • Lässt sich das umgehen? Wenn ja, wie?
  • Worauf muss man aufpassen?
  • Wie sieht ein Beispiel aus der Praxis aus?
  • Wo gab es bei bisherigen Projekten Schwierigkeiten? Welche? Wie wurden sie gelöst?
  • Wann ist ein singleton *wirklich* sinnvoll?

Hierfür hätte ich gerne eure Ideen (Fachlich, inhaltlich, technisch, ...):
Wie kann man das alles so ordnen, dass man nicht zig Seiten Text lesen muss?
Welche Bereiche/ Spalten/ Themen sind sinnvoll?
Welches Tool wäre passend?


Natürlich sollen am Ende ein oder mehrere Artikel im Tricktresor dabei herauskommen, in dem man alles gesammelt nachlesen kann...! ;)

PS:

Code: Alles auswählen.

DATA(year2019) = NEW year( 2019 ).
year2019->wish( 'Happy new year' ).


Re: CONSTRUCTOR & Co. [Sammeln & Seltenes]

Beitrag von deejey (Specialist / 199 / 48 / 16 ) » 3. Jan 2019 01:55

Ich habe relativ grobe OO-Kenntnisse, musste erst nachlesen was Singleton überhaupt bedeutet :D aber ich frage mich warum es wichtig ist wie viele Parameter der Constructor hat? Auch bei Erweiterungen sehe ich das Problem nicht, das Konzept optionaler Parameter ist doch perfekt und deckt vieles ab!? Und wenn es nicht optional ist, dann müssen eben alle Aufrufe angepasst werden, denn die fachliche Anforderung des neuen Parameters hatte ja einen Grund, den man meist nicht vorab ahnen konnte oder wollte.

Re: CONSTRUCTOR & Co. [Sammeln & Seltenes]

Beitrag von SaskuAc (Specialist / 251 / 21 / 30 ) » 3. Jan 2019 08:30

Also grundsätzlich glaube ich kann man festhalten, dass es keine allgemein gültige Lösung, bzw. "die Richtige Art und Weise" gibt, wie man Objekte instantiiert.

Persönlich bin ich ein Freund davon, eine "get_instance" Methode zu haben, welche dann das Objekt zurück liefert. Man kann hier nämlich im Hintergrund Sachen erledigen bzw. Logiken austauschen, welche bei einem Constructor nicht geht. ( z. B. kann man, wenn es Später dann mal Nötig ist, die Klasse zu einem Singleton ummodeln, oder aber zu einem Multiton ( was ich in deiner Mindmap zum ersten Mal höre, aber klingt mir einleuchtend, wofür man das brauchen kann )

Danach setzt man mit verschiedenen Public Setter-Methoden die jeweiligen Attribute. Ist auch für die Wartbarkeit und Testbarkeit ( speziell für Unit Tests ) extrem gut.

Wenn man dennoch einen Constructor verwendet, dann bitte wenige Parameter, da hier ( wie überall wo extrem viele Parameter auftauchen ) die Wartbarkeit leidet. Bei wenigen Parametern hat man dementsprechend den Vorteil, dass nicht so viele Programme angefasst werden müssen, wenn ein neues Attribut, welches man evtl. im Constructor initialisiert, hinzukommt. - dafür auch wieder eine Setter-Methode und fertig. Nicht jedes Programm wird dieses neue Attribut brauchen - man müsste es aber anfassen, wenn man den Constructor ändert ( wobei man ja den parameter auf optional setzen kann - bin aber absolut kein freund davon! ). Man soll einfach danach die Setter Methode aufrufen und fertig.

Edit:
deejey hat geschrieben:Ich habe relativ grobe OO-Kenntnisse, musste erst nachlesen was Singleton überhaupt bedeutet :D aber ich frage mich warum es wichtig ist wie viele Parameter der Constructor hat? Auch bei Erweiterungen sehe ich das Problem nicht, das Konzept optionaler Parameter ist doch perfekt und deckt vieles ab!? Und wenn es nicht optional ist, dann müssen eben alle Aufrufe angepasst werden, denn die fachliche Anforderung des neuen Parameters hatte ja einen Grund, den man meist nicht vorab ahnen konnte oder wollte.
Naja, es leidet dennoch die Testbarkeit und lesbarkeit. ich finde:

Code: Alles auswählen.

new Year( year = '2019' 
                         wish = 'Happy new Year' 
                         people_on_earth = 8.000.000.000 " nicht wirklich 
                         etc = etc 
                         usw = usw ). 
weniger lesbar als

Code: Alles auswählen.

data(year) = Year=>get_instance( year = '2019' ). 
year->set_wish( 'Happy new Year' ). 
year->set_people( 8.000.000.000 ). 
year->set_etc( etc ). 
year->set_usw( usw ). 
natürlich besteht hier mehr tipparbeit und es ist natürlich auch eine sehr Subjektive Sache. - Dennoch finde ich das schöner. Abgesehen davon ist das sehr viel einfacher zu testen und, für den Fall dass Fehler auftreten leichter zu behandeln. Abgesehen davon ist OO dafür da, dass stark gekapselt wird ( ich werde unten das protected prinzip ausklammern ) - der Konstruktor kapselt aber überhaupt nicht. Mal von der Kapselung abgesehen ist ein anderes OO-Prinzip verletzt, wenn man viele Parameter rein haut: Man soll kleine Methoden schreiben. Da du im Konstruktor alle Parameter auf Gültigkeit prüfen musst und danach dann noch verarbeiten ( z. B. zum Attribut setzen - was ja noch das geringste wäre ) musst, können hier schnell riesige Construktor-Methoden entstehen, was nicht schön ist ( und im Construktor dann die setter methoden aufrufen ergibt für mich keinen Sinn .. da kann man die auch gleich von außen aufrufen ... da erspart man sich dann wieder tipparbeit ).
Die Kritik hier wäre nicht relevant, wenn es in ABAP das Konstrukt mit "Überladenen"-Methoden gäbe. Heißt 2 Methoden mit dem selben Namen, aber mit unterschiedlicher Signatur ( heißt in dem Fall, Importparametern ). Dann könnte man einfach den Constructor wählen den man haben will, mit Parameter oder ohne und dann bei bedarf die Setter-Methoden rufen.

Endedit.

Bezüglich der Sichtbarkeit - es kommt ein wenig drauf an wie man nun das Objekt instantiieren möchte. Wie oben schon gesagt, gibt es keine allgemein gültige Lösung. Protected habe ich in ABAP ( und auch anderen Sprachen um ehrlich zu sein ) noch nie verwenden können. ( Python unterstützt soweit ich weiß noch nicht einmal diese Art der Kapselung hin zu private ) - Und um ehrlich zu sein, habe ich noch kein einziges ABAP Programm gesehen, welches Protected irgendwie verwendet .. . Klar, wenn man ganz streng nach OO-Konzept geht, sollte man es verwenden, aber es ist mM nicht relevant. Zu Public schreibst du
"Aufrufer muss über Parameter / Attribute bescheid wissen"
- das muss er aber auch bei einem private. Wenn man irgendwie "von außen" ein Attribut verändern möchte, muss man wissen wie das Beschaffen ist, sonst funktioniert das keinesfalls. Oder übersehe ich hier etwas?

Zum Singleton ist es relativ einfach Beispiele zu finden. Eines der besten ist, wie du schon schreibst eine Log-Klasse. Oder ein anderes Beispiel aus unserer Firma. Wir haben einen "Verbucher-Report" - welcher, je nach angegebener Zeit, Sachen verarbeitet. Die Klasse die dafür zuständig ist, die Daten zu verarbeiten, ist ein Singleton. Das brauchen wir, weil sich die "Updatetasks" sonst in die quere kommen könnten und dann eventuell Tabellen ( bei uns im HR-Umfeld eher Personen ) sperren oder auch teilweise Laufzeitfehler verursachen könnten.

Bei der Verwendung von Festwerten wenn möglich, falls man auf einem 7.51 System ( oder höher ) sitzt, dann Enumeratoren ( kurz enums ( sing. Enum ) ) verwenden. Wenn man einen Parameter hat, welcher auf einem Enum aufbaut, prüft der Syntaxcheck gleich ob das verwendet worden ist. Dadurch spart man sich die Prüfung ob der mitgegebene Parameter gültig ist oder nicht.

Zum Punkt "Wann ist welcher Anwendungsfall am besten":
Wenn es Klassen gibt - bei der man nur eine Methode nach Instantiierung aufruft finde ich das Konstrukt am besten:

Code: Alles auswählen.

" gut lesbarer einzeiler, oder?
new Year( '2019' )->wish( 'Happy new Year' ). 
Danach verschwindet das Objekt nämlich wieder aus dem Speicher und alles ist gut. Das "new"-Konstrukt ( also der normale Konstruktor aufruf ) nehme ich hauptsächlich dann her, wenn ich ein Objekt als Parameter irgendwo übergeben muss:

Code: Alles auswählen.

data(greetings) = newYearGreetings=>get_instance( new Year( Year=>enum-2019 ) ). 
greetings->wish( ). " output is 'Happy new Year'
Wenn man mit dem Objekt weiterarbeiten möchte ( wie z. B. dem Coding darüber )

Code: Alles auswählen.

" entweder - ist leichter zu lesen, wenige Parameter vorausgesetzt 
data(year2019) = Year=>get_instance( Year=>enum-2019 ). 

" oder -  finde ich aus wartungs- und testsicht besser
data(2_year2019) = Year=>get_instance( ).
2_year2019->set_year( Year=>enum-2019 ). 

year2019 = 2_year2019. 

year2019->wish( 'Happy new Year' ). 
year2019->vergesse_vorsätze( abap_true ). 
" ... 
Zum Punkt, wie man das gut Visualisieren und Aufbereiten kann:
finde deine MindMap von der Struktur her nicht schlecht. - Es muss halt nur richtig zugeordnet sein. Wie oben schon beschrieben, finde ich den Punkt bei Public jetzt nicht so Richtig..
Wie man das aufbereiten kann ohne ewig viel Text, nur durch Beispiele, glaub ich. Tatsächlich habe ich gerade das Buch "Entwurfsmuster in ABAP" neben mir liegen. Die Texte die drinnen stehen, sind nicht wirklich erklärend, die Beispiele aber schon. wahrscheinlich wäre es gut, wenn du das auch mit einigen kleinen Code-Abschnitten auf Tricktresor dann darstellen könntest.

Naja, das wars jetzt dann erstmal mit einem kleinen Monolog. :D Hoffe das war nicht allzu durcheinander :?
Zuletzt geändert von SaskuAc am 3. Jan 2019 08:57, insgesamt 2-mal geändert.

Folgende Benutzer bedankten sich beim Autor SaskuAc für den Beitrag:
ewx


Re: CONSTRUCTOR & Co. [Sammeln & Seltenes]

Beitrag von nickname8 (Specialist / 106 / 15 / 16 ) » 3. Jan 2019 08:36

deejey hat geschrieben:...das Konzept optionaler Parameter ist doch perfekt und deckt vieles ab!?
Ich halte das Konzept der optionalen Parameter für schlecht in der Form wie es jetzt besteht. Hier wird oft versucht mehrere ähnliche use-cases in einer Methode zu erschlagen und das wird dann über eine jeweilige Kombination von optionalen Parametern erreicht. Wenn es in ABAP überschreibbare Methoden gäbe, würden die optionalen Parameter auch wirklich Sinn machen. Da ist optional dann auch echt optional und nicht ein hässliches "entweder so oder so, aber eins von den beiden Kombinationen musst du schon bedienen, sonst dumpts".

Ansonstens: Super Thread. Bin sehr gespannt was man hier mitnehmen kann.

@ewx: du fragtest nach einen echten Usecase für einen Singleton. Wir nutzen für unsere Handscanner im WHS ein Fremwork welches Funktionsgruppenbasiert realisiert wurde vom Hersteller. Bedeutet: Jeder Screen (ver)braucht zwei FUBAs pro Screen (PBO und PAI). Ein Screen kann man sich vorstellen als Dynpro (ganz grob, nur um eine Idee zu bekommen). Bedeutet, man kann pro Funktionsgruppe 49 Screens erstellen (max. FUBAs pro FUGRU = 99 / 2 = 49,5 --> 49 Screens). Heißt, ich kann Daten/Objekte zwischen Screens aus verschiedenen Funktionsgruppen nicht global in einem Include des Rahmenprogramms speichern, da die andere Gruppe dieses Include nicht kennt (bzw wenn ich es auch in der anderen Gruppe einbinde ist es für dieses Rahmenprogramm nicht die selber Instanz, ich hoffe das war verständlich). Hier brauchte ich das selbe Objekt in allen Screens und das habe ich über ein Singleton gelöst.

Folgende Benutzer bedankten sich beim Autor nickname8 für den Beitrag:
ewx


Re: CONSTRUCTOR & Co. [Sammeln & Seltenes]

Beitrag von ralf.wenzel (Top Expert / 3416 / 149 / 220 ) » 3. Jan 2019 11:25

Interesaantes Thema, gerade auch für mich, der immer wieder „schlechtes OO“ überarbeiten muss, um es objektorientierter zu machen. Schlechtes OO ist schlimmer als gar kein OO..... Und Objektorientierung fängt eben mit der Objekterzeugung an.
ewx hat geschrieben:Hallo zusammen,
in der letzten Zeit sind vermehrt Themen und Diskussionen aufgetaucht, die sich um die "richtige" Definition und Instantiierung von Objekten dreht.
  • Singleton
  • Multiton
  • Factory
  • get_instance
  • Constructor-Parameter (ja, nein, wie viele?)
  • usw
Das hängt immer vom Einzelfall ab. Ein Singleton nutzt man, wenn man nur ein Objekt braucht. Ich brauche keine n Instanzen einer Persistenzklasse, um n MARA-Sätze zu speichern, sondern nur eine. Ich brauche auch nicht n Instanzen einer UI-Klasse für einen Dialog. Ein Singleton schützt mich einfach davor, versehentlich den Speicher mit Instanzen zuzunageln.

Ein Multiton (SaskuAc liest meine Postings scheinbar nicht, ich hab schon vor Jahren das Pattern beschrieben) brauche ich, um mehrere Instanzen zu verwalten, weil ich z. B. eine Reihe von Materialstämmen verwalten will und verhindern will, dass ich für einen Materialstamm mehrere Objekte habe, die ggf. widersprüchliche Sachen tun. Im Grunde ist es es wie ein Singleton mit einer Tabelle als Attribut. Beides nutzt man, um es nicht dem Verwender zu überlassen, wie und wann ein Objekt erzeugt wird.

Eine Factory verwendet man, um die (Verantwortung für die) Instanziierung nicht nur vom Verwender abzukoppeln, sondern auch vom Erzeuger. Weil zum Beispiel das Objekt einer Subklasse erzeugt wird und der Erzeuger gar nicht weiß, welche Subklasse das Objekt erzeugt. So wird dann die wirklich objekterzeugende Klasse austauschbar, änderbar, erweiterbar. Das ist insbesondere bei der Frage der Testbarkeit von Belang, wie austuschbar die Implementierungen sind.

Der Constructor wird ohnehin immer durchlaufen, aber es hat sich gezeigt, dass es selten sinnvoll ist, ihn auszuprägen, um Vorgabewerte zu vergeben. Grund: Ändert sich die Logik oder der Typ für einen Vorgabewert, muss der constructor geändert und bezüglich seiner kompletten Funktionalität getestet werden. Verwende ich setter-Methoden, ändere ich nur das Coding für diesen einen Vorgabewert, was den Testaufwand senkt. Dann muss natürlich klar sein, welche Setter-Methoden unbedingt durchlaufen werden müssen, damit das Objekt konsistent ist. Am Besten realisiert man das in einer Methode, die eben diese Konsistenz prüft, ehe das Objekt zu arbeiten beginnt und durch sprechende Unit-Tests, die dem Entwickler zeigen, wie er mit der Klasse umzugehen hat. Doku wäre natürlich auch nicht schlecht, aber ich bin ja bescheiden geworden.

Für den Constructor gilt, was für alle Methoden gilt: Viele Parameter deuten darauf hin, dass in der Methode prozedural programmiert wurde. Komplexe Daten übergibt man am Besten als komplexe Struktur oder gleich als Objekt, weil sich die Schnittstelle nicht (oder automatisch mit-)ändert, wenn sich die übergebenen Parameter ändern. Es muss sich für einen Parameter nur die Konsistenzprüfung ändern, schon muss muss man ganzen Konstruktor neu testen. Außerdem führen viele Parameter bei jeder Methode zu vielen Testläufen, weil (wenn man es ordentlich macht) jedes Testtupel von mindestens einem Testlauf getroffen wird.
ewx hat geschrieben:
  • Was sind die Vorteile, wenn ein CONSTRUCTOR keine/wenige/viele Parameter hat?
  • Was sind die Nachteile?
  • Wie verhält es sich bei Erweiterungen, also wenn Parameter hinzukommen müssten?
  • Lässt sich das umgehen? Wenn ja, wie?
  • Worauf muss man aufpassen?
  • Wie sieht ein Beispiel aus der Praxis aus?
  • Wo gab es bei bisherigen Projekten Schwierigkeiten? Welche? Wie wurden sie gelöst?
  • Wann ist ein singleton *wirklich* sinnvoll?
Wenige Parameter sind immer gut, keine sind noch besser, das gilt nicht nur für Konstruktoren, schon der vielen Testtupel wegen. Wenn man viele Parameter hat, sind sie in der Regel (nach meiner Erfahrung) schlecht oder gar nicht zusammengefasst. Wenn mehrere Variablen einen semantischen Zusammenhang haben, gehören sie in eine Struktur oder ein Objekt.

Wenn Parameter hinzukommen, behilft man sich zumeist mit optionalen Parametern. Das ist schnell und billig, aber nicht gründlich, weil man darüber immer wieder stolpern wird. Die Alternative eines Refactorings (eines Überarbeitens aller alten Aufrufstellen) sollte zumindest erwogen (und aufwandstechnisch durchgerechnet) werden. Der Grundfehler ist aber oben schon beschrieben: Übergebe ich Daten in einer komplexen Struktur oder einem Objekt, kann mir das fast nicht passieren, weil ich den Typen jederzeit anpassen kann, ohne die Schnittstelle ändern zu müssen. Und *eigentlich* ist Objektorientierte Programmierung die „Programmierung der *Kommunikation* von Objekten“ (weshalb die Erfinder des OO den Namen bis heute falsch finden, weil es eigentlich eine kommunikationsorientierte Programmierung ist). Nach meinen Erfahrungen ist DAS der Punkt, den viele im OO arbeitenden Entwickler gar nicht verstanden haben: Es geht nicht um die Objekte an sich, sondern um die Kommunikation zwischen ihnen. Darum arbeitet man mit Interfaces (die ja eben diese Kommunikation klassenübergreifend festlegen), und darum sind gute Methodenschnittstelle so wichtig. Im Grunde kann man sagen: An der Zahl der Methodenaufrufe kann man ungefähr ermessen, wie gut OO verstanden wurde. Ein mächtiger Konstruktor (eine Methode) mit vielen Parametern im Vergleich zu einem kleinen Konstruktor (mit weniger Parametern) mit vielen settern ist ein Hinweis auf wenig durchdachtes OO. Natürlich kann man sich hinstellen und sagen „Was soll eine Methode mit einer Anweisung?“, aber es gibt eben triftige Gründe dafür. Sogar eine implementierte Methode OHNE Anweisung kann sehr wichtig sein.

Und ehe jetzt wieder wer meine Worte auf die Goldwaage legt: Nein, es ist nicht alleiniges oder primäres Kriterium, aber ein Hinweis darauf. Natürlich kann man auch mit vielen Methodenaufrufen schlechtes OO schreiben. Es ist aber schwierig, mit wenigen Methoden gutes OO zu schreiben, weil die Methodenaufrufe ja die Kommunikation zwischen den Objekten darstellen.

Ich hatte neulich den Fall, dass jemand Datum und Uhrzeit an eine Methode übergeben hat, damit sie sich einen Zeitstempel errechnen kann. Ersetzt habe ich die zwei Parameter durch ein Interface, das von einer Klasse implementiert ist, die einen Zeitstempel ermittelt. So habe ich nur einen Parameter und wenn ich zum Zeitstempel noch etwas anderes brauche (meinerwegen einen zweiten), ändere ich die Schnittstellendefinition, einen optionalen Parameter brauche ich dazu nicht. Bei einem Parameter ohne Verhalten reicht dann auch eine tiefe Struktur. Aber oftmals kommt dann eben doch Verhalten dazu....

Zum Singleton habe ich ja oben schon einiges geschrieben. In der Regel ist es so, dass Akteure (Belege, Lieferungen, etc.) kein Singleton haben sollten, technische Klassen aber eben doch. Beispiele sind Persistenzklassen, die ja auch nur EINE Tabelle repräsentieren, Factory-Klassen, etc.

Interessanterweise erhalte ich Rückendeckung für meine Entwicklungsmethode (private Instanzenbildung mit Erzeugermethode), die hier kürzlich kritisiert wurde, vom Autor des Buches „Agile ABAP Entwicklung“, der deutlich für diese Technik plädiert.
ewx hat geschrieben: Natürlich sollen am Ende ein oder mehrere Artikel im Tricktresor dabei herauskommen, in dem man alles gesammelt nachlesen kann...! ;)
Wo DU dann schreibst, was für tolle Ideen du hattest? LOL


Ralf
Zuletzt geändert von ralf.wenzel am 3. Jan 2019 16:25, insgesamt 1-mal geändert.

Folgende Benutzer bedankten sich beim Autor ralf.wenzel für den Beitrag (Insgesamt 2):
ewxTommy Nightmare


Re: CONSTRUCTOR & Co. [Sammeln & Seltenes]

Beitrag von ewx (Top Expert / 3972 / 164 / 368 ) » 3. Jan 2019 13:57

Ralf.Wenzel hat geschrieben:Wo DU dann schreibst, was für tolle Ideen du hattest? LOL
Ganz genau! 8)

Re: CONSTRUCTOR & Co. [Sammeln & Seltenes]

Beitrag von a-dead-trousers (Top Expert / 3217 / 81 / 799 ) » 3. Jan 2019 21:03

Ich bin ne faule Sau und deher hatte ich nicht die Zeit alle Postings zu lesen, aber ein Prolem über das ich immer wieder stolpere ist, dass man CONSTRUCTOR-Methoden und daraus aufgerufene Methoden (in ABAP) NICHT so überladen kann wie erwartet. Deswegen baue ich in meinen ganzen Frameworks z,B. eine INITIALIZE Methode ein die grundsätzlich den Constructor ablöst und wie aus anderen Programmiersprachen erwartet überladen werden kann.
Das Problem ist, dass ABAP im Constructor (und nur da) die Vererbung ignoriert. Das bedeutet, dass bei einer Methode die im Constructor einer untergeordneten Klasse aufgerufen wird, nicht die überladene Methode einer übergeordneten Klasse aufgerufen wird sondern nur die aktuelle Methode der untergeordneten Klasse.
Grundsätzlich kein Drama, wenn man weiß, dass sich ABAP so verhällt, aber dennoch ein Problem für jemanden, der aus einer anderen Programmierumgebung kommt. Man kann dies mit Framworks umgehen die z.B. eine INITIALZE-Methode verwenden die zwingend nach dem CONSTRUCTOR aufgerufen werden muss und somit die spezielle ABAP-Vorgabe der Constructor-Aufruf-Hierarchie umgeht.

Wenn das jemand anderes hier bereits eingebracht hat, möchte ich mich enschuldien, aber ich wollte diesen Punkt weder unter den Tisch fallen gelassen noch zu sehr hervorgehoben wissen.

lg ADT

Folgende Benutzer bedankten sich beim Autor a-dead-trousers für den Beitrag:
ewx

Theory is when you know something, but it doesn't work.
Practice is when something works, but you don't know why.
Programmers combine theory and practice: Nothing works and they don't know why.

ECC: 6.07
Basis: 7.40

Re: CONSTRUCTOR & Co. [Sammeln & Seltenes]

Beitrag von ralf.wenzel (Top Expert / 3416 / 149 / 220 ) » 3. Jan 2019 21:13

Nein, das hatte noch keiner erwähnt, auch ich hätte es im Kopf, aber dann vergessen. Das ist aber ein wichtiger Hinweis, weil viele das nicht wissen und es ein wahrlich überraschendes Verhalten darstellt. Und du hast recht: Es ist ein Argument, möglichst wenig direkt in den Konstruktor zu schreiben.

Du solltest aber ein wenig auf deine Wortwahl achten: Du meinst z. B. etwas anderes als überladen (das Überladen von Methoden wird in ABAP grundsätzlich nicht unterstützt). So kommt es leicht zu Missverständnissen.



Ralf

Folgende Benutzer bedankten sich beim Autor ralf.wenzel für den Beitrag:
a-dead-trousers


Re: CONSTRUCTOR & Co. [Sammeln & Seltenes]

Beitrag von a-dead-trousers (Top Expert / 3217 / 81 / 799 ) » 3. Jan 2019 22:43

ralf.wenzel hat geschrieben:Du solltest aber ein wenig auf deine Wortwahl achten: Du meinst z. B. etwas anderes als überladen (das Überladen von Methoden wird in ABAP grundsätzlich nicht unterstützt). So kommt es leicht zu Missverständnissen.
Sorry, wenn man eine Methode (theotetisch) durch eine ander ersetzen kann, war für mich das immer "überladen", aber du meinst das "überladen" einer Methode auch mit anderen Parametern, was in ABAP natürlich leider von jeher nie funktioniert hat. Peinlich jetzt, dass ich mich an die genaue Bezeichnung für diese Art der Methoden-Ersetzung nicht mehr erinnern kann. :oops:
(und ich komm ursprünglich aus der Java-Welt)
Man merkt dass ich mich in den letzten Jahr(zehnt)en zu sehr auf ABAP konzentriert habe.

EDIT:
Ein guter Freund hat mich gerade in Java bzw C++ darüber aufgeklärt, dass es sowohl die OWERWRITE als auch die OVERLOAD Anotation gibt. Damit wird dort die Unterscheidung zwischen diesen beiden Fälle deklariert.
Theory is when you know something, but it doesn't work.
Practice is when something works, but you don't know why.
Programmers combine theory and practice: Nothing works and they don't know why.

ECC: 6.07
Basis: 7.40

Re: CONSTRUCTOR & Co. [Sammeln & Seltenes]

Beitrag von ralf.wenzel (Top Expert / 3416 / 149 / 220 ) » 4. Jan 2019 07:41

a-dead-trousers hat geschrieben:
ralf.wenzel hat geschrieben:Du solltest aber ein wenig auf deine Wortwahl achten: Du meinst z. B. etwas anderes als überladen (das Überladen von Methoden wird in ABAP grundsätzlich nicht unterstützt). So kommt es leicht zu Missverständnissen.
Sorry, wenn man eine Methode (theotetisch) durch eine ander ersetzen kann, war für mich das immer "überladen",
Du suchst nach dem Wort „Redefinieren“.

Hinzufügen wollte ich aber mich, dass die Ansätze von Enno sich keinesfalls gegenseitig ausschließen. Am Beispiel einer Factory: Die ist stets selbst ein Singleton und kann auch Singletons oder Multitons erzeugen.

Hinweis an Enno: Unterscheide zwischen abstrakter und konkreter Factory, das sind grundsätzlich verschiedene Dinge.


Ralf

Re: CONSTRUCTOR & Co. [Sammeln & Seltenes]

Beitrag von black_adept (Top Expert / 3243 / 54 / 568 ) » 4. Jan 2019 08:03

  • Kann man eigentlich sagen, dass die Methode "GET_INSTANCE" eine Factory-Methode für den Singleton-Pattern ist?
  • Sollte man bei Verwendung von Factories die Instanzerzeugung der Klasse auf "Private" stellen
live long and prosper
Stefan Schmöcker

email: stefan@schmoecker.de

Re: CONSTRUCTOR & Co. [Sammeln & Seltenes]

Beitrag von black_adept (Top Expert / 3243 / 54 / 568 ) » 4. Jan 2019 08:58

ralf.wenzel hat geschrieben:Ich hatte neulich den Fall, dass jemand Datum und Uhrzeit an eine Methode übergeben hat, damit sie sich einen Zeitstempel errechnen kann. Ersetzt habe ich die zwei Parameter durch ein Interface, das von einer Klasse implementiert ist, die einen Zeitstempel ermittelt. So habe ich nur einen Parameter und wenn ich zum Zeitstempel noch etwas anderes brauche (meinerwegen einen zweiten), ändere ich die Schnittstellendefinition, einen optionalen Parameter brauche ich dazu nicht. Bei einem Parameter ohne Verhalten reicht dann auch eine tiefe Struktur. Aber oftmals kommt dann eben doch Verhalten dazu....
Das ist ein Paradebeispiel dafür, dass ich mich manchmal bei Ralfs Ausführungen frage: "Warum" oder "Was zum Geier meint er hier"?
Wenn ich das richtig verstanden habe ist jetzt folgendes entstanden:
Vorher:

Code: Alles auswählen.

lv_timestamp = get_timestamp( iv_datum = ...  iv_uzeit = ... ).
...
method get_timestamp.
  berechne irgendwie den Zeitstempel 
endmethod.
Nachher:

Code: Alles auswählen.

lo_implementation = get_instance_timestamphelperclass( ... ).
lo_implementation->set_time( ... ).
lo_implementation->set_data( ... ).
Entweder das hier 
  lv_timestamp = get_timestamp( lo_implementation ).
oder das hier
  lv_timestamp = lo_implementation->get_timestamp( ).

method get_timestamp.
  berechne irgendwie den Zeitstempel 
endmethod.
method get_implementation.
...
endmethod.
method set_time.
...
endmethod.
method set_data.
...
endmethod.

Aber das kann ich mir kaum vorstellen. Lieber Ralf - helle mich mal auf was für ein Konstrukt du jetzt verwendet hast.
live long and prosper
Stefan Schmöcker

email: stefan@schmoecker.de

Re: CONSTRUCTOR & Co. [Sammeln & Seltenes]

Beitrag von ralf.wenzel (Top Expert / 3416 / 149 / 220 ) » 4. Jan 2019 10:40

So ungefähr stimmt das, was du schreibst. Es sieht natürlich deutlich mehr aus, weil du „bei mir“ zwei Varianten zeigst. In Wahrheit verwende ich kaum mehr Coding als du. Der Punkt aber ist:

• Ich fasse die Daten zusammen, die zusammengehören
• Bei mir ändert sich die Methodenschnittstelle nicht, wenn die Definition des Timestamps sich ändert
• Ich habe einen Verwendungsnachweis auf die Timestamp-Verwendungen

Gerade beim ersten Punkt vermisse ich oft das Sehen der Datensemantik. Im Kontext des Timestamps sind Datum und Uhrzeit nur ein Teil der Daten. So wie ich nie auf die Idee kommen würde, in zwei verschiedenen Parametern erst die ersten 10 Stellen und dann den Rest einer Materialnummer zu übergeben, würde ich Datum und Zeit nie in Einzelfeldern übergeben in einem Kontext, wo sie nur gemeinsam zu betrachten sind. Also gehören Datum und Uhrzeit zumindest in eine Struktur. Weil zusammengehört, was zusammen betrachtet wird.

Nun haben wir hier nicht nur nicht-elementare Daten zu verwenden, sondern ein für diese Daten typisches Verhalten zu implementieren. Und beim Wort „datentypisches Verhalten“ (oder „Daten mit datenspezifischer Logik“) bin ich eben beim Objekt.

Zu deiner Frage „Was will der eigentlich?“ sage ich nur „Dokumentation“. Das Interface sollte dokumentiert und mit einem sprechenden Namen versehen sein. Dann fragt man sich das gar nicht erst. Schwerer zu lesen finde ich das nicht, zumal der eigentliche Aufruf sich ja sogar vereinfacht (nur ein Parameter statt zweien).

Der Grundirrtum ist eben oft „Die Instanz einer Klasse ist ein Objekt“. Ich gehe andersherum da ran (nämlich so, wie Alan Kay es definiert hat und er hat es immerhin erfunden): „Alles ist ein Objekt“. Ich mache also kein Objekt, weil ich eine Klasse habe, sondern ich schreibe eine Klasse, weil ich ein Objekt brauche. Das ist z. B. der Fall, wenn ich ein komplexes Datenobjekt habe, das über spezifisches Verhalten verfügen muss.

Ich habe selbst interne Tabellen manchmal in einer Klasse verschalt (mit einem Iterator-Pattern), wenn ich spezielle Eigenschaften brauchte, die man programmieren muss oder sogar Strukturen. Beispiel: Beim Aufbau von Materialstammsätzen für MATERIAL_MAINTAIN_DARK braucht man eine spezielle Datenhierarchie: Wenn ich zwei MARD-Sätze habe, brauche ich für jeden MARD-Satz auch einen korrespondierenden MARC- und und zu jedem MARC-Satz einen korrespondierenden MARA-Satz, so dass ein (!) Materialstamm durchaus aus 6 MARA-Sätzen bestehen kann.

Bei mir prüft ein MAR*-Satz ob ein übergeordneter Satz vorhanden ist. Ist dem nicht so, tritt er die Erzeugung an. Das ist viel einfacher als manueller Abgleich und muss nur einmal implementiert werden, um für beliebig viele Materialstämme zu funktionieren. So erhalte ich quasi „intelligente“ Strukturen, die selbst für ihre Konsistenz sorgen.


Ralf

Re: CONSTRUCTOR & Co. [Sammeln & Seltenes]

Beitrag von black_adept (Top Expert / 3243 / 54 / 568 ) » 4. Jan 2019 10:57

ralf.wenzel hat geschrieben:So ungefähr stimmt das, was du schreibst. Es sieht natürlich deutlich mehr aus, weil du „bei mir“ zwei Varianten zeigst. In Wahrheit verwende ich kaum mehr Coding als du.
Es sieht nicht nur so aus - es ist deutlich! mehr Coding. Letztlich habe ich das Gefühl, als ob du eine (bisher wohl nur lokal) verwendete Methode in eine Helperklasse verschiebst. Macht ja bei mehrfach verwendbaren Methoden durchaus Sinn - aber das war irgenwie nicht der Tenor deiner ursprünglichen Ausführung.
ralf.wenzel hat geschrieben:• Ich fasse die Daten zusammen, die zusammengehören
Das machte die ursprüngliche Methode auch, indem sie hoffentlich 2 Pflichtparameter verlangt hat. Gibt halt verschiedene Wege nach Rom
ralf.wenzel hat geschrieben:• Bei mir ändert sich die Methodenschnittstelle nicht, wenn die Definition des Timestamps sich ändert
WAS?
ralf.wenzel hat geschrieben:• Ich habe einen Verwendungsnachweis auf die Timestamp-Verwendungen
Die hatte man vorher auch durch den Verwendungsnachweis der Methode.
live long and prosper
Stefan Schmöcker

email: stefan@schmoecker.de

Re: CONSTRUCTOR & Co. [Sammeln & Seltenes]

Beitrag von erp-bt (Specialist / 156 / 4 / 20 ) » 4. Jan 2019 11:04

black_adept hat geschrieben:
  • Kann man eigentlich sagen, dass die Methode "GET_INSTANCE" eine Factory-Methode für den Singleton-Pattern ist?
Nein, könnten zur Laufzeit ja ganz unterschiedliche Instanzen geholt werden. Je nachdem was man gerade benötigt. GET_INSTANCE ist einfach das delegieren der Instanzerzeugung, kann dann natürlich auch ein Singleton sein.
black_adept hat geschrieben:
  • Sollte man bei Verwendung von Factories die Instanzerzeugung der Klasse auf "Private" stellen
[/list]
Sollte so sein. Wenn Du eine separate Factory-Klasse hast, muss diese allerdings dann als "Friend" der eigentlich zu instantiierenden Klasse definiert werden.

Liebe Grüße, Tapio
...entwickelnder Berater...beratender Entwickler

Seite 1 von 3 (current) Nächste

Aktuelle Forenbeiträge

Langtext zur Exception
vor 54 Minuten von a-dead-trousers 11 / 96
Welche Entwicklertools?
vor 18 Stunden von LostDarkness 2 / 922
Werksspezifische Konfiguration kopieren
vor 19 Stunden von eleve 2 / 48
Removal of left space - next to a docking container
vor 19 Stunden von Haemma83 16 / 115

Unbeantwortete Forenbeiträge

BAPI_PO_CREATE1 und Einkaufsinfosatz
vor 3 Tagen von SweetRuedi 1 / 81
WCOCO: Gruppe für Betragsfelder 0S01
vor 5 Tagen von SAP_ENTWICKLER 1 / 52
CAS-Nr.: Chemical Abstracs Service
vor einer Woche von SAP_ENTWICKLER 1 / 92
Interaktives Skript, Rolle IC-Manager
vor 3 Wochen von erubadhron86 1 / 129