CONSTRUCTOR & Co. [Sammeln & Seltenes]

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

Re: CONSTRUCTOR & Co. [Sammeln & Seltenes] ~ Optionale Param

Beitrag von ewx (Top Expert / 3963 / 164 / 366 ) » 7. Jan 2019 19:04

Was optionale Parameter und deren Bündelung in einer Struktur angeht...
ralf.wenzel hat geschrieben: 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.
Da zeige ich dir in unserem System auf die Schnell 5077 Negativbeispiele:
Alle BAPI_* Funktionsbausteine. Da sind alle Kopfdaten in einer Kopfstruktur und so weiter. Das hilft dir aber auch nicht weiter, weil es innerhalb der Struktur diverse Abhängigkeiten gibt.

Letztendlich ist es egal, ob ich einen neuen Parameter hinzufüge oder der Zugrunde liegenden Struktur ein Feld: Ich muss Anpassungen vornehmen. Habe dabei im Testumfeld sogar den Vorteil, dass mir das System sagt, welche Methodenaufrufe ich alle anfassen muss (sofern ich den neuen Parameter nicht als optional kennzeichne).

Schön finde ich die von Paul Hardy vorgestellte Methode in seinem Buch ABAP to the future:
Preconditions and Postconditions

Er hat eine einfache Methode geschrieben, mit der man die Bedingungen für die Parameter sprachlich gut erfassen kann:

Code: Alles auswählen.

zcl_dbc=>require( 
    that = 'DATE is given, TIME is given or DATE and TIME are given'
    which_is_true_if = boolc( ( date is initial and time is not initial ) 
                           or ( date is not initial and time is initial )
                           or ( date is not initial and time is not initial ) ) ).
Das ist jetzt natürlich ein einigermaßen doofes Beispiel und ja, man kann die Bedingung auch einfach so als CHECK programmieren.
Es macht aber deutlich, was die Funktion erwartet.

Wo ich regelmäßig stolpere ist, wenn ich ein GUI-Control baue, dass ich für den Aufrufer möglichst einfach aufrufbar machen möchte.
Einfach heißt in dem Fall, dass der Aufrufer den Namen eines Custom-Containers oder eine Containerinstanz übergeben kann.
1.: bekommt der CONSTRUCTOR diese beiden Parameter mit?
2.: oder mache ich eine extra Methode DISPLAY?

(1) hat den Vorteil, dass ich im PBO einfach programmieren kann:

Code: Alles auswählen.

IF myObject IS INITIAL. o_object = new #( container_name = 'CC_HUGO' ). ENDIF.
Evtl. will ich aber die Instantiierung viel früher machen, weil bereits Daten gelesen werden...? Dann müsste ich Variante (2) verwenden.
(2) hat den Nachteil, dass der Aufrufer wissen muss, dass er diese Methode zur Anzeige aufrufen muss.


Re: CONSTRUCTOR & Co. [Sammeln & Seltenes]

Beitrag von ralf.wenzel (Top Expert / 3414 / 149 / 219 ) » 7. Jan 2019 19:26

Der Aufrufer guckt sich sicherlich die Klassenschnittstelle (also die öffentlichen Komponenten) an, ehe er eine Klasse verwendet. Somit wird er die Display-Methode sehen, darum verwende ich immer Methode 2.

Zum anderen Thema: Man kann einer Meinung sein oder eben nicht. Für mich gehören semantisch zusammengehörige Daten in ein Datenobjekt. Je nach Art der Daten ist das eine Struktur, eine Tabelle oder eben ein Objekt.

Ich packe gerade und habe kein System, vielleicht schaffe ich es morgen beim Kunden, dazu was zu schreiben.


Ralf

Re: CONSTRUCTOR & Co. [Sammeln & Seltenes] ~ Anforderung

Beitrag von ewx (Top Expert / 3963 / 164 / 366 ) » 7. Jan 2019 19:28

Ein großes Problem bei Parametern ist m.E. häufig, dass gar nicht genau definiert ist, wann wie welche Parameter mit welchen Werten gefüllt sein müssen oder dürfen.
Wenn ich bei der Timestamp-Methode bleibe, dann möchte ich evtl. prüfen, ob die übergebenen Daten auch wirklich ein Datum oder eine Uhrzeit sind:

Code: Alles auswählen.

IF i_datum(4) > 3000. RAISE wrong_year. 
IF i_datum+4(2) = '00' or i_datum+4(2) > 12. RAISE wrong_month. 
IF i_datum+6(2) = '00' or i_datum+6(2) > 31. RAISE wrong_day.
Aber wenn ich das mache und z.B. das Jahr prüfen möchte, dann hängt es von der Anwendung ab, welche Gültigkeiten gelten sollen. Wenn ich das Datum für Personen prüfen möchte, dann kann ich vielleicht grob sagen: es lebt keiner mehr, der vor 1900 geboren wurde. Wenn die Anwendung jetzt aber erweitert wird, so dass auch das Geburtsdatum der Eltern und Großeltern eingetragen werden muss...?

Und selbst wenn das Datum oder die Uhrzeit falsch sind, weil sie von einer Schnittstelle falsch geliefert werden: ist _meine_ Methode dann dafür verantwortlich, wenn der timestamp falsch erzeugt wird?
Was sind geeignete Maßnahmen, um fehlerhafte Parameter abzufangen? Muss ich für jede Eventualität eine Sicherung einbauen?

Und auch dann: Bei einem Datum kann ich Prüfungen machen und kann auch gut argumentieren, dass _meine_ Methode keine fehlerhaften Timestamps erzeugen wird. Wenn dann wirklich über eine Schnittstelle falsche Daten geliefert werden, müssen diese an anderer Stelle geprüft werden. Oder die Methoden muss erweitert werden, so dass Fehler korrigiert werden.

Aber auch hier ist es immer noch einfach. Ich muss mich als Programmierer entscheiden ob und wie ich eine Fehlerbehandlung machen möchte.

Kompliziert wird es dann, wenn immer mehr Parameter für bestimmte Fälle dazu kommen und hinterher gar nicht mehr klar ist, was wie in welcher Kombination überhaupt möglich ist.
Da mag man dann sagen: "tja, schlecht konzipiert", aber so sieht doch der Arbeitsalltag bei Programmierern häufig aus.
Wo ist dann der Punkt wo ich sagen muss: "Jetzt muss eine neue/ zweite/ dritte Methode her" oder "Jetzt muss ich mal alle Parameter hinterfragen"?
Selbst wenn man das machen würde, scheitert es häufig daran, dass man das gar nicht mehr testen kann.

Re: CONSTRUCTOR & Co. [Sammeln & Seltenes] ~ Optionale Param

Beitrag von black_adept (Top Expert / 3243 / 54 / 568 ) » 7. Jan 2019 20:49

ewx hat geschrieben:Wo ich regelmäßig stolpere ist, wenn ich ein GUI-Control baue, dass ich für den Aufrufer möglichst einfach aufrufbar machen möchte.
Einfach heißt in dem Fall, dass der Aufrufer den Namen eines Custom-Containers oder eine Containerinstanz übergeben kann.
1.: bekommt der CONSTRUCTOR diese beiden Parameter mit?
2.: oder mache ich eine extra Methode DISPLAY?
Wofür soll jetzt die Extramethode gut sein bzw. was macht die anders als der Konstruktor?
Davon abgesehen - wenn du es wirklich einfach halten willst nimm einen Parameter - dafür vom Typ "ANY" und schreib in die Beschreibung rein was erwartet wird. Im Coding kannst du dann je nach übergebenem Typ ( Referenz oder C-Feld ) intern unterscheiden. Nachteil ist halt die dadurch auf die Runtime verschobene Typprüfung - Vorteil die einfache Bedienbarkeit. Manchmal muss man halt entscheiden was man für wichtiger hält.
live long and prosper
Stefan Schmöcker

email: stefan@schmoecker.de

Re: CONSTRUCTOR & Co. [Sammeln & Seltenes] ~ Optionale Param

Beitrag von a-dead-trousers (Top Expert / 3212 / 81 / 798 ) » 7. Jan 2019 22:43

black_adept hat geschrieben:Wofür soll jetzt die Extramethode gut sein bzw. was macht die anders als der Konstruktor?
Wie ich schon erwähnt hab ist der einzig wirkliche Vorteil, dass die "Redefinierbarkeit" voll gegeben ist.
Mit dem Nachteil, dass man eben eine eigene Methode dafür (ver-)braucht.

Was mir persöhnlich noch an der Extramethode gegenüber der Konstruktorinitialisierung besser gefällt, ist das nachgelagerte Fehlerhandling. Beim Konstruktor hat man im Fehlerfall (Exceptionhandling hin oder her) *kein* Objekt, was man (theoretisch) im weiteren Verlauf berücksichtigen muss. Bei einem "leeren" Konstruktor und einer Extramethode ist das Objekt nach dem CREATE oder NEW() ohne weitere notwendige Prüfungen immer vorhanden. Selbst wenn das INITIALIZE nicht funktioniert hat, kann man das Objekt noch verwenden und es kann auch noch Auskunft über seinen Status geben (IS_INITIALIZED, GET_LAST_ERROR usw.)
Natürlich kann man darüber jetzt streiten, ob man das alles nicht doch besser mit Exception-Klassen löst oder nicht. Ich bin da je nach Anwendungsumfang recht flexibel. Mal machen echte Exceptions mehr Sinn und ein anderes Mal doch die "Statusauskunft". Vielleicht sehe ich das auch deswegen nicht so eng, weil Exceptions für mich immer irgendwie den Touch haben "hier ist Endstation und nichts geht mehr" und ich sie daher immer sehr sparsam verwendet hab. Ich hab auch schon mal mit dem "Resumeable" herumgespielt, aber das wirkt vom Verhalten her nicht so ganz wie aus einem Guß. Es ist IMHO auch nicht so leicht zu durchschauen wann, wie und wo das "Resume" jetzt eigentlich mit der Arbeit fortsetzt.
Kommen dann noch ein, zwei oder mehrere CLEANUP dazu ... :?
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] ~ Optionale Param

Beitrag von black_adept (Top Expert / 3243 / 54 / 568 ) » 7. Jan 2019 23:21

a-dead-trousers hat geschrieben:Wie ich schon erwähnt hab ist der einzig wirkliche Vorteil, dass die "Redefinierbarkeit" voll gegeben ist.
Mit dem Nachteil, dass man eben eine eigene Methode dafür (ver-)braucht.

Vielleicht ist das ja genau der Grund, warum es den Konstruktor gibt - gemacht für den gegenteiligen Fall. Wenn ich mit meinem Objekt sicher stellen will, dass auch alle abgeleiteten Klassen gewisse Standards einhalten kann ich durch meine Definition des Konstruktors festlegen, dass all diese meine Initialisierungen durchlaufen müssen und nicht irgendwelchen Schlonz machen können, indem sie meine Initialisierungen redefinieren.
live long and prosper
Stefan Schmöcker

email: stefan@schmoecker.de

Re: CONSTRUCTOR & Co. [Sammeln & Seltenes] ~ Optionale Param

Beitrag von ralf.wenzel (Top Expert / 3414 / 149 / 219 ) » 8. Jan 2019 09:07

ewx hat geschrieben:Ein großes Problem bei Parametern ist m.E. häufig, dass gar nicht genau definiert ist, wann wie welche Parameter mit welchen Werten gefüllt sein müssen oder dürfen.
Wenn ich bei der Timestamp-Methode bleibe, dann möchte ich evtl. prüfen, ob die übergebenen Daten auch wirklich ein Datum oder eine Uhrzeit sind:

Code: Alles auswählen.

IF i_datum(4) > 3000. RAISE wrong_year. 
IF i_datum+4(2) = '00' or i_datum+4(2) > 12. RAISE wrong_month. 
IF i_datum+6(2) = '00' or i_datum+6(2) > 31. RAISE wrong_day.
Und genau sowas gehört in meinen Augen in die IF-Implementierung rein, die sicherstellt, dass ich der Methode nur gültige Datumsangaben übermittle. Die empfangende Methode sollte das nicht erst noch verproben müssen (um dann Ausnahmen zu werfen, wenn die Angaben ungültig sind). Der Vorteil bei Objekten ist halt: Sie können sich schön auf Konsistenz selbst prüfen und was immer das Objekt rausgibt, ist konsistent. Das ist ein Beispiel für "datenspezifische Logik". Einer Methode potentiell ungültige Daten vor die Füße zu werfen, finde ich schon deshalb doof, weil dann die Methode einen Fehler wirft, die gar nicht fehlerhaft ist, sondern deren Arbeitsvoraussetzungen. Den Fehler sucht man dann im Aufrufer, den man erstmal suchen muss.

Abgesehen davon gilt das, was ich über OO im Allgemeinen geschrieben habe: OO ist das Kommunizieren von Objekten mittels Methodenaufrufen. Kann man wollen, kann man lassen, aber es mal so und mal so zu machen, finde ich verwirrend.

Aber wie ich schon schrieb: Ich habe nicht den Anspruch, dass jeder meiner Meinung ist ;) Ich wollte hier nur beschreiben, wie ich es in diesem Falle mache (sozusagen als Denkanstoß) und begründen, warum das so ist.

Vom eigentlichen Thema entwickeln wir uns übrigens weg. Wir sollten uns ggf. wieder mehr der Objekterzeugung widmen.
a-dead-trousers hat geschrieben:Natürlich kann man darüber jetzt streiten, ob man das alles nicht doch besser mit Exception-Klassen löst oder nicht. Ich bin da je nach Anwendungsumfang recht flexibel. Mal machen echte Exceptions mehr Sinn und ein anderes Mal doch die "Statusauskunft". Vielleicht sehe ich das auch deswegen nicht so eng, weil Exceptions für mich immer irgendwie den Touch haben "hier ist Endstation und nichts geht mehr"
Davon solltest du dich lösen. Eine Ausnahmebehandlung ist (ganz grob gesagt) für alle Fälle sinnvoll, wo auch ein "if sy-subrc ne 0" sinnvoll ist. Das muss nicht in einer Fehlermeldung enden, sondern kann durchaus ein alternatives operatives Coding sein.

Aber ein Constructor, der keine Ausnahme wirft UND kein Objekt erzeugt, würde mich überraschen. Dafür sind Ausnahmen da: Ich will was, ich kriege es nicht, also kommt eine Ausnahme.


Ralf

Re: CONSTRUCTOR & Co. [Sammeln & Seltenes] ~ Optionale Param

Beitrag von ewx (Top Expert / 3963 / 164 / 366 ) » 9. Jan 2019 11:20

black_adept hat geschrieben:
ewx hat geschrieben:Wo ich regelmäßig stolpere ist, wenn ich ein GUI-Control baue, dass ich für den Aufrufer möglichst einfach aufrufbar machen möchte.
Einfach heißt in dem Fall, dass der Aufrufer den Namen eines Custom-Containers oder eine Containerinstanz übergeben kann.
1.: bekommt der CONSTRUCTOR diese beiden Parameter mit?
2.: oder mache ich eine extra Methode DISPLAY?
Wofür soll jetzt die Extramethode gut sein bzw. was macht die anders als der Konstruktor?
Sie macht nichts anders, sondern nur "separat".
Wäre in sofern sinnvoll, wenn der CONSTRUCTOR noch weitere Parameter bräuchte.
Dann würde man diese Anzeige-relevanten Parameter schon mal auslagern.
black_adept hat geschrieben: Davon abgesehen - wenn du es wirklich einfach halten willst nimm einen Parameter - dafür vom Typ "ANY" und schreib in die Beschreibung rein was erwartet wird. Im Coding kannst du dann je nach übergebenem Typ ( Referenz oder C-Feld ) intern unterscheiden. Nachteil ist halt die dadurch auf die Runtime verschobene Typprüfung - Vorteil die einfache Bedienbarkeit. Manchmal muss man halt entscheiden was man für wichtiger hält.
puh. Das ist aber schon einigermaßen dirty... ;)

Re: CONSTRUCTOR & Co. [Sammeln & Seltenes]

Beitrag von ralf.wenzel (Top Expert / 3414 / 149 / 219 ) » 9. Jan 2019 11:23

Das ist nicht nur dirty, sondern der Aufrufer wird kaum verstehen, was er mitgeben muss. Also muss er die Methode lesen und das ist eigentlich gegen das Konzept.


Ralf

Re: CONSTRUCTOR & Co. [Sammeln & Seltenes] ~ Optionale Param

Beitrag von black_adept (Top Expert / 3243 / 54 / 568 ) » 9. Jan 2019 13:36

ewx hat geschrieben:puh. Das ist aber schon einigermaßen dirty... ;)
ralf.wenzel hat geschrieben:Das ist nicht nur dirty, sondern der Aufrufer wird kaum verstehen, was er mitgeben muss. Also muss er die Methode lesen und das ist eigentlich gegen das Konzept.
Schau dir mal in ABAP2XLSX die Methoden an, die irgendwie mit Spalten zu tun haben. Einerseits kann man die Spalten nummerisch, andererseits in der Excel-üblichen Schreibweise "A-Z,AA-ZZ, AAA..." angeben. Nahezu alle Methoden, die irgendwo eine Spalte erwarten sind so nett dem Aufrufer sowohl das eine als auch das andere zu erlauben, je nachdem was gerade beim Aufrufer zur Verfügung steht.
Ist im Endeffekt nichts anderes als was SAP bei diversen Befehlen auch von Haus aus kann - z.B. beim ASSIGN COMPONENT comp OF STRUCTURE struc , wo je nach Typ von comp anders verfahren wird.
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 ) » 9. Jan 2019 13:45

Nachtrag zu eben: Ja - ich verwende tatsächlich solche Klassen, die auf verschiedene Eingabetypen leicht unterschiedlich reagieren. Beispiel ist eine Utilitymethode, die mir einen Feldkatalog zurückliefert. Und ob ich nun eine Tabelle, eine Struktur, eine Referenz auf eine Tabelle oder Struktur übergebe. Die Methode gibt mir immer schön einen Feldkatalog zurück.
Man sollte mit solchen Sachen auch nicht um sich werfen bloß weil man es kann. Denn der Verlust der statischen Typprüfung sollte immer im Hinterkopf bleiben, so dass solch "Typ-überladene" Parameter die absolute Ausnahme bleiben sollten. Aber in dem o.a. Fall ist die Schlichtheit der Verwendung in meinen Augen zu präferieren.

Folgende Benutzer bedankten sich beim Autor black_adept für den Beitrag (Insgesamt 2):
ralf.wenzela-dead-trousers

live long and prosper
Stefan Schmöcker

email: stefan@schmoecker.de

Re: CONSTRUCTOR & Co. [Sammeln & Seltenes]

Beitrag von a-dead-trousers (Top Expert / 3212 / 81 / 798 ) » 9. Jan 2019 21:32

black_adept hat geschrieben:Beispiel ist eine Utilitymethode, die mir einen Feldkatalog zurückliefert. Und ob ich nun eine Tabelle, eine Struktur, eine Referenz auf eine Tabelle oder Struktur übergebe. Die Methode gibt mir immer schön einen Feldkatalog zurück.
Ja, die Methode hab ich auch. 8)
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


Vorherige Seite 3 von 3 (current)

Aktuelle Forenbeiträge

Quellcodeänderung mehrerer Programme
vor 23 Minuten von Tron 11 / 309
BAPI_PO_CREATE1 und Einkaufsinfosatz
Gestern von SweetRuedi 1 / 55
Format xx oder xx-xx oder xx-xx-xx
vor 2 Tagen von black_adept 5 / 195
Salv Table - Layouts speichern
vor 2 Tagen von ewx 2 / 81
WCOCO: Gruppe für Betragsfelder 0S01
vor 3 Tagen von SAP_ENTWICKLER 1 / 41

Unbeantwortete Forenbeiträge

BAPI_PO_CREATE1 und Einkaufsinfosatz
Gestern von SweetRuedi 1 / 55
WCOCO: Gruppe für Betragsfelder 0S01
vor 3 Tagen von SAP_ENTWICKLER 1 / 41
CAS-Nr.: Chemical Abstracs Service
vor 5 Tagen von SAP_ENTWICKLER 1 / 76
Interaktives Skript, Rolle IC-Manager
vor einer Woche von erubadhron86 1 / 118
Wie findet man das Rahmenprogramm eines Infosets?
vor einer Woche von DeathAndPain 1 / 142