Hello,

Je reviens une fois de plus sur un sujet qui me tiens à coeur de comprendre, les DTO et leur utilisation.

Je ne link plus les différents articles qui existe mais pour rappel, il y a les traductions de rvt26 des article de Rudy Lavocara (j'écorche sûrement son nom) ainsi qu'un article de skalp (cela devrait suffir pour que les curieux qui ne les auraient pas encore lu puisse les trouver).

Il s'agit de travailler sur un projet multi-couche organisé comme suit :
  • une couche DTO qui contient les objets de bases
  • une couche DAL qui communique avec la DB (qui fait référence la couche DTO)
  • une couche BLL qui communique avec la DAL au moyen de DTO (qui fait référence à DAL et DTO)
  • une couche GUI qui communique avec la BLL au moyen de DTO (qui fait référence à BLL et DTO)


Voilà pour l'architecture...

Mon souci se situe dans la couche BLL.

Dans un précédent projet, je structurais une classe de la couche BLL comme suit :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
 
Public Class BllClass
    Public Property DTO as DtoClass
 
    Public Sub New(dto as DtoClass)
        DTO = dto
    End Sub
 
    Public Shared Function GetFromDB(id as Integer) as BllClass
        Return New BllClass(DAL.DalClass.GetOne(id))
    End Function
 
    Public Sub Save()
        DAL.DalClass.Save(DTO)
    End Sub
End Class
Public Class BllClasses
    Public Property DTO as List(Of DtoClass)
 
    Public Sub New (dtos as List(Of DtoClass)
        DTO = dtos
    End Sub
 
    Public Shared Function GetFromDb(param as object) as BllClasses
        Return New BllClasses(DAL.DalClass.GetList(param))
    End Function
 
    Public Function GetOne(id as Integer) as BllClass
        Dim dto as DtoClass = (For d as DtoClass in Me.DTO
                                       Where d.Id = id
                                       Select d).FirstOrDefault
        Return New BllClass(dto)
    End Function
 
    Public Sub Save()
        For Each d as DtoClass in DTO
            DAL.DalClass.Save(d)
        End For
    End Sub
End Class
Avantage : Pas de duplication de code au niveau des propriétés des DTO. La couche GUI peut passer le DTO de l'objet BLL directement à un DataGridView par exemple.
Désavantage : 2 classes au lieu d'une. Une pour gérer un seul DTO et une pour gérer une liste.

J'ai brièvement réfléchi à comment éviter d'avoir cette duplication de classe et je suis arrivé à ceci :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
 
Public Class BllClass
    Public Property Id as Integer
    Public Property P1 as Integer
    Public Property P2 as String
 
    Public Sub New(id as Integer, p1 as Integer, p2 as String)
        Me.Id = id
        Me.P1 = p1
        Me.P2 = p2
    End Sub
 
    Public Shared Function GetOneFromDb(id as Integer) as BllClass
        Dim dto as DtoClass = DAL.DalClass.GetOne(id)
        Return New BllClass(dto.Id, dto.P1, dto.P2)
    End Function
 
    Public Shared Function GetListFromDb(param as Object) as List(Of BllClass)
        Dim result as New List(Of BllClass)
        Dim dtos as List(Of DtoClass) = DAL.DalClass.GetList(param)
        For Each d as DtoClass in dtos
            result.Add(New BllClass(d.Id, d.P1, d.P2)
        End For
        Return result
    End Function
End Class
N.B. : Il manque un test ou l'autre mais l'idée est là...

Avantage : Une seule classe au lieu de deux.
Désavantage : Plus de code à écrire (il faut reproduire les propriétés du DTO dans BLL)

Mais avec ces solutions en 1 seule class, j'ai l'impression de perdre la philosophie des DTO's dans le sens que la couche GUI n'a même plus besoin de référencer la couche DTO puisqu'elle ne travaillera qu'avec les objets de la couche BLL et n'aura même pas conscience des DTO's sous-jacents. Pour afficher une liste dans un DataGridView, elle donnera une liste de BllClass et non pas une liste DtoClass.

Etant donné que je débute encore avec tout cela, je me tourne vers vous pour savoir quelle solution il faut préférer car cela a probablement des implications auxquelles je ne pense pas. Et je suis malheureusement sur un projet où je ne peux pas me permettre de perdre du temps à revenir en arrière à cause d'un souci auquel je n'aurais pas pensé causé par modélisation de la couche BLL... :-/

Vous faites comment vous ?