Анемичный домен - это когда продукт или другой класс на самом деле не реализуют ничего, кроме установщиков и получателей данных - без поведения домена.
Например, объект домена продукта должен содержать некоторые методы, некоторые проверки данных, некоторую реальную бизнес-логику.
В противном случае версия BLL (объект домена) вряд ли лучше, чем DTO.
http://martinfowler.com/bliki/AnemicDomainModel.html
ProductBLL productBll = new ProductBLL();
List<ProductDTO> productList = productBll.GetAllProducts();
Проблема здесь в том, что вы предполагаете, что ваша модель анемична, и подвергаете DTO потребителей бизнес-уровня (пользовательский интерфейс или что-то еще).
Ваш код приложения, как правило, хочет работать с <Product>
s, а не с любым BLL, DTO или чем-то еще. Это классы реализации. Они не только мало что значат для уровня мышления программиста приложений, они мало что значат для экспертов по предметной области, которые якобы понимают проблемную область. Таким образом, они должны быть видны только когда вы работаете над сантехникой, а не когда вы проектируете ванную комнату, если вы понимаете, о чем я.
Я называю свои объекты BLL именем сущности бизнес-домена. И DTO является внутренним между бизнес-субъектом и DAL. Когда доменная сущность не делает ничего, кроме DTO, - это когда она анемична.
Кроме того, я добавлю, что я часто просто пропускаю классы DTO explcit, и заставляю объект домена переходить к универсальному DAL с организованными сохраненными процессами, определенными в конфигурации, и загружать себя из простого старого устройства чтения данных в его свойства. С замыканиями теперь возможно иметь очень общие DAL с обратными вызовами, которые позволяют вам вставлять ваши параметры.
Я бы придерживался самой простой вещи, которая может работать:
public class Product {
// no one can "make" Products
private Product(IDataRecord dr) {
// Make this product from the contents of the IDataRecord
}
static private List<Product> GetList(string sp, Action<DbCommand> addParameters) {
List<Product> lp = new List<Product>();
// DAL.Retrieve yields an iEnumerable<IDataRecord> (optional addParameters callback)
// public static IEnumerable<IDataRecord> Retrieve(string StoredProcName, Action<DbCommand> addParameters)
foreach (var dr in DAL.Retrieve(sp, addParameters) ) {
lp.Add(new Product(dr));
}
return lp;
}
static public List<Product> AllProducts() {
return GetList("sp_AllProducts", null) ;
}
static public List<Product> AllProductsStartingWith(string str) {
return GetList("sp_AllProductsStartingWith", cm => cm.Parameters.Add("StartsWith", str)) ;
}
static public List<Product> AllProductsOnOrder(Order o) {
return GetList("sp_AllProductsOnOrder", cm => cm.Parameters.Add("OrderId", o.OrderId)) ;
}
}
Затем вы можете переместить очевидные части в DAL. DataRecords служат вашим DTO, но они очень недолговечны - их коллекция на самом деле никогда не существует.
Вот DAL.Retrieve для SqlServer, который является статическим (вы можете видеть, что достаточно просто изменить его на использование CommandText); У меня есть версия этого, которая инкапсулирует строку подключения (и поэтому это не статический метод):
public static IEnumerable<IDataRecord> SqlRetrieve(string ConnectionString, string StoredProcName,
Action<SqlCommand> addParameters)
{
using (var cn = new SqlConnection(ConnectionString))
using (var cmd = new SqlCommand(StoredProcName, cn))
{
cn.Open();
cmd.CommandType = CommandType.StoredProcedure;
if (addParameters != null)
{
addParameters(cmd);
}
using (var rdr = cmd.ExecuteReader())
{
while (rdr.Read())
yield return rdr;
}
}
}
Позже вы можете перейти к полноценным фреймворкам.