Approfitto di questi schermi per...
Ogni tanto (IMHO non abbastanza) sui NewsGroup si parla di design e l'argomento principe per chi si sta approcciando al problema è quasi sempre la stratificazione (suddivisione in Layer) delle applicazioni.
Naturalmente il "problema" l'ho dovuto sviscerare anche io e dopo varie reimplementazioni l'ho "rilsolto" (almeno per ora).

Quando sono di fronte ad applicazioni di un certo "spessore" la struttura è sintetizzabile così:
Domain Layer
Rappresenta lo strato di business e contiene tutte le classi/entities necessarie.
Una esempio tipo di business entity(s) potrebbe essere:

//
// ASSEMBLY
// Topics.Common.dll
//

/*
    MyObject è la classe di base da cui tutte le 
    entity del mio framework erditano
*/
public abstract class MyObject
{
    
protected virtual void Initialize( System.Data.IDataReader reader )
    {
        
if( reader == null )
        {
            
/*
            L'istanza rappresenta un nuovo oggetto
            quindi inizializziamo i field con i
            valori di default
            */
            
this._uid = Guid.NewGuid();
            
this._description = String.Empty;
            
            
this._isNew = true;
        }
        
else
        
{
            
this._uid = reader.GetGuid( reader.GetOrdinal( "UID" ) );
            
this._description = reader.GetString( reader.GetOrdinal( "Description" ) );
            
            
this._isNew = false;
        }
    }
    
    
protected MyObject( System.Data.IDataReader reader )
    {
        
if( reader == null )
        {
            
throw new ArgumentException( "Invalid Source" );
        }
        
        
this.Initialize( reader );
    }
    
    
protected MyObject()
    {
        
this.Initialize( null );
    }
    
    
private Guid _uid;
    
    
//La chiave primaria
    
public Guid UID
    {
        
getreturn this._uid; }
    }
    
    
private bool _isNew;
    
/*
        La proprietà in sola lettura IsNew
        ci permette di sapere se l'istanza
        che stiamo maneggiando arriva da un 
        DataSource o sia una nuovo elemento
    */
    
public bool IsNew
    {
        
getreturn this._isNew; }
    }
    
    
private string _description;
    
public string Description
    {
        
getreturn this._description; }
        
set
        
{
            
ifvalue == null )
            {
                
value = String.Empty;
            }
            
            
if( !value.Equals( this._description ) )
            {
                
this._description = value
            }
        }
    }
    
    
/*
        ParametersCollection (omessa per semplicità) non è che una
        collection di coppia Key (String)/Value (Object) che viene 
        usata a mo di MOC object al fine di scambiare dati con lo 
        strato di factory
    */
    
protected virtual ParametersCollection GetParameters()
    {
        ParametersCollection parameters = 
new ParametersCollection();
        parameters.Add( "UID", 
this.UID );
        parameters.Add( "Description", 
this.Description );
        
        
return parameters;
    }
    
    
protected abstract void InsertData( ParametersCollection parameters );
    
protected abstract void UpdateData( ParametersCollection parameters );
    
protected abstract void DeleteData( ParametersCollection parameters );
    
    
public void Save()
    {
        
/*
            Nell'applicazione reale la gestione è decisamente più
            complessa e comprende una serie di eventi che permettono 
            di manipolare dall'esterno alcuni aspetti e consento anche
            di interrompere il processo di salvataggio e/o cancellazione
        */
        
ParametersCollection parameters = this.GetParameters();

        
/*
            Usiamo IsNew per determinare quale sia l'azione
            da intraprendere per il salvataggio
        */
        
ifthis.IsNew )
        {
            
this.InsertData( parameters );
        }
        
else
        
{
            
this.UpdateData( parameters );
        }
    }
    
    
public void Delete()
    {
        ParametersCollection parameters = 
new ParametersCollection();
        parameters.Add( "UID", 
this.UID );
        
        
this.DeleteData( parameters );
    }
}

//
// ASSEMBLY
// Topics.MyApplication.Domain.dll
//

public class MyCustomer : MyObject
{
    
protected override void Initialize( System.Data.IDataReader reader )
    {
        
if( reader == null )
        {
            
/*
            L'istanza rappresenta un nuovo oggetto
            quindi inizializziamo i field con i
            valori di default
            */
            
this._companyName = String.Empty;
        }
        
else
        
{
            
this._companyName = reader.GetString( reader.GetOrdinal( "CompanyName" ) );
        }
    }

    
public MyCustomer( System.Data.IDataReader reader )
        : 
base( reader )
    {
        
    }
    
    
public MyCustomer()
        : 
base()
    {
        
    }
    
    
private string _companyName;
    
public string CompanyName
    {
        
getreturn this._companyName; }
        
set
        
{
            
ifvalue == null )
            {
                
value = String.Empty;
            }
            
            
if( !value.Equals( this._companyName ) )
            {
                
this._companyName = value
            }
        }
    }
    
    
protected override ParametersCollection GetParameters()
    {
        ParametersCollection parameters = 
base.GetParameters();
        parameters.Add( "CompanyName", 
this.CompanyName );
        
        
return parameters;
    }
    
    
protected override void InsertData( ParametersCollection parameters )
    {
        
/*
            TODO
            Solo la classe "reale" Customer conosce il sistema
            per persistere/manipolare i propri dati
        */
    
}
    
    
protected override void UpdateData( ParametersCollection parameters )
    {
        
/*
            TODO
            Solo la classe "reale" Customer conosce il sistema
            per persistere/manipolare i propri dati
        */
    
}
    
    
protected override void DeleteData( ParametersCollection parameters )
    {
        
/*
            TODO
            Solo la classe "reale" Customer conosce il sistema
            per persistere/manipolare i propri dati
        */
    
}
}
Persistence Layer
E' lo strato che si occupa effettivamente di persistere ( Insert Update e Delete ) i dati, anche qui un esempio è meglio di mille parole:

//
// ASSEMBLY
// Topics.Common.Persistence.dll
//

public sealed class PersistanceEngine
{
    
private PersistanceEngine()
    {
    
    }

    
private static PersistanceEngine _engine;
    
    
/*
        Singleton
    */
    
public static PersistencaEngine Engine
    {
        
get
        
{
            
if( _engine == null )
            {
                _engine = 
new PersistanceEngine();
            }
            
            
return _engine;
        }
    }
    
    
private MyCustomerPersistance _myCustomers
    
public MyCustomerPersistance MyCustomers
    {
        
get
        
{
            
ifthis._myCustomers == null )
            {
                
this._myCustomers = MyCustomerPersistance.CreateInstance();
            }
            
            
return this._myCustomers;
        }
    }
}

public abstract class MyCustomerPersistance
{
    
public static MyCustomerPersistance CreateInstance()
    {
        
/*
            OMISSIS
            Legge da file .config quale tipo di
            Persistance debba istanziare e da quale
            assembly, trami Activator.CreateInstance( ... )
            inizializza la classe "reale" corretta
        */
    
}
    
    
public abstract void Update( ParametersCollection parameters );
    
public abstract void Insert( ParametersCollection parameters );
    
public abstract void Delete( ParametersCollection parameters );
}

//
// ASSEMBLY
// Topics.MyApplication.SqlPersistence.dll
//

public class MyCustomerSqlPersistance : MyCustomerPersistance
{
    
public override void Update( ParametersCollection parameters )
    {
        
//Salva su db via StoredProcedure
    
}
    
    
public override void Insert( ParametersCollection parameters )
    {
        
//Salva su db via StoredProcedure
    
}
    
    
public override void Delete( ParametersCollection parameters )
    {
        
//Cancella da db via StoredProcedure
    
}
}
Quindi sistemando la ns classe MyCustomer nello strato di business i metodi InsertData, UpdateData e DeleteData avranno tutti un semplice corpo del tipo
protected override void InsertData( ParametersCollection parameters )
{
    PersistanceEngine.Engine.MyCustomers.Insert( parameters );
}

protected override void UpdateData( ParametersCollection parameters )
{
    PersistencaEngine.Engine.MyCustomers.Update( parameters );
}

protected override void DeleteData( ParametersCollection parameters )
{
    PersistanceEngine.Engine.MyCustomers.Delete( parameters );
}
In questo modo il domain layer accede ad un'interfaccia astratta e non ha la più "pallida idea" (come è giusto che sia) di quale sia la reale implementazione dello strato di Persistance. Questo porta un ulteriore vantaggio siccome lo strato di persistenza viene istanziato dinamicamente tramite informazioni prese da un file di configurazione è possibile creare un nuovo strato di persistenza in un nuovo assembly copiarlo nella directory "bin " dell'applicazione modificare opportunemente il file di configurazione e cambiare radicalmente il comportamento dell'applicazione senza che quest'ultima se ne accorga e soprattutto senza ricompilare.
"Fine prima parte"
.m
-------------------
Have a nice day