2011-08-16 72 views
0

我正在規劃一個程序的結構並希望使用多個層。 您認爲我的方法很好嗎?或者您有其他建議嗎?多層程序體系結構,反饋和/或建議

// The Form is the View + Controller (Windows Forms standard behaviour, don't want to change it) 
    class FormCustomer 
    { 
     CustomerModel _customerModel; 
     void LoadCustomer() 
     { 
      Customer c = _customerModel.ReadCustomer(tbCustomer.Text); 
      ShowCustomer(c); 
   } 
    } 

    // The Model-Layer is for business Logic 
    class CustomerModel 
    { 
     StorageLayer _StorageLayer;   
     public Customer ReadCustomer(int id) 
     { 
      if (id < 0) throw new Exception("Invalid id"); 
      Customer c = _StorageLayer.ReadCustomer(id); 
      if (c == null) throw new Exception("Customer not found"); 
      return c; 
     } 
    } 

    // The StorageLayer ist a facade to all storage Methods 
    // See http://en.wikipedia.org/wiki/Facade_pattern for more details 
    class StorageLayer 
    { 
     SqlMethods _sqlMethods; 
     public Customer ReadCustomer(int id) 
     { 
      return _sqlMethods.ReadCustomer(id) 
     } 
    } 

    // The SqlMethods is one class (or maybe several classes) which contain 
    // all the sql operations. 
    class SqlMethods 
    { 
     public Customer ReadCustomer(int id) 
     { 
      string sql = "Select c.*, a.* From customers c left join addresses a where c.id = " + id; // Not optimized, just an example 
      IDataReader dr = ExecuteStatement(sql); 
      return FetchCustomer(dr); 
     } 
    } 
+1

您對您的架構有任何具體問題嗎?你使用多層的原因是什麼?你是否理解[層和層之間的區別](http://stackoverflow.com/q/120438/310112)? –

回答

2

1)首先問題 - 並列耦合。

  • FormCustomerCustomerModel
  • CustomerModel到StorageLayerCustomer
  • StorageLayer到CustomerSqlMethods
  • TODO:引入接口和注入上建造階段
// Now you don't need StorageLayer, basically it would be IDataService 
// rModel class should provide a some kind of business logic otherwise it just 
// wrapping with zero value a IDataService and will have 
// a mess introducing model class per entity 
public sealed class CustomerModel 
{ 
    private readonly IDataService 

    // now you can inject any an other data service without model changes 
    // XmlDataService, WebDataService, etc 
    public CustomerModel (IDataService dataService) 
    { 
     this.dataService = dataService; 
    } 

    public ICustomer GetCustomer(int id) 
    { 
     if (id < 0) 
     { 
      throw new ArgumentException("id", 
            "Id should be equal or greater than zero"); 
     } 

     ICustomer c = this.dataService.SelectEntity<Customer>(id); 
     // ... 
    } 
} 
依賴性10

2)第二個 - 嘗試使用泛型,因此每次需要一個新的實體以及客戶(例如Account等)時,您至少可以重用大部分基礎架構。

TODO:考慮設計喜歡去耦實體的查詢(?也許某個時候woudl不是一個SQL查詢)

public interface IDbEntity 
{ 
} 

public interface IDbContract 
{ 
     string SelectByIdQuery { get; } 
} 

public sealed class DataBaseContractFactory 
{ 
    public IDbContract CreateContract<TEntity>() 
     where TEntity: IDbEntity 
    { 
     if (typeof(TEntity) == typeof(ICustomer)) 
     { 
      return this.customerDbContract; 
     } 
    } 
} 

public sealed class SqlDataService: IDataService 
{ 
    public SqlDataService(DataBaseContractFactory dbContractFactory) 
    { 
     // assign to private field 
    } 

    public T SelectEntity<TEntity>(int entityId) 
     where TEntity: IDbEntity 
    { 
     IDbContract contract = this.dbContractFactory.CreateContract<TEntity>(); 

     // Consider using more safe way of query building: 
     // adapter.SelectCommand.Parameters.Add(
     // "@Id", SqlDbType.Int).Value = id; 
     string sqlQuery = String.Format(contract.SelectByIdQuery, id); 

     IDataReader dataReader = ExecuteStatement(sqlQuery); 
     return this.BuildEntytyFromDataReader<TEntity>(dataReader); 
    } 
} 
2
string sql = "Select c.*, a.* From customers c left 
        join addresses a where c.id = " + id; 
// Not optimized, just an example IDataReader dr 
= ExecuteStatement(sql); 

永遠不要做這個的任何理由。這是完全不能接受的。測試不可接受,原型不可接受。作爲開發人員,出於任何原因做這件事都會使你的手受到懲罰。

這是SQL注入最好的。

僅僅因爲這是一個int現在並不意味着你不會改變它爲一個字符串,或意識到你需要一些其他參數,然後加入字符串。

您必須使用參數。

+1

+1但是,砍掉手太寬鬆。我認爲一個緩慢的痛苦的死亡更合適。 –