2014-09-04 5 views
0

J'ai le code suivant. J'ai 2 emplois différents qui appelle la même classe de processeur ci-dessous. Les deux font presque la même chose mais ne diffèrent que dans la dernière étape. Actuellement, je le gère sur la base de la variable booléenne 'createReport'. Je voulais extraire la fonctionnalité commune de 90% dans une seule classe.Motif de conception: Extraction de la fonctionnalité commune

Je pensais au modèle de modèle. Mais comment puis-je injecter la dépendance de repositoryA dans la classe abstraite?

Imports log4net 
Imports System 
Imports System.Collections.Generic 

Public Interface IProcessor 
    Sub Process(path As String, includeCache As Boolean, createReport As Boolean) 
End Interface 

Public Class Processor 
    Implements IProcessor 

    Private ReadOnly _repositoryA As IRepositoryA 
    Private ReadOnly _repositoryB As IRepositoryB 
    Private ReadOnly _logger As ILog 

    Public Sub New(repositoryA As IRepositoryA, repositoryB As IRepositoryB, logger As ILog) 
     If repositoryA Is Nothing Then 
      Throw New ArgumentNullException("repositoryA") 
     End If 

     If repositoryB Is Nothing Then 
      Throw New ArgumentNullException("repositoryB") 
     End If 

     If logger Is Nothing Then 
      Throw New ArgumentNullException("logger") 
     End If 

     _repositoryA = repositoryA 
     _repositoryB = repositoryB 
     _logger = logger 
    End Sub 

    Public Sub Process(folderPaths As String, includeCache As Boolean, createReport As Boolean) Implements IProcessor.Process 
     _logger.Info("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++") 

     If String.IsNullOrEmpty(folderPaths) Then 
      Throw New ArgumentNullException("folderPaths") 
     End If 

     Dim paths() As String = folderPaths.Split(New Char() {";"c}) 
     For Each path As String In paths 
      Dim cList As List(Of Container) = _repositoryA.GetContainers(path, includeCache) 
      For Each container As Container In cList 
       If Not container.IsDeleted Then 
        Dim assetList As List(Of Asset) = _repositoryA.GetAssets(container.ContainerID) 
        If Not assetList Is Nothing Then 
         For Each asset As Asset In assetList 
          ProcessAsset(asset, createReport) 
         Next 
        End If 
       End If 
      Next 
     Next 

     _logger.Info("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++") 
    End Sub 

    Private Sub ProcessAsset(asset As Asset, createReport As Boolean) 
     'Again some common business logic 

     'at last depending on value of createReport 
     If createReport Then 
      CreateReport(asset) 
     Else 
      SyncAsset(asset, ...other arguments) 
     End If 
    End Sub 

    Private Sub SyncAsset(asset As asset, ..other arguments) 
     'business logic. Dependency on _repositoryB here 
    End Sub 

    Private Sub CreateReport(asset As asset) 
     'business logic 
    End Sub 
End Class 

Merci pour l'aide à l'avance

Cordialement, Suyog

+0

Veuillez utiliser la syntaxe en surbrillance –

+0

Je ne vois pas le problème. La méthode de modèle semble être une approche raisonnable. Qu'est-ce qui vous empêche de définir les variables du référentiel dans la classe abstraite? –

Répondre

1

Je partagerais vos Process méthodes dans différentes classes que vous exprimez le flux veulent votre code à suivre. Passez ensuite ces classes derrière une abstraction à l'algorithme principal, ce qui vous permet d'échanger des parties du comportement à la volée.

Dans ce cas, vous souhaitez répertorier les actifs et traiter chaque actif. Le processus effectue N opérations et finaliser l'actif (c'est-à-dire soit le synchroniser de créer un rapport). Brisons le décomposer en sous-/ interfaces que nous pourrions utiliser:

  • IAssetListCreator {IEnumerable CreateAssetList();}
  • IAssetProcessor {void Process (Asset a, IAssetFinalizer af);}
  • IAssetFinalizer {void finalize (Asset a);}

maintenant, vous pouvez composer les différentes briques afin de reproduire l'algorithme que vous aviez avant:

Public Interface IProcessor 
    Sub Process(creator as IAssetListCreator, processor as IAssetProcessor, finalizer as IAssetFinalizer) 
End Interface 

' inside the process class 
Public Sub Process(creator as IAssetListCreator, processor as IAssetProcessor, finalizer as IAssetFinalizer) Implements IProcessor.Process 
    _logger.Info("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++") 

    For Each asset As Asset In creator.CreateAssetList() 
     processor.Process(asset, finalizer) 
    Next 

    _logger.Info("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++") 
End Sub 

' inside the IAssetProcessor 
Private Sub ProcessAsset(asset As Asset, finalizer as IAssetFinalizer) 
    'Again some common business logic 
    finalizer.Finalize(asset) 
End Sub 

Maintenant, chaque composant peut être construit en utilisant uniquement les éléments dont il a besoin: si repositoryA n'est nécessaire que dans le comportement de synchronisation, créez une classe héritant de IAssetFinalizer qui utilise le repositoryA dans le constructeur. Dans le même esprit, seule l'instance IAssetListCreator doit connaître le chemin dans lequel se trouvent les actifs, ou si le cache doit être impliqué, etc ...

Je suis allé à plein régime en décomposant le code original; Vous pouvez toujours utiliser le code de liste dans la fonction Process, mais vous pouvez vraiment limiter les paramètres aux composants qui en ont besoin: