Hmm, ich habe das zwar noch nie benötigt, aber kannst Du die Methode der übergeordneten Klasse nicht einfach mit "SUPER->" aufrufen?a-dead-trousers hat geschrieben: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
Ich kann das Verhalten der Klasse doch jederzeit ändern. An der Methodenschnittstelle ändert das nichts, die bekommt das Objekt. Was passiert, wenn du z. B. die Zeitzone mit in den Timestamp reinrechnen sollst? Dann brauchst du einen weiteren Parameter, entweder optional oder du änderst alle Aufrufe. Ich baue eine neue Setter-Methode und schreibe damit ein neues Attribut, als Parameter übergebe ich trotzdem mein „altes“ Interface. In agilen Projekten kommt es ständig vor, dass sich sowas ändert.black_adept hat geschrieben:WAS?ralf.wenzel hat geschrieben:• Bei mir ändert sich die Methodenschnittstelle nicht, wenn die Definition des Timestamps sich ändert
Zumeist nennt man die Methode beim Singleton GET_INSTANCE, ansonsten CREATE. Darum sind Parameter beim CREATE üblich, beim GET_INSTANCE eher selten.erp-bt hat geschrieben: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:
- Kann man eigentlich sagen, dass die Methode "GET_INSTANCE" eine Factory-Methode für den Singleton-Pattern ist?
Der Zweck einer Factory ist die Entkoppelung, dann sollte man verhindern, dass jemand an der Factory vorbei Objekte erzeugt. Das geht nur so.erp-bt hat geschrieben:Sollte so sein. Wenn Du eine separate Factory-Klasse hast, muss diese allerdings dann als "Friend" der eigentlich zu instantiierenden Klasse definiert werden.black_adept hat geschrieben:[/list]
- Sollte man bei Verwendung von Factories die Instanzerzeugung der Klasse auf "Private" stellen
Deine Ausführungen zeigen, dass du selbst da Objekte siehst, wo ich einfach nur subtriviale Funktionalitäten sehe. Wenn du der Meinung bist für so was wie das o.a. Zeitstempelbeispiel eine eigene Klasse zu benötigen - es sei dir gegönnt. Bei mir tut es tatsächlich eine Methode ( mit dann von mir aus optionalem Parameter für die Zeitzone oder eine Alternativmethode mit zusätzlich dem Zeitstempel dabei oder ...). Dass sich dann bei mir nicht das Verhalten eines Datenobjekts sondern nur das Verhalten einer Methode ändert macht mich jetzt nicht sonderlich traurig.ralf.wenzel hat geschrieben:Ich kann das Verhalten der Klasse doch jederzeit ändern. An der Methodenschnittstelle ändert das nichts, die bekommt das Objekt. Was passiert, wenn du z. B. die Zeitzone mit in den Timestamp reinrechnen sollst? Dann brauchst du einen weiteren Parameter, entweder optional oder du änderst alle Aufrufe. Ich baue eine neue Setter-Methode und schreibe damit ein neues Attribut, als Parameter übergebe ich trotzdem mein „altes“ Interface. In agilen Projekten kommt es ständig vor, dass sich sowas ändert.black_adept hat geschrieben:WAS?ralf.wenzel hat geschrieben:• Bei mir ändert sich die Methodenschnittstelle nicht, wenn die Definition des Timestamps sich ändert
Deine Ausführungen zeigen genau, was ich sagte: Du betrachtest eines Klasse als ein Programm-Modul. So wie eine Funktionsgruppe, wo man mehrfach benötigtes Coding kapselt. Das ist genau NICHT das Konzept von OO. Denn dieses bindet das Verhalten von Datenobjekten an das Datenobjekt selbst
Wohl kaum. Aber ich betrachte Methoden häufig als Programm-Modul - und genau davon sprachen wir ursprünglich als du ausführtest, eine in meinen Augen einfach und sinnvoll entworfene Methode in ein anderes Rahmenkonzept zu bringen. Und ich halte in diesem speziellen Fall deine Vorgehensweise tatsächlich für einen Overhead, der für mich keinen Mehrwert in Lesbarkeit oder Wartbarkeit bietet. Mag ja sein, dass so was bei komplexeren Dingen seine Daseinsberechtigung hat - aber nicht hier.ralf.wenzel hat geschrieben: Du betrachtest eines Klasse als ein Programm-Modul. So wie eine Funktionsgruppe, wo man mehrfach benötigtes Coding kapselt.
und:Ein Element, welches Funktionen, Methoden, Prozeduren, einen inneren Zustand, oder mehrere dieser Dinge besitzt.
Nirgendwo steht „eine Klasse ist ein Teil eines Programms“, weil ein Objekt eben ein eigenständiges Etwas ist, das sich mit prozeduralen Begriffen nicht umfassend erklären lässt.Die Klasse entspricht in etwa einem komplexen Datentyp wie in der prozeduralen Programmierung, geht aber darüber hinaus: Sie legt nicht nur die Datentypen fest, aus denen die mit Hilfe der Klassen erzeugten Objekte bestehen, sie definiert zudem die Algorithmen, die auf diesen Daten operieren.
Natürlich kannst du mit SUPER-> auf die ursprügliche Implementierung einer redefinierten Methode zugreifen AUßER im Konstruktor.erp-bt hat geschrieben:Hmm, ich habe das zwar noch nie benötigt, aber kannst Du die Methode der übergeordneten Klasse nicht einfach mit "SUPER->" aufrufen?
Generierst Du Dir durch eine separate INITIALIZE-Methode nicht eine Abhängigkeit zur rufenden Klasse oder rufst Du die im Constructor? Würde mich mal interessieren.
Folgende Benutzer bedankten sich beim Autor a-dead-trousers für den Beitrag:
erp-bt
In der Theorie hast du ja recht. Aber ich finde das trotzdem korrekt so vorzugehen, dass man Datum und Uhrzeit abfragt. Grund: Wenn ich beides brauche setze ich halt beide Parameter nicht auf optional --> der Aufrufer muss beide mitgeben.a-dead-trousers hat geschrieben:Bestes Beispiel ist hier die Angabe von Datum UND Uhrzeit wenn man eigentlich einen Zeitpunkt übergeben möchte.
Um das noch mehr herauszustreichen, was a-d-t gerade gepostet hat: Im Konstruktor während er Objekterzeugung wird nicht die redefinierte Methode aufgerufen, nachher schon.a-dead-trousers hat geschrieben:Natürlich kannst du mit SUPER-> auf die ursprügliche Implementierung einer redefinierten Methode zugreifen AUßER im Konstruktor.
Gegeben seinen zwei Klassen X und Y. Y erbt von X. in X wird die Methode A definiert und in Y redefiniert. Die Methode A wird im Konstruktor von X aufgerufen. Instanziert man nun ein Objekt vom Typ Y wird die Methode A von X aufgerufen und nicht A von Y obwohl man eigentlich ein Objekt von Y angelegt hat.
Code: Alles auswählen.
REPORT.
CLASS lcl_x DEFINITION .
PUBLIC SECTION.
METHODS: constructor,
test.
ENDCLASS.
CLASS lcl_y DEFINITION INHERITING FROM lcl_x.
PUBLIC SECTION.
METHODS:
test REDEFINITION.
ENDCLASS.
CLASS lcl_x IMPLEMENTATION.
METHOD constructor. test( ). ENDMETHOD.
METHOD test. WRITE:/'X'. ENDMETHOD.
ENDCLASS.
CLASS lcl_y IMPLEMENTATION.
METHOD test. WRITE:/ 'Y' COLOR 3. ENDMETHOD.
ENDCLASS.
END-OF-SELECTION.
NEW lcl_x( )->test( ). ULINE.
NEW lcl_y( )->test( ).
Dann musst du aber unbedingt dafür sorgen, dass alle Aufrufer, die deine Klassen verwenden wollen, verpflichtend die INITIALIZE-Methoden aufrufen bevor sie wirklich loslegen können. Und genau dafür sind dann doch Factory-Methoden gedacht, die genau das machen bzw. die bei privater Instanzerzeugung halt dafür sorgen, dass der Aufrufer sie verwenden muss und nicht einfach so den Konstruktor verwenden.a-dead-trousers hat geschrieben:Daher bin ich mittlerweile dazu übergegangen kaum noch Sachen im Konstruktor zu programmieren, sondern eigene INITIALIZE-Methoden dafür zu verwenden.
Ich wollte das einfach nur mal zitieren, um den wichtigsten Satz aus dem Posting mal prominent herauszustellen. Ich halte es für ein triftige Argumentation gegen wahllose (ungesteuerte, öffentliche) Instanziierung.black_adept hat geschrieben:genau dafür sind dann doch Factory-Methoden gedacht, die genau das machen bzw. die bei privater Instanzerzeugung halt dafür sorgen, dass der Aufrufer sie verwenden muss und nicht einfach so den Konstruktor verwenden.
Das eine schließt das andere nicht aus. Der Aufrufer kann ja trotzdem "gezwungen" werden die Factory, Factorymethod oder Createmethod (Blick auf Ralf's Cheatsheet) zu verwenden. Intern läuft dann aber alles über die INITIALIZE-Methode(n) der/des beteiligten Objekte(s). Das mach ich meist dann, wenn meine Kollegen meine Klassen verwenden sollen, ihnen die Erzeugung oder bestimmte Abläufe in der Verwendung zu "kompliziert" sind. Damit entstehen in Abstimmung mit den Kollegen halt wieder Aufruferklassen und -methoden mit überdurchschnittlich vielen Parametern aber wenigstens werden darin meine "schönen und schlanken" Methoden/Klassen verwendet.black_adept hat geschrieben:Dann musst du aber unbedingt dafür sorgen, dass alle Aufrufer, die deine Klassen verwenden wollen, verpflichtend die INITIALIZE-Methoden aufrufen bevor sie wirklich loslegen können. Und genau dafür sind dann doch Factory-Methoden gedacht, die genau das machen bzw. die bei privater Instanzerzeugung halt dafür sorgen, dass der Aufrufer sie verwenden muss und nicht einfach so den Konstruktor verwenden.a-dead-trousers hat geschrieben:Daher bin ich mittlerweile dazu übergegangen kaum noch Sachen im Konstruktor zu programmieren, sondern eigene INITIALIZE-Methoden dafür zu verwenden.
Moin a-d-t,a-dead-trousers hat geschrieben:Etwas Offtopic, aber weil ich mich gerade glaube wieder zu erinnern:
War hier im Forum nicht mal das Thema das statische Methoden im Kernel speziell behandelt werden und somit "länger" im Speicher geladen bleiben (Stichwort: Garbage Collector) auch wenn von der Klasse sonst nichts mehr benötigt wird? Ralf, hast du das nicht mal eingebracht?
Ich frage desshalb, weil ich das bei uns in der Firma schon länger als Argument vorbringe keine statischen Methoden zu verwenden. Auch als Factory, Create oder Class Constructor versuche ich sie daher so gut es geht zu vermeiden.
Folgende Benutzer bedankten sich beim Autor ralf.wenzel für den Beitrag:
a-dead-trousers
Ok, danke. Ich persönlich nutze den Constructor im wesentlichen auch "nur" für Constructor-Injection.a-dead-trousers hat geschrieben:Natürlich kannst du mit SUPER-> auf die ursprügliche Implementierung einer redefinierten Methode zugreifen AUßER im Konstruktor.erp-bt hat geschrieben:Hmm, ich habe das zwar noch nie benötigt, aber kannst Du die Methode der übergeordneten Klasse nicht einfach mit "SUPER->" aufrufen?
Generierst Du Dir durch eine separate INITIALIZE-Methode nicht eine Abhängigkeit zur rufenden Klasse oder rufst Du die im Constructor? Würde mich mal interessieren.
Gegeben seinen zwei Klassen X und Y. Y erbt von X. in X wird die Methode A definiert und in Y redefiniert. Die Methode A wird im Konstruktor von X aufgerufen. Instanziert man nun ein Objekt vom Typ Y wird die Methode A von X aufgerufen und nicht A von Y obwohl man eigentlich ein Objekt von Y angelegt hat.
Daher bin ich mittlerweile dazu übergegangen kaum noch Sachen im Konstruktor zu programmieren, sondern eigene INITIALIZE-Methoden dafür zu verwenden. Auch, dass man im Konstruktor nicht sofort auf Attribute der Klasse verweisen kann, solange man den SUPER->CONSTRUCTOR nicht aufgerufen hat, kann zu einem Problem führen. Vorallem dann wenn man anfängt auch Zustände in Klassen abzubilden, weil man dann oft mit den Reihenfolgen der Konstruktoren durcheinander kommt. Mit einer eigenen INITIALIZE-Methode kann man von außen dezidiert sagen, "jetzt ist alles notwendige vorhanden, leg los". Außerdem versuche ich die Methodenschnittstellen so schmal wie möglich zu halten. Nichts verwirrt IMHO mehr als wenn eine Methode "dutzende" Eingabeparametern aufweist und man dann noch auf Abhängigkeiten zwischen den Parametern aufpassen muss. Bestes Beispiel ist hier die Angabe von Datum UND Uhrzeit wenn man eigentlich einen Zeitpunkt übergeben möchte. Oft werden dann auch mehrere Datum (mehrzahl von Datum) und Uhrzeiten übergeben, einmal für Gültigkeiten und dann für den eigentlichen Datensatz.
lg ADT
Mal abgesehen vo völlig unnützen Fullquote (hast du eine Ahnung, wie aufwendig das Löschen auf einem Smartphone ist?) gebe ich dir weitestgehend recht. Das mit dem Abhängigkeitsproblem stimmt freilich nicht, weil ich ein Interface oder eine Struktur nachträglich ändern kann. Die Methode juckt es nicht, wie viele Felder die Struktur oder wie viele Komponenten ein IF hat.erp-bt hat geschrieben:Lange Methodensignaturen sind ja ein bekanntes Code-Smell (gibt's da eigentlich eine sinnvolle deutsche Übersetzung für?). Ich nutze ganz gerne Parameter-Objekte (oder Strukturen), obwohl das natürlich nicht das Abhängigkeitsproblem zwischen den Parametern löst. Unter Umständen ist es auch schwieriger nachzuvollziehen, was eine Methode eigentlich macht, war für mich aber bisher kein Problem.
Dann zeig uns doch mal die Wahrheit.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 sind drei Punkte </goldwaage>ralf.wenzel hat geschrieben: Der Punkt aber ist:
Beispiel? Gerade wenn im Falle des Timestamps nur DATUM und UHRZEIT notwendig sind, dann sind sie auch so in der Methode zusammengefasst.ralf.wenzel hat geschrieben:• Ich fasse die Daten zusammen, die zusammengehören
Selbst wenn: Irgendwo hast du immer Anpassungen. Selbst wenn sich die Schnittstelle nicht ändert: Der Timestamp ändert sich ja und dementsprechend muss der Verwender eh angepasst werden.ralf.wenzel hat geschrieben:• Bei mir ändert sich die Methodenschnittstelle nicht, wenn die Definition des Timestamps sich ändert
Hast du mit jeder einfachen GET_TIMESTAMP-Methode auch.ralf.wenzel hat geschrieben:• Ich habe einen Verwendungsnachweis auf die Timestamp-Verwendungen
Code: Alles auswählen.
p_ts = NEW my_timestamp( )->date( p_date )->time( p_time )->get( ).
Code: Alles auswählen.
PARAMETERS p_date TYPE d.
PARAMETERS p_time TYPE t.
PARAMETERS p_ts TYPE timestamp MODIF ID dis.
CLASS my_timestamp DEFINITION.
PUBLIC SECTION.
METHODS date IMPORTING date TYPE d RETURNING VALUE(obj) TYPE REF TO my_timestamp.
METHODS time IMPORTING time TYPE t RETURNING VALUE(obj) TYPE REF TO my_timestamp.
METHODS get RETURNING VALUE(ts) TYPE timestamp.
PRIVATE SECTION.
DATA mv_date TYPE d.
DATA mv_time TYPE t.
ENDCLASS.
CLASS my_timestamp IMPLEMENTATION.
METHOD date.
mv_date = date.
obj = me.
ENDMETHOD.
METHOD time.
mv_time = time.
obj = me.
ENDMETHOD.
METHOD get.
IF mv_date IS INITIAL.
mv_date = sy-datum.
ENDIF.
IF mv_time IS INITIAL.
mv_time = sy-uzeit.
ENDIF.
ts = |{ mv_date }{ mv_time }|.
ENDMETHOD.
ENDCLASS.
AT SELECTION-SCREEN.
p_ts = NEW my_timestamp( )->date( p_date )->time( p_time )->get( ).
AT SELECTION-SCREEN OUTPUT.
LOOP AT SCREEN.
IF screen-group1 = 'DIS'.
screen-input = '0'.
MODIFY SCREEN.
ENDIF.
ENDLOOP.