2010-03-17 10 views
6
public class StepClause 
{ 
    public NamedStepClause Action1() {} 

    public NamedStepClause Action2() {} 
} 

public class NamedStepClause : StepClause 
{ 
    public StepClause Step(string name) {} 
} 

Fondamentalmente, voglio essere in grado di fare qualcosa del genere:design di interfaccia Fluent e il codice odore

var workflow = new Workflow().Configure() 
    .Action1() 
    .Step("abc").Action2() 
    .Action2() 
    .Step("def").Action1(); 

Così, alcuni "passi" sono chiamati e alcuni non lo sono.

La cosa che non mi piace è che la StepClause conosca la sua classe derivata NamedStepClause.

Ho provato un paio di cose per farlo stare meglio con me. Ho provato a spostare le cose verso le interfacce ma poi il problema è passato dal concreto alle interfacce - INamedStepClause deve ancora derivare da IStepClause e IStepClause deve restituire INamedStepClause per poter chiamare Step(). Potrei anche fare di Step() parte di un tipo completamente separato. Poi non abbiamo questo problema e ci piacerebbe avere:

var workflow = new Workflow().Configure() 
    .Step().Action1() 
    .Step("abc").Action2() 
    .Step().Action2() 
    .Step("def").Action1(); 

che è ok ma mi piacerebbe fare il passo di denominazione opzionale, se possibile.

Ho trovato questo altro post su SO here che sembra interessante e promettente. Quali sono le tue opinioni? Penserei che la soluzione originale sia completamente inaccettabile o vero?

A proposito, quei metodi di azione prenderanno predicati e funtori e non penso di voler prendere un parametro aggiuntivo per nominare il passo lì.

Il punto è tutto, per me, è definire solo questi metodi di azione in un posto e in un solo luogo. Quindi le soluzioni dal link di riferimento usando i metodi di generica e di estensione sembrano essere gli approcci migliori finora.

+0

Semplicemente non mi piace la maggior parte delle risposte che ottengo. L'altra ragione è che ho dimenticato: P –

risposta

9

Ti darò due opzioni.

Opzione A

var a = new A.NamedStepClause(); 

a.Action1() 
    .Step("abc").Action2() 
    .Action2() 
    .Step("def").Action1(); 


namespace A 
{ 
    public class StepClause<SC> where SC : StepClause<SC> 
    { 
     public SC Action1() { return null; } 
     public SC Action2() { return null; } 
    } 

    public class NamedStepClause : StepClause<NamedStepClause> 
    { 
     public NamedStepClause Step(string name) { return null; } 
    } 
} 

Opzione B

var b = new B.StepClause(); 

b.Action1() 
    .Step("abc").Action2() 
    .Action2() 
    .Step("def").Action1(); 

namespace B 
{ 
    public class StepClause 
    { 
     public StepClause Action1() { return null; } 
     public StepClause Action2() { return null; } 
    } 

    public static class StepClauseExtensions 
    { 
     public static StepClause Step(this StepClause @this, string name) 
     { return null; } 
    } 
} 

Entrambe le opzioni di compilazione e vi darà l'interfaccia fluida che stai cercando. Sono più incline ad andare con l'opzione A in quanto ti dà accesso al funzionamento interno della classe. L'utilizzo di metodi di estensione significa che potrebbe essere necessario fornire una sorta di accesso esterno alla classe, rompendo così l'incapsulamento.

Buona fortuna!

+0

+1 per l'opzione A –

+1

Prenderò l'opzione A con una modifica nel metodo Step in NamedStepClause - dovrebbe restituire StepClause piuttosto che NamedStepClause; altrimenti mi trovo in una situazione in cui è possibile: Step ("1"). Step ("2"). Step ("3") ... Forse quella richiesta non era chiara - scusa –

+0

L'opzione B in realtà non lo è lavoro per lo stesso motivo che ho affermato nel commento sopra. –

Problemi correlati