Refactor à n-tier
-
03-07-2019 - |
Question
Je suis un programmeur vb6 autodidacte qui utilise DAO. Vous trouverez ci-dessous un exemple de code typique que je pourrais créer:
Sub cmdMultiplier_Click() 'Button on form, user interface '
dim Rec1 as recordset
dim strSQL as string
strSQL = "select * from tblCustomers where ID = " & CurrentCustomerID 'inline SQL '
set rec1 = GlobalDataBase.openrecordset(strSQL) ' Data access '
if rec1.bof <> true or rec1.eof <> true then
if rec1.fields("Category").value = 1 then
PriceMultiplier = 0.9 ' Business Logic '
else
priceMultiplier = 1
end if
end if
End Sub
Veuillez supposer que ce qui précède est le code source complet d’une application CRUD. Je sais que ce design est mauvais, tout est mélangé. Idéalement, il devrait comporter trois couches distinctes: interface utilisateur, logique métier. et accès aux données. Je comprends en quelque sorte pourquoi c'est souhaitable mais je ne sais pas comment cela se fait et je soupçonne c'est pourquoi je ne comprends pas vraiment pourquoi une telle séparation est bonne. Je pense que je serais beaucoup plus loin sur la route si quelqu'un pouvait refactorer ridiculement ce qui précède exemple trivial en 3 niveaux.
La solution
un exemple trivial, oui, mais avec tous les éléments de base - ils appartiennent à 3 classes différentes (voir ci-dessous). La raison principale en est la "séparation des problèmes". principe, c’est-à-dire que l’interface graphique ne concerne que les éléments de l’interface graphique, la couche logique logique ne concerne que les règles de gestion et la couche d’accès aux données ne concerne que les représentations de données. Cela permet à chaque couche d'être maintenue indépendamment et réutilisée dans toutes les applications:
'in Form class - button handler
Sub cmdMultiplier_Click()
PriceMultiplier = ComputePriceMultiplier(CurrentCustomerId)
End Sub
'in Biz Logic class
Function ComputePriceMultiplier(custId as Integer) as Double
Dim cust as Customer = GetCustomer(custId)
if cust.Category = 1 then 'please ignore magic number, real code uses enums
return 0.9
end if
return 1
End Function
'in Data Access Layer class
Function GetCustomer(custId as Integer) as Customer
Dim cust as Customer = New Customer 'all fields/properties to default values
Dim strSQL as String = "select * from tblCustomers where ID = " & custId
set rec1 = GlobalDataBase.openrecordset(strSQL) ' Data access '
if rec1.bof <> true or rec1.eof <> true then
cust.SetPropertiesFromRecord(rec1)
end if
return cust
End Function
[une application "réelle" mettrait en cache le client actuel, disposerait de constantes ou de procédures stockées pour la requête du client, etc. ignoré par souci de brièveté]
Comparez cela à votre exemple original du gestionnaire de boutons "Tout-dans-le-bouton-de-bouton" (qui est effroyablement courant dans le code VB car il est si facile de le faire de cette façon) - si vous aviez besoin de la règle de multiplicateur de prix dans une autre application, vous devez copier, coller et modifier le code dans le gestionnaire de boutons de cette application. À présent, la même règle commerciale doit être gérée par deux utilisateurs et deux par la même occasion, où la même requête client est exécutée.
Autres conseils
Quel est le but du bouton?
Mes premiers pas seraient:
- extrait la partie accédant à la base de données. (avertissement: code aérien à venir)
function getCustomer (CurrentCustomerID as Long)
strSQL = " select * from tblCustomers où ID = " & amp; CurrentCustomerID set rec1 = GlobalDataBase.openrecordset (strSQL) résultat = 1
si rec1.recordcount > 0 alors getCustomer = rec1 autre getCustomer = false fin si fonction de fin
- composer la fonction de logique métier:
function getCustomerDiscount (ID client en tant que long)
customer = getCustomer (customerID)
res = 1 si client alors si client (" catégorie ") = 1) alors res = .9 fin si endif
getcustomerdiscount = res
fonction de fin
- puis changez le bouton:
Sub cmdMultiplier_Click () pricemultiplier = getcustomerdiscount (currentcustomerid) fin sous
Généralement, votre code d'interface utilisateur répondra aux événements déclenchés par l'utilisateur, dans ce cas, le clic du bouton.
Après cela, cela dépend vraiment de la conception de votre programme. La conception la plus élémentaire consisterait à faire référence à une instance Client et il contiendrait une propriété multiplicateur. Votre objet client est renseigné à partir des données de votre DAL.
La validation de l'interface utilisateur irait dans la couche d'interface utilisateur, les règles de validation métier pourraient aller dans votre objet métier, puis votre DAL serait votre couche de persistance.
Voici un exemple très simple de pseudo-code:
btnClick
Dim Cust as New Customer(ID)
multplr = Cust.DiscountMultiplier
End Click
Class Customer
Sub New(ID)
Data = DAL.GetCustomerData(ID)
Me.Name = Data("Name")
Me.Address = Data("Address")
Me.DiscountMultiplier = Data("DiscountMultiplier")
End Sub
Property ID
Property Name
Property Address
Property DiscountMultiplier
Return _discountMultiplier
End
End Class
Class DAL
Function GetCustomerData(ID)
SQL = "Paramaterized SQL"
Return Data
End Function
End Class
Savoir refactoriser est une bonne chose. A partir de maintenant, vous saurez séparer les calques.
Cependant, je pense que votre temps sera mieux dépensé pour mettre à niveau les outils que vous utilisez en même temps. Avez-vous pensé à le faire avec VB.Net?
Une façon de le faire en préservant votre base de code existante consiste à coder la couche de données et le répertoire de ressources en VB.Net. Ensuite, exposer le BR via l'interface COM (il s'agit d'une option de case à cocher dans le projet). Vous pouvez ensuite utiliser le nouveau BR depuis votre interface actuelle.
Une fois tous les BR et DAL terminés, vous serez sur une nouvelle plateforme complète.