Ankündigung

Einklappen
Keine Ankündigung bisher.

OOP Umsetzung

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • cycap
    hat ein Thema erstellt OOP Umsetzung.

    OOP Umsetzung

    Hi Leute,

    ich habe jetzt mal nen Fall wo mir OOP sicher sehr nützlich sein kann, nur es hapert etwas an der Umsetzung, nicht von der Syntax her sondern von der Logik.

    Folgende situation:

    Code:
    - Klasse Buchungen
    - Klasse Arbeitszeiten (bzw. Abwesenheitszeiten)
    - Klasse Spesen
    Das ganze ist im Prinzip eine n:1:n Beziehung, in der o.g. Reihenfolge. Es geht im Prinzip um die Datenbank, kommt also jemand daher und bucht eine neue Tätigkeit, so muss der Mutterdatensatz erstellt, bzw geupdatet werden.

    Es muss also untereinander kommuniziert werden und das unter allen 3en. Wie setzte ich das am schlausten um? Oder denke ich in eine falsche Richtung?

    Gruß
    Cy

  • dr.e.
    antwortet
    Hallo cycap,

    bist du schon weiter gekommen, kann man noch irgendwo helfen?

    Einen Kommentar schreiben:


  • dr.e.
    antwortet
    Hallo cycap,

    das sieht doch mal nicht schlecht aus. Das ist zwar ein Tabellen-Layout, ich denke jedoch, dass du damit auch deine Domänen Objekte meinst. Damit wäre dann auch festgelegt, wie dein Mapper und deine Business-Schicht arbeiten muss.

    Ich würde nun an deiner Stelle damit beginnen, die Klassen (=Tabellen) zu erstellen. Anschließend solltest du vertikal vorgehen, sprich eine Funktion nach der anderen erstellen. Dabei erweiterst du deinen Mapper und deinen Manager so, dass die Funktion abgebildet werden kann. Wichtig ist dabei, dass die Mapper- und Manager-Methoden so generisch wie möglich gehalten werden. Würdest du meinen (leider noch nicht mit stable gekennzeichneten) GenericORRelationMapper einsetzen würdest, könntest du dir die Datenschicht komplett sparen. In diesem Fall musst du das Mapping diskret implementieren. Hier würde ich im Mapper pro Objekt jeweils eine private Methode für das Laden und Speichern erstellen, dann hast du schon mal den größten Teil erschlagen. Als Beispiel kannst du dir nochmal den Quellcode meines Gästebuch-Tutorials unter Adventure PHP Framework - Gaestebuch Tutorial 2 anschaun. Bei Fragen einfach melden. Wenn du Lust hast, können wir das auch hier weiterdiskutieren und deinen Quellcode zusammen analysieren/optimieren.

    Einen Kommentar schreiben:


  • cycap
    antwortet
    Hi,

    erstmal danke das du dir soviel Mühe gibts. Das weiss ich echt zu schätzen.

    Das mit dem Attribut gedachte ich einfach so umzusetzen, das bei id_workblock ne NULL (oder 0) steht, dann ist ja klar das die Buchung noch keinem Workblock zugewiesen wurde.

    Vielleicht kannst du hiermit mehr anfangen:

    Einen Kommentar schreiben:


  • dr.e.
    antwortet
    Hallo cycap,

    hab mir die Grafiken man angesehen. Der Workflow ist nachvollziehbar, beim Klassendiagramm hab ich so meine Schwierigkeiten. Fangen wir beim ersten an:

    1. Workflow:
    Die aus meiner Sicht notwendigen Daten sind hier
    - Benutzerdaten
    - Buchungen des Benutzers
    - Workblock des Benutzers

    2. Klassendiagramm:
    Auf Basis der bisherigen Informationen ergibt sich aus meiner Sicht folgendes Klassendiagramm:



    Ausgesprochen bedeutet das, dass ein Benutzer mehrere Buchungen und Workblocks komponiert (Komposition deshalb, da eine Buchung nicht ohne einen Benutzer existieren kann). Ein Workblock setzt sich dabei aus mehreren Buchungen zusammen, oder wird von diesen bestimmt. Wie genau, könnte man noch mit einem Beziehungsobjekt zwischen "Transaction" und "Workblock" näher definieren.

    Alle offenen Transaktionen sollte man noch zu einem Objekt "Offene Transaktion" assoziieren, damit man feststellen kann, welche Transaktionen noch offen sind. Auch könnte man einer Transaktion ein Attribut mitgeben, das dieses indiziert.

    Innerhalb deiner Anwendung kannst du nun alle offenen Transaktionen auslesen, diese einem Workblock zuordnen und das Konstrukt entsprechend Speichern. Genauer bin ich allerdings noch nicht durchgestiegen, was ein Workblock darstellt, vielleicht kannst du das nochmal genauer definieren und das Diagramm vervollständigen.

    Hope that helps you?!

    Einen Kommentar schreiben:


  • cycap
    antwortet
    Hallo dr.e.,

    ja stimmt, der rote Faden ist hier natürlich nicht zu erkennen, da das Prüfen der Buchung natürlich nur der erste Schritt ist, ich versuche mal meine Gedanken vom Papier in Visio nachzustellen.

    Am besten erkennt man mein Vorhaben wahrscheinlich am Programmablaufplan und ein Klassendiagramm hab ich auch versucht zu machen.

    Einen Kommentar schreiben:


  • dr.e.
    antwortet
    Hallo cycap,

    wie darf ich die Klasse verstehen? Hast du ein komplettes Klassen-Mode bereits auf Papier? Irgendwie kann ich den roten Faden noch nicht erkennen. Ich würde die Klasse als Domain-Objekt bezeichnen, die jedoch zu viel Logik enthält.

    Zur Klasse selbst:
    - [s|g]etErrMsg() hat nichts in einem Domain-Objekt zu suchen, diese Logik gehört eindeutig in die Business-Schicht. In deinem Fall würde die Präsentationsschicht das Objekt soweit füllen, wie sie kann, sprich mit den Eingabewerten des Benutzers und würde es der Business-Schicht übergeben. Stellt diese fest, dass dort ein Fehler passiert ist, muss sie einen entsprechenden View anzeigen, der die Fehlermeldung präsentiert. Sollte der Fehler "heilbar" sein, so kann das die Business-Logil in der Business-Schicht tun und das Objekt anschließend an die Datenschicht (Mapper) zur Speicherung weitergeben.
    - Sollte die Information des Domain-Objekts dazu dienen (das ist nun die Betrachtung in die andere Richtung), dann darf diese Information auch nicht in das Domain-Objekt, sondern muss ins Model der Anwendung. Das Model wiederum beeinflusst dann die Darstellung der Anwendung und es kann ein Fehler ausgegeben werden.

    Ich bin mal auf weitere Klassen gespannt. Was helfen würde: poste mal dein komplettes Klassendiagramm. Es gibt wo viele Tools (Visio, Enterprise Architect, ...), die das digital können...

    Einen Kommentar schreiben:


  • cycap
    antwortet
    Ich hab jetzt mal angefangen eine Klasse für die Buchungen geschrieben (und mich in Englisch versucht ), die könnt ihr euch ja mal anschauen und mir konstuktive Kritik geben:

    PHP-Code:
    class newposting
    {
      private 
    $time,$user,$cun,$job,$source,$charges,$type,$errmsg=array(),$error=false;

      function 
    __construct($user,$cun,$job,$type,$source)
      {
        
    // first part: check inputs
        
    $this->time time();
        
    $this->user = (int)$user;
        
    $this->cun = (int)$cun;
        
    $this->job = (int)$job;
        
    $this->source $this->checkSource($source);
        
    $this->charges $this->getChargesFromSource();
        
    $this->type $this->checkType($type);
        if(!
    $this->error// only jump to next method if there is no error
        
    {
          
    // jump to next step (check user,cun,job with database)
        
    }
      }
      
      private function 
    checkSource($source)
      {
        
    // only add from allowed sources
        
    $allowed = array("pda","spesen","portal");
        
        if(
    in_array($source,$allowed))
          return 
    $source;
        else
        {
          
    $this->setErrMsg("This source is not allowed");
          return 
    false;
        }
      }
      
      private function 
    checkType($type)
      {
        
    // only add with allowed types
        
    $allowed = array("work","pause","end","night");
        
        if(
    in_array($type,$allowed))
          return 
    $type;
        else
        {
          
    $this->setErrMsg("This type is not allowed");
          return 
    false;
        }
      }
      
      private function 
    getChargesFromSource()
      {
        
    // Posting is only able for charges if it is from one of these sources
        
    if($this->source == 'pda' || $this->source == 'spesen')
          return 
    true;
        else
          return 
    false;
      }

      private function 
    setErrMsg($msg)
      {
        
    $this->error true;
        
    $this->errmsg[] = $msg;
      }

      function 
    getErrMsg($html=true)
      {
        if(
    $html)
        {
          return 
    implode('<br>',$this->errmsg);
        }
        else
        {
          return 
    implode("\r\n",$this->errmsg);
        }
      }


    Einen Kommentar schreiben:


  • cycap
    antwortet
    Ok, ich glaube ich bin jetzt einen ganzen Schritt weiter. Ich habe mir nen DINA3 Blatt genommen und nen bisschen gezeichnet.

    Dabei ist mir klar geworden das ich für die Spesendatensätze so keine vernünftige Beziehung aufbauen kann, wie ich bisher versucht habe. Das Problem dabei war die 0-Uhr grenze, die zwar bei der Abrechnung gebraucht wird, aber ja in den Daten gar nicht vorhanden ist.

    Was also machen? Die Referenz des Spesendatensatzes auf die Buchungen machen (nicht auf die Workblocks) und die Spesen wirklich solange laufen lassen bis eine "echte" Arbeitsende-Buchung (keine Übernachtung) kommt.

    Die 0-Uhr grenze soll dann nicht mehr in der Datenbank sondern im Programm abgefangen werden. Also eine Schleife die jeden Tag des Spesensatzes durchgeht und immer wenn ein neuer Tag beginnt auch eine neue Zeile in der Auswertung mit 00:00 beginnen.

    Hmm und jetzt versuch ich erstmal weiter nachzudenken.

    Einen Kommentar schreiben:


  • dr.e.
    antwortet
    Hallo cycap,

    dabei sind mir einige Rechtschreibfehler aufgefallen, die kannste ja mal wegmachen :
    Danke, werde ich im 1.6er final Release ausbessern.

    und wo hängt es jetzt bei mir? bei punkt 3?
    Ich nehme an, du meinst das Kapitel "Anwendungsfälle"? Die im Tutorial aufgezeigte Vorgehensweise ist state of the art. Damit gehst du sicher, dass die Anforderungen sauber definiert sind und später keine Diskussionen entstehen. Anschließend definierst du die technischen Aspekte der Software, sprich Domänenmodell (Kapitel 4), Struktur der Applikation (Kapitel 4, zweiter Abschnitt) und die Datenstruktur (Kapitel 5).

    Das mit dem Mapper hört sich interessant an, da such ich mir mal noch Infos zu.
    Ist es auch. Der Mapper im Tutorial ist jedoch konkret für die Applikation implementiert. Aktuell fahre ich jedoch einen anderen Ansatz, in dem ich auch einen Mapper soweit abstrahiere, dass dieser für jede Applikation eingesetzt werden kann. Das Mapper-Thema hat von unten betrachtet den Vorteil, dass die Anwendung an sich komplett objektorientiert implementiert werden kann. Setzt du keinen Mapper ein, musst du dich in der Applikation mit SQL und Datenbankspezifika rumschlagen. Das hat dann den Nachteil, dass deine Applikation nicht portierbar ist.

    Einen Kommentar schreiben:


  • cycap
    antwortet
    Ok, lese gerade dein Tutorial und

    [OT]
    dabei sind mir einige Rechtschreibfehler aufgefallen, die kannste ja mal wegmachen :
    Unter 2: Schnittstellt
    Unter 3: Prgrammiersprachen
    [/OT]

    und wo hängt es jetzt bei mir? bei punkt 3? und soll ich gleich die komplette Anwendung so machen, also auch das beantragen/genehmigen von Korrekturen? weil das ist ja noch ne ganze ecke komplizierter und ich würde das erst im nächsten Schritt einbauen.

    Das mit dem Mapper hört sich interessant an, da such ich mir mal noch Infos zu.

    Einen Kommentar schreiben:


  • dr.e.
    antwortet
    Zitat von nikosch77-new Beitrag anzeigen
    Möglicherweise wäre hier eine stored procedure oder eine Datenbanksicht besser geeignet, die die Daten bei Bedarf on-the-fly zusammenbaut.
    Ich würde das eher über einen Datamapper lösen, der das Domain-Model der Anwendung kennt und zwischen dem Modell der Datenhaltung und dem Modell der Anwendung übersetzt. So behält man sich die Flexibilität vor eine andere Anwendung auf exakt den selben Daten arbeiten lassen zu können.

    Ich weiß, das geht schon sehr stark in das Thema Master-Data-Management, es ist jedoch ein sehr probates Mittel um eine saubere Abschottung plus Erhaltung der Datenhaltungs- und Anwendungsdatenmodellierung zu erhalten.

    Einen Kommentar schreiben:


  • dr.e.
    antwortet
    Zitat von cycap Beitrag anzeigen
    Naja es ist halt das erste Problem was ich wirklich in OOP umzusetzen versuche. Zu deinem ersten Absatz: Naja ich dachte halt jede Tabelle ist eine Klasse, dann instanziere ich $buchungen = new buchungen(); und sage $buchungen->add(...); was dann je nach Buchung eine Methode der Elternklasse aufruft und so weiter...
    Dieser Ansatz ist eine Möglichkeit der Umsetzung der Datenschicht, hat jedoch zunächst mit der Umsetzung / mit dem Design der Applikation nichts zu tun. Im OOP/OOD-Ansatz überlegt man sich zuerst die Daten, die in der Applikation behandelt werden. Diese können sich direkt aus Daten in der Datenbank der Anwendung oder aus weiteren kumulierten Daten zusammen setzen. Wenn du genau weißt, welche (natürlichen!) Objekte deine Anwendung hat, ist es an der Zeit, sich über die Datenschicht der Applikation gedanken zu machen.

    Ein Konstrukt wie

    $buchungen->add(...);
    ist dabei eine Möglichkeit der Umsetzung des Table-Data-Gateway-Patterns, man kann jedoch auch mit einem dedizierten Mapper arbeiten, dem man das Buchungsobjekt übergibt. Z.B. so:

    PHP-Code:
    $Mapper = new Mapper();
    $Buchungen = new Buchungen();
    ...
    $Mapper->save($Buchungen); 
    Zitat von cycap Beitrag anzeigen
    Bei deinem zweiten Absatz versteh ich nur Bahnhof vielleicht doch zu den Anfängern zurück schieben?
    Mein zweiter Ansatz ist eigentlich nur eine Implementierung für einen generischen OR-Mapper, der auch Relationen abbilden kann. Das Feature gibt es in Tools wie Propel oder den OR-Mapper-Schichten von CakePHP, CodeIgniter & Co. nicht.

    Grundsätzlich ist es jedoch wichtig, dass du die Anforderungen an deine Applikation und das Datenmodell derselben vorher definierst. Hierzu bietet sich UML an. Anschließend arbeitest du dich dann zur konkreten Implementierung vor. Ein IMHO gutes Beispiel ist das Gästebuch-Tutorial auf Adventure PHP Framework - Gaestebuch Tutorial.

    Einen Kommentar schreiben:


  • nikosch
    antwortet
    Möglicherweise wäre hier eine stored procedure oder eine Datenbanksicht besser geeignet, die die Daten bei Bedarf on-the-fly zusammenbaut.

    Einen Kommentar schreiben:


  • cycap
    antwortet
    Zitat von nikosch77-new Beitrag anzeigen
    Sorry, wenn ich hier mal meinen unqualifizierten Kommentar abgebe (Hoffe ich habe nichts überlesen): Von was für einer Art Anwendung reden wir hier eigentlich - von einer Art Verwaltung der unter der geposteten Datenbank-Struktur hinterlegten Daten? Oder von einer Art check-in/check-out Anwendung, mittels der EIN Nutzer seine persönlichen Vorgänge bucht?
    In letzterem Fall beschränkt sich die Kiste doch einzig auf die Klasse 'Buchung', die ID, Land, aktuelle Kostenstelle etc. vorhält.

    Die als 'Workblocks' und 'Awayblocks' beschriebenen Strukturen finde ich total unglücklich. Die würde ich allenfalls temporär für die Buchhaltung oder so erstellen.
    Den zweiten Fall.

    Das workblocks und awayblocks verfahren ist eigentlich auch überflüssig, sind ja nur Zusammenfassungen. Allerdings brauche ich die für Stunden- / Spesenzettel (PDF), die sich die Mitarbeiter jederzeit angucken können. Die workblocks werden außerdem noch von der Programmierung meines Kollegen ausgelesen und weiterverarbeitet.

    Schlag ein besseres verfahren vor, ich bin gern bereit alles umzubauen.

    Einen Kommentar schreiben:

Lädt...
X