Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

3 lagen architectuur en "controller" klassen.

Pagina: 1
Acties:

  • MasterTweaker
  • Registratie: Maart 2010
  • Laatst online: 16-11 21:46
Ik ben bezig met een projectje waarbij ik een systeem ontwerp voor een online bibliotheek. Ik maak nu gebruik van een drie lagen architectuur:
- Presentatielaag.
- Logicalaag
- Datalaag (Deze laag spreekt de database aan ).

Maar nu heb ik o.a. de volgende "Use Case" die het systeem moet uitvoeren: "Het aanmaken van een klant".

Ik gebruik hiervoor twee klassen:
- Klant ( Deze klasse bevindt zich in de logicalaag).
- Klantencontroller ( Deze klasse bevindt zich in de datalaag en moet de data naar de goede tabel in de database schrijven).

Maar nu vraag ik mij af welke operaties er dan logischerwijs in de klant klasse zitten en welke operaties in de klantencontroller klasse.
In de klant klasse bijvoorbeeld: "new" en "validate"? En in de klantencontroller klasse: "WriteKlant" en "GetKlant".

Of is er in het geval van deze "Use Case" eigenlijk helemaal geen nut om de scheiding tussen Klant en Klantencontroller aan te brengen?
Kan iemand misschien wat duidelijkheid verschaffen over hoe ik dit zou moeten implementeren?

  • GewoonWatSpulle
  • Registratie: Oktober 2009
  • Laatst online: 24-11 17:27
Volgens mij hoort het zo te zijn dat je zowel Klant als KlantController in je logic-layer hebt, en op je datalaag een KlantDataObject.

Klant = variabelen lezen voor het scherm (username opvragen)
KlantController = variabelen schrijven via functies en functies uitvoeren, (wachtwoord veranderen)
KlantDataObject = simpel weg memory wegschrijven en lezen. (Create, Read, Update, Delete + Collecties)

Kijk anders even naar Wikipedia: Multitier architecture

[ Voor 17% gewijzigd door GewoonWatSpulle op 11-04-2012 15:53 ]


  • MasterTweaker
  • Registratie: Maart 2010
  • Laatst online: 16-11 21:46
GewoonWatSpulle schreef op woensdag 11 april 2012 @ 15:49:
Volgens mij hoort het zo te zijn dat je zowel Klant als KlantController in je logic-layer hebt, en op je datalaag een KlantDataObject.

Klant = variabelen lezen voor het scherm (username opvragen)
KlantController = variabelen schrijven via functies en functies uitvoeren, (wachtwoord veranderen)
KlantDataObject = simpel weg memory wegschrijven en lezen. (Create, Read, Update, Delete + Collecties)

Kijk anders even naar Wikipedia: Multitier architecture
Oke dus dan worden de operaties per klasse ongeveer als volgt:
Klant: GetName, SetName, GetAdress, SetAdress, GetAge, SetAge.
Klantencontroller: New, Validate.
KlantendataObject: Write, Read, Update, Delete.

Maar dit kan dan toch ook met twee klassen neem ik aan? Jouw Klant en Klantencontroller worden dan mijn Klant. En jouw KlantendataObject wordt dan mijn Klantencontroller.

Ik zie het nut namelijk niet helemaal in van het verdelen van de functionaliteiten in drie lagen. Die eerste twee klasssen van jou zouden best samengevoegd kunnen worden lijkt mij.

  • GewoonWatSpulle
  • Registratie: Oktober 2009
  • Laatst online: 24-11 17:27
Even een snel voorbeeldje:

PL: Klant.FullName = JohnDoe
LL: (property)FullName return (First+Last);
DL: Save: Klant.First, Klant.Middle, Klant.Last

Nu kom je tot de conclusie dat overal in je front-end je voornaam/achternaam aan elkaar geplakt zijn zonder tussenvoegsels, in de logic-layer pas nu het nu aan naar (property)FullName return First + (Middle?" " + Middle) + " " + Last

En je resultaat is overal in je front-end (presentation layer) "John the Doe" wat je werkelijk op slaat is nog steeds enkel Klant.First, Klant.Middle, Klant.Last.

[ Voor 4% gewijzigd door GewoonWatSpulle op 11-04-2012 16:08 . Reden: bold ter verduidelijking ]


  • Bee.nl
  • Registratie: November 2002
  • Niet online

Bee.nl

zoemt

Het gaat eigenlijk al fout bij naamgeving van je klassen. Klant hoort een Entity te zijn. Hierin zit je klantdata inclusief de business-specifieke logica voor een klantentity. Het heeft verder geen weet van de database. Er kan validatielogica inzitten om de state te controleren. Contextspecifieke validatie waarbij je bijv meerdere entities nodig hebt, hoort hier niet thuis (maar bijv in de repository). Dus het kan goed zijn dat er op 2 niveaus validatie plaatsvindt.

Dan heb je een KlantRepository nodig die de CRUD-operaties verzorgt. De repository zal bij een CRUD-aanroep de bijbehorende KlantDAO raadplegen. Deze DAO zal de daadwerkelijke database-operaties uitvoeren. Vervolgens kun je ervoor kiezen om een DTO-object tussen de DAO en repository te doen, maar dat hangt van de applicatie af.

Een andere benadering is het ActiveRecord pattern. Relatief simpel om op te zetten, maar daarmee maak je geen onderscheid in verantwoordelijkheden.
MasterTweaker schreef op woensdag 11 april 2012 @ 16:00:
[...]

Oke dus dan worden de operaties per klasse ongeveer als volgt:
Klant: GetName, SetName, GetAdress, SetAdress, GetAge, SetAge.
Klantencontroller: New, Validate.
KlantendataObject: Write, Read, Update, Delete.
Ik zou afstappen van de 'controller'-naamgeving. Noem het liever repository of service. Zeker wanneer je het MVC-pattern wilt aanhouden is controller in de naam zeer verwarrend. Het is overigens create, en niet 'new' of 'write' ;)
Maar dit kan dan toch ook met twee klassen neem ik aan? Jouw Klant en Klantencontroller worden dan mijn Klant. En jouw KlantendataObject wordt dan mijn Klantencontroller.

Ik zie het nut namelijk niet helemaal in van het verdelen van de functionaliteiten in drie lagen. Die eerste twee klasssen van jou zouden best samengevoegd kunnen worden lijkt mij.
Het scheiden van verantwoordelijkheden is juist om spaghetti-code te voorkomen en overzicht in je code te houden. Een entity weet niets van de database of van de repository. De repository is een centraal aanspreekpunt en doorgeefluik. Het heeft verder geen flauw benul van de manier waarop de data wordt opgeslagen. De DAO heeft geen weet van de business-logica en spreekt weer alleen de database aan.
Stel dat je ooit van database verandert of dat de business-logica wijzigt, dan hoef je maar één laag aan te passen.

  • MasterTweaker
  • Registratie: Maart 2010
  • Laatst online: 16-11 21:46
Bee.nl schreef op woensdag 11 april 2012 @ 16:48:
Het gaat eigenlijk al fout bij naamgeving van je klassen. Klant hoort een Entity te zijn. Hierin zit je klantdata inclusief de business-specifieke logica voor een klantentity. Het heeft verder geen weet van de database. Er kan validatielogica inzitten om de state te controleren. Contextspecifieke validatie waarbij je bijv meerdere entities nodig hebt, hoort hier niet thuis (maar bijv in de repository). Dus het kan goed zijn dat er op 2 niveaus validatie plaatsvindt.

Dan heb je een KlantRepository nodig die de CRUD-operaties verzorgt. De repository zal bij een CRUD-aanroep de bijbehorende KlantDAO raadplegen. Deze DAO zal de daadwerkelijke database-operaties uitvoeren. Vervolgens kun je ervoor kiezen om een DTO-object tussen de DAO en repository te doen, maar dat hangt van de applicatie af.

Een andere benadering is het ActiveRecord pattern. Relatief simpel om op te zetten, maar daarmee maak je geen onderscheid in verantwoordelijkheden.


[...]

Ik zou afstappen van de 'controller'-naamgeving. Noem het liever repository of service. Zeker wanneer je het MVC-pattern wilt aanhouden is controller in de naam zeer verwarrend. Het is overigens create, en niet 'new' of 'write' ;)

[...]

Het scheiden van verantwoordelijkheden is juist om spaghetti-code te voorkomen en overzicht in je code te houden. Een entity weet niets van de database of van de repository. De repository is een centraal aanspreekpunt en doorgeefluik. Het heeft verder geen flauw benul van de manier waarop de data wordt opgeslagen. De DAO heeft geen weet van de business-logica en spreekt weer alleen de database aan.
Stel dat je ooit van database verandert of dat de business-logica wijzigt, dan hoef je maar één laag aan te passen.
Bedankt voor de informatie. Ik heb het nu als volgt toegepast:

http://i44.tinypic.com/23svhq8.jpg

Is dit een juiste klassenstructuur? En hoe gedetailleerd geef je de klassen eigenlijk weer in zo'n 3 lagen "view". Geef je dan ook de individuele attributen en operaties weer in de klassen of doe je dat in een apart klassendiagram?

  • Big Womly
  • Registratie: Oktober 2007
  • Laatst online: 01-09 13:39

Big Womly

Live forever, or die trying

MasterTweaker schreef op woensdag 11 april 2012 @ 16:00:
[...]
Klant: GetName, SetName, GetAdress, SetAdress, GetAge, SetAge.
Even tussendoor: de leeftijd veranderd jaarlijks. Het is beter om de geboortedatum bij te houden en via getAge de leeftijd op te vragen.
dus dan heb je: getDateOfBirth, setDOB en getAge.

When you talk to God it's called prayer, but when God talks to you it's called schizophrenia


  • Bee.nl
  • Registratie: November 2002
  • Niet online

Bee.nl

zoemt

MasterTweaker schreef op donderdag 12 april 2012 @ 10:21:
Bedankt voor de informatie. Ik heb het nu als volgt toegepast:

http://i44.tinypic.com/23svhq8.jpg

Is dit een juiste klassenstructuur? En hoe gedetailleerd geef je de klassen eigenlijk weer in zo'n 3 lagen "view". Geef je dan ook de individuele attributen en operaties weer in de klassen of doe je dat in een apart klassendiagram?
Dat ziet er al beter uit. Of je methodes en members in een dergelijk overzicht moet zetten hangt van de opdrachteisen af, maar de methodes zet je er vrijwel altijd bij. De naamgeving 'controller' blijft een beetje apart. Je moet het klant-repository-dao verhaaltje meer zien als het M(odel) gedeelte. Stel dat je het veelgebruikte MVC-paradigma neemt in combinatie met het repository pattern, dan kom je al snel in de knoop met je naamgeving. Zie dit voorbeeld in PHP:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class KlantController 
{
   public function infoAction()
   {
      $repository = new KlantRepository();
      $klant = $repository->getById($id); 
      // onder water vraagt de repository de klantdata op aan de juiste DAO
      // en de repository propt die data weer in de juiste entity en geeft het terug

      if (!$klant) {
         // klant bestaat niet, laat foutmelding zien
      }

      $view->klant = $klant; // geef klant door naar view
   }

   public function newAction()
   {
      $klant = new Klant();
      $klant->setName($name);
      // code..
      $saved = $repository->save($klant);
      // omgekeerde: repository ontrekt data uit klant en
      // geeft deze data aan de DAO voor een insert/update
   }
}

Je hoeft de naamgeving niet over te nemen -dat is je eigen keus-, maar het helpt je wellicht om de patterns en verantwoordelijkheden beter te doorgronden.
Big Womly schreef op donderdag 12 april 2012 @ 10:27:
Even tussendoor: de leeftijd veranderd jaarlijks. Het is beter om de geboortedatum bij te houden en via getAge de leeftijd op te vragen.
dus dan heb je: getDateOfBirth, setDOB en getAge.
Scherp :)
GetAge() is een goed voorbeeld van een methode die in de entity Klant thuishoort.

  • Teknix1982
  • Registratie: Januari 2005
  • Niet online
Eigenlijk is de controller laag bedoeld om een applicatie van de ene pagina naar de andere te sturen en daartussen een service aan te sturen met gegevens van de view om de acties uit te voeren. De models zijn het onderdeel waar de gegevens van en naar de view gaan en gemanipuleerd worden. Zo behaal je mijns inziens de hoogste herbruikbaarheid van code. Het fat model, thin/skinny controllers principe. Tenminste, dat hanteer ik wel het liefst.
Pagina: 1