我正在计划程序的结构,并希望使用多个层。 你认为我的方法是好还是你有其他建议吗?
// 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);
}
}
答案 0 :(得分:2)
1)首先问题 - 绑定耦合。
FormCustomer
至CustomerModel
StorageLayer
,Customer
Customer
,SqlMethods
// 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);
// ...
}
}
2)第二次 - 尝试使用泛型,因此每当您需要与客户一起使用新实体(如帐户等)时,您至少可以重复使用基础架构的主要部分。
TODO :考虑设计就像要从实体中分离查询(可能有时候它不是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);
}
}
答案 1 :(得分: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现在并不意味着你不会将它改成字符串,或者意识到你需要一些其他参数然后加入字符串。
你必须使用参数。