2008-10-22 7 views
1

Je suis un programmeur vb6 autodidacte qui utilise DAO. Voici un exemple d'une pièce typique de code que je pouvais désabonnement:Refactor à n-tier

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 

S'il vous plaît faire semblant que ce qui précède est l'intégralité du code source d'une application CRUD. Je sais que ce design est mauvais, tout est mélangé. Idéalement, il devrait avoir trois couches distinctes, l'interface utilisateur, la logique métier et l'accès aux données. Je sais pourquoi cela est souhaitable, mais je ne sais pas comment c'est fait et je pense que c'est pourquoi je ne comprends pas pourquoi une telle séparation est bonne. Je pense que je serais beaucoup plus loin sur la route si quelqu'un pouvait refactoriser l'exemple trivial ridicule ci-dessus en 3 niveaux.

+0

il serait très difficile de refactoriser cela simplement parce que c'est ridiculement trivial. Avoir une application à trois niveaux introduirait beaucoup de complexité dans un exemple si simple qu'il n'illustrerait pas correctement qu'une architecture à trois niveaux est plus simple qu'un méli-mélo général de code. – workmad3

+0

Je sais ce que tu veux dire mais je voulais voir comment c'est fait. Après y avoir réfléchi un peu plus, je pense qu'une séparation en niveaux est peut-être analogue à la normalisation d'une base de données? Sur un plan superficiel, il semble ajouter de la complexité sans aucune récompense – kjack

+0

oui, il est analogue à normaliser une base de données. Par George je pense qu'il l'a eu (tm)! –

Répondre

3

un exemple trivial, oui, mais avec tous les éléments de base - ils appartiennent seulement dans 3 classes différentes (voir ci-dessous). La principale raison en est le principe de «séparation des préoccupations», à savoir que l'interface graphique concerne uniquement les éléments de l'interface graphique, la couche Biz Logic ne concerne que les règles métier et la couche d'accès aux données concerne uniquement les représentations de données. Cela permet à chaque couche à maintenir de manière indépendante 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 » serait mettre en cache le client actuel, ont des constantes ou des procédures stockées pour la requête de client, etc .; Comparez-le pour simplifier]

Comparez cela avec votre exemple original de tout-dans-le-bouton-gestionnaire (ce qui est terriblement commun dans le code VB parce qu'il est si facile de le faire de cette façon) - si vous avez besoin du multiplicateur de prix Dans une autre application, vous devez copier, coller et modifier le code dans le gestionnaire de boutons de cette application. Maintenant, il y aurait deux endroits pour maintenir la même règle de gestion, et deux endroits où la même requête de client a été exécutée. Savoir refactoriser est une bonne chose.

+0

Bonne réponse! Préserver le code original en le redistribuant a vraiment aidé à la compréhension. – kjack

+0

Peut-être que dans la couche d'accès aux données, il y aurait une seule fonction pour obtenir les données? Pour qu'une seule ligne comme celle-ci dans l'ensemble de l'application: set rec1 = GlobalDataBase.openrecordset (strSQL) – kjack

+0

@kjack Il n'y a pas de réponse facile à votre dernière question. Certaines personnes disent oui, d'autres diront non. Cela dépend de ce à quoi ressemble le reste de votre architecture. –

1

Quel est l'objectif du bouton?

Mes premiers pas seraient:

  • extraire la partie accès à la base de données. (Avertissement: code air avant)

fonction getCustomer (CurrentCustomerID comme Long)

strSQL = "select * from tblCustomers où ID =" & CurrentCustomerID ensemble rec1 = GlobalDataBase.openrecordset (strSQL) résultat = 1

si rec1.recordcount> 0 puis getCustomer = rec1 autre getCustomer = false endif fonction fin

  • composent la fonction logique métier:

fonction getCustomerDiscount (customerID comme Long)

client = getCustomer (customerID)

res = 1 si le client puis si le client (» catégorie ") = 1) puis res = .9 endif endif

getcustomerdiscount = res

fonction fin

  • puis, changer le bouton:

Sous cmdMultiplier_Click() pricemultiplier = getcustomerdiscount (currentcustomerid) end sub

+0

J'ai oublié de coller dans un but pour le bouton. Peut-être afficher le multiplicateur sur une étiquette. Merci pour votre réponse, la réponse de Stephen A. Lowe a étoffé les choses un peu plus, ce qui est plus compréhensible pour moi. – kjack

1

En général, vous demandez à votre code d'interface utilisateur de répondre aux événements déclenchés par l'utilisateur, dans ce cas, cliquez sur le bouton. Après que cela dépendra vraiment de la façon dont votre programme est conçu, la conception la plus basique consisterait à référencer une instance de client et elle contiendrait une propriété de multiplicateur. Votre objet client est renseigné à partir des données de votre DAL.

La validation de l'interface utilisateur se ferait dans une couche d'interface utilisateur, les règles de validation métier pourraient entrer dans votre objet métier, puis votre couche de persistance est votre couche de persistance.

Voici un exemple pseudo-code très basique:

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 
+0

Merci, j'ai accepté la réponse de Stephen A Lowe parce que je l'ai un peu mieux comprise (même si objectivement je ne suis pas en mesure de juger de la meilleure réponse). – kjack

1

A partir de maintenant vous saurez comment 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 envisagé de le faire avec VB.Net?

Une façon de le faire préservera votre base de code existante est de coder la couche de données et BR dans VB.Net. Ensuite, pour 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 à deux pas d'une nouvelle plate-forme complète.

+0

C'est un bon point. Je pense à tout porter sur .net dans le futur, mais je pense que vb6 a encore quelques années. Je pense qu'il pourrait être plus facile à la fois de maintenir, d'améliorer et de refactoriser l'application existante et d'apprendre la POO etc. dans un environnement dans lequel je suis déjà à l'aise. – kjack

Questions connexes