2015-11-08 4 views
8

Ho implementato una semplice classe di fabbrica in C# e Java. Questa classe crea istanze di classi di lavoro concrete che hanno una stessa interfaccia. In particolare, tutte queste classi hanno tali metodi come:Quale modello di progettazione utilizzare per implementare il meccanismo di transazione o concatenamento

create 
select 
alter 
etc. 

Ora voglio avere un meccanismo (costruito sulla cima di qualche modello classico/non classica) che mi permetterà di creare "catene" di questi metodi o per incapsularli in una sorta di transazione. In uno pseudo-codice mi aspetto di vedere qualcosa di simile:

Transaction tnx = create(...args...).alter(...args_2...); 
//tnx.Execute(); 

O qualcosa di simile:

Transaction tnx; 
tnx.Start(); 
tnx.Add(method_name, ... variable list of arguments ...); 
tnx.Add(another_method_name, ... variable list of arguments ...); 
tnx.Execute(); 

Non sono così bravo a modelli di progettazione e non sono sicuro di quale schema da utilizzare. Spero che qualcuno possa condividere e rilasciare un paio di righe di codice (in C# o in Java) che dimostreranno come ciò possa essere implementato. Grazie!

risposta

6

unità di lavoro è il modello diritto di rappresentare le transazioni dominio .

Accumula le modifiche (aggiunge, aggiorna e rimuove) e possono essere atomicamente accettate o scartate. L'atomicità è garantita dall'implementazione dell'intera unità di lavoro e l'implementatore deve essere sicuro che i cambiamenti siano persistenti o scartati atomicamente.

controllare come Martin Fowler definisce on his pattern catalog:

Mantiene un elenco di oggetti colpiti da una transazione commerciale e coordina la scrittura di modifiche e la risoluzione dei problemi di concorrenza .

Una possibile interfaccia per Unità di modello di lavoro potrebbe essere:

public interface IUnitOfWork 
{ 
    void Commit(); 
    void Rollback(); 
} 

E si può anche aggiungere i seguenti metodi per l'interfaccia:

// Note I've added a generic type parameter to define what kind of 
// objects will handle the whole unit of work 
public interface IUnitOfWork<TObject> 
{ 
    void RegisterNew(TObject some); 
    void RegisterUpdated(TObject some); 
    void RegisterDeleted(TObject some); 
    void Commit(); 
    void Rollback(); 
} 

In ogni caso, tutti gli aggiornamenti dovrebbero essere gestito utilizzando un rilevamento delle modifiche monitorato dall'unità di lavoro e alcune aggiunte e Elimina troppo:

  • Se si aggiunge un nuovo oggetto di una raccolta associata a qualche altro oggetto (Associazione 1-n), un'unità di lavoro dovrebbe essere in grado di rilevare che l'oggetto è sporco e deve essere mantenuta senza dire manualmente all'unità di lavoro di farlo.

  • Uguale per le operazioni di rimozione. Se rimuovi un oggetto da un'associazione 1-n e nessun altro oggetto fa riferimento a esso (un oggetto orfano) dovrebbe essere automaticamente contrassegnato come eliminato.

La maggior parte dei mapper dati come O/M quadri già di attuazione cambiamento oggetto di monitoraggio utilizzando proxy degli oggetti da intercettare le chiamate insieme di proprietà.

+0

Grazie! Sembra utile! Controllerò e testerò questo modello. – Jacobian

+0

@Jacobian Il pattern composito non ha nulla a che fare con ciò che vuoi comunque risolvere! –

+0

Immagino, hai ragione. Sembra che il tuo consiglio si adatti meglio al compito. – Jacobian

3

Composite pattern è una scelta ovvia per le situazioni in cui si modella un intero sistema. Ecco come lo schema del modello sembra:

Composite pattern

Dato che si dispone di una fabbrica di oggetti della stessa interfaccia, si è quasi fatto l'attuazione del composite.

  • La vostra fabbrica produce oggetti conformi ad alcune interfacce. Questa interfaccia è l'interfaccia componente della tua implementazione composita.
  • La vostra fabbrica produce classi concrete, che rappresentano le classi Leaf nella vostra implementazione composita.

L'unica classe lasciata da costruire è la classe Composite.

Diciamo vostra interfaccia Component si presenta così:

public interface IComponent { 
    void Create(); 
    void Alter(); 
    void Execute(); 
} 

Poi la classe composita Transaction può apparire come segue:

public class Transaction : IComponent { 
    private readonly IList<IComponent> components = new List<IComponent>(); 
    public void Add(IComponent c) { 
     components.Add(c); 
    } 
    void Create() { 
     foreach (var c in components) { 
      c.Create(); 
     } 
    } 
    void Alter() { 
     foreach (var c in components) { 
      c.Alter(); 
     } 
    } 
    void Execute() { 
     foreach (var c in components) { 
      c.Execute(); 
     } 
    } 
} 
+0

Grazie per questo grande capolavoro! Mi piace veramente! Ma posso chiederti, per favore, di dimostrare in un paio di righe di codice come può essere usato. Lo sto chiedendo, perché per me sembra che la classe Transaction sia troppo legata alle lezioni concrete. Non dovrebbe essere più disaccoppiato? E a proposito, cosa ne pensi del modello di comando? Non è adatto al compito meglio del modello Composite? – Jacobian

+0

@Jacobian Lo scopo della classe 'Transaction' che implementa la stessa interfaccia' IComponent' come classi concrete è che è possibile aggiungere 'Transaction' come membro di un'altra transazione, che può includere altre transazioni. Il modello 'Command' nasconde la distinzione tra intero e parte, ma la composizione non ne fa parte. – dasblinkenlight

+0

@Jacobian Inoltre, non sono affatto d'accordo con il commento incondizionato di Matías secondo cui "il modello composito non ha nulla a che fare con ciò che si vuole risolvere", perché ciò che chiamate "transazione" nella descrizione di ciò che state implementando ha poco a che fare con le transazioni nel senso atomico-coerente-durevole-isolato della parola. Quello che stai facendo assomiglia a una serie di azioni e il modello composito offre molta flessibilità nel modo di implementarlo. – dasblinkenlight