尝试实现三层架构(不是:层,我只想在一台机器上逻辑分离我的项目)时,我发现有很多不同的方法,让我感到困惑,如果有的话,最好的方法是什么,可以在WinForms应用程序中实现。现在我只对项目中应该存在的3个层没有疑问:
UI(表示层)
BLL(业务逻辑层)
DAL(数据访问层)
在UI中,我放置了所有的WinForms。还必须有一些逻辑来使用控件中的数据填充对象并将其传递到BLL层。
在DAL中,我想放置使用ADO.NET进行数据操作的类和方法,例如:
问题出在 BLL 上,关键是:我应该使用 数据传输对象(DTO) 在层之间传递数据,还是应该传递整个类?
如果我选择使用 DTO,那么我需要创建一个额外的公共类
并将逻辑分离到BLL中:
这种方法在不同的名称下被使用,例如:here或here。
另一方面,一些“聪明人”及其追随者(如here)称其为贫血领域模型,并抱怨它是一个糟糕的设计和反模式,不应该被使用。 优点:
UI(表示层)
BLL(业务逻辑层)
DAL(数据访问层)
在UI中,我放置了所有的WinForms。还必须有一些逻辑来使用控件中的数据填充对象并将其传递到BLL层。
在DAL中,我想放置使用ADO.NET进行数据操作的类和方法,例如:
public class OrderDAL
{
public OrderDAL()
{
}
public int Add(Order order)
{
//...add order to database
}
public int Update(Order order)
{
//...update order in database
}
//...etc.
}
问题出在 BLL 上,关键是:我应该使用 数据传输对象(DTO) 在层之间传递数据,还是应该传递整个类?
如果我选择使用 DTO,那么我需要创建一个额外的公共类
Order
,它会被 UI、BLL 和 DAL 引用:public class Order
{
public int Id { get; set; }
public DateTime Date { get; set; }
public string Number { get; set; }
public string CustomerName { get; set; }
public Order ()
{
}
}
并将逻辑分离到BLL中:
public class OrderBLL
{
public OrderBLL()
{
}
public int Add(Order order)
{
OrderDAL orderDAL = new OrderDAL();
return orderDAL.Add(order);
}
public int Update(Order order)
{
OrderDAL orderDAL = new OrderDAL();
return orderDAL.Update(order);
}
//...etc.
}
这种方法在不同的名称下被使用,例如:here或here。
另一方面,一些“聪明人”及其追随者(如here)称其为贫血领域模型,并抱怨它是一个糟糕的设计和反模式,不应该被使用。 优点:
- DTO可以轻松地被设计成代表数据库表,
- 它很轻量级和清晰,只包含数据库所需的字段,
- DAL不必引用BLL,
- 反模式(听起来很可怕;P),
- 违反面向对象编程原则(将属性与方法分开),
- 因为逻辑在不同的类中,当某些内容改变时,可能更难维护。
因此,相反的做法是在层之间传递整个对象,就像这里一样:没有DTO,只有以下BLL:
public class Order
{
public int Id { get; set; }
public DateTime Date { get; set; }
public string Number { get; set; }
public string CustomerName { get; set; }
public Order()
{
}
public int Add()
{
OrderDAL orderDAL = new OrderDAL();
return orderDAL.Add(this);
}
public int Update(Order order)
{
OrderDAL orderDAL = new OrderDAL();
return orderDAL.Update(order);
}
}
优点:
- 这是一个很好的封装对象,遵循面向对象编程规则(我想是这样的吧;)).
- 逻辑和属性都在同一位置,更易于维护和调试。
缺点:
- 要使用对象,数据访问层必须引用业务逻辑层(这不应该是三层架构的方式,不是吗?)。
- 类可能包含一些在数据库中未使用的字段,也可能包含一些来自数据库的字段(如Id)不代表“真实”对象。
所以,看起来无论我选择什么,都会违反某些规则。那么,有没有更好的方法,我应该选择哪种?也许还有其他方法我还没发现?