我目前的服务类看起来像这样
public class UserService : IUserService
{
private IAssignmentService _assignmentService;
private ILocationService _locationService;
private IUserDal _userDal;
private IValidationDictionary _validationDictionary;
public UserService(IAssignmentService assignmentService, ILocationService locationService, IValidationDictionary validationDictionary)
{
this._assignmentService = assignmentService;
this._locationService = locationService;
this._userDAL = new UserDal();
this._validationDictionary = validationDictionary;
}
.....
private void ValidateUser(IUser user)
{
if (_locationService.GetBy(user.Location.Id) == null)
_validationDictionary.AddError("....");
if (_assignmentService.GetBy(user.Assignment.Id) == null)
_validationDictionary.AddError("....");
.....
}
}
Run Code Online (Sandbox Code Playgroud)
和DAL类看起来像这样
public class UserDal: IUserDal
{
private IAssignmentDal _assignmentDal;
private ILocationDAL _locationDAL
public UserDal()
{
this_assignmentDal = new AssignmentDal();
this._locationDal = new LocationDal();
}
public int AddUser(IUser user)
{
// db call and insert user
_locationDal.Add(user.Location);
_assignmentDal.Add(user.Assignment);
}
public IUser GetUser(int id)
{
..DB Call
IUser user = new User() { userData, GetLocation(dr["Location_Id"]),GetAssignment([dr["Assignment_Id"]);
return user
}
private ILocation GetLocation(int id)
{
return new LocationDal().GetById(id);
}
private IAssignment GetAssignment(int id)
{
return new AssignmentDal().GetById(id);
}
}
Run Code Online (Sandbox Code Playgroud)
我想知道将服务层与其他服务层对象进行通信以及Dal与其他Dal对象进行通信是否被认为是错误的设计?
提前致谢
鉴于你的例子的设计,你将遇到我喜欢称为依赖地狱的东西.沿着您正在走的路线当然是一个选择,但它将导致高度耦合的架构,可能很难维护和重构.但是,如果您抽象一点,您可以简化您的体系结构,更多地组织职责,并以这样一种方式分离关注点,即管理依赖关系会更容易.
UserService,AssignmentService和LocationService看起来像CRUD样式的服务.对他们来说更合适的术语是实体服务.实体服务应全权负责直接实体的CRUD操作,而不是其他任何操作.涉及多个实体,实体关系等的操作可以推送到可以协调大规模操作的更高级别的服务.这些通常称为Orchestration或Task Services.
我建议采用如下方法.这里的目标是简化每个服务,使其具有最小的责任范围,并控制依赖关系.简化您的服务合同以减少现有实体服务的责任,并添加两项新服务:
// User Management Orchestration Service
interface IUserManagementService
{
User CreateUser();
}
// User Entity Service
interface IUserService
{
User GetByKey(int key);
User Insert(User user);
User Update(User user);
void Delete(User user);
}
// User Association Service
interface IUserAssociationService
{
Association FindByUser(User user);
Location FindByUser(User user);
void AssociateWithLocation(User user, Location location);
void AssociateWithAssignment(User user, Assignment assignment);
}
// Assignment Entity Service
interface IAssignmentService
{
Assignment GetByKey(int key);
// ... other CRUD operations ...
}
// Location Entity Service
interface ILocationService
{
Location GetByKey(int key);
// ... other CRUD operations ...
}
Run Code Online (Sandbox Code Playgroud)
创建用户并将其与位置和分配相关联的过程属于UserManagementService,后者将组成较低级别的实体服务:
class UserManagementService: IUserManagementService
{
public UserManagementService(IUserService userService, IUserAssociationService userAssociationService, IAssignmentService assignmentService, ILocationService locationService)
{
m_userService = userService;
m_userAssociationService = userAssociationService;
m_assignmentService = assignmentService;
m_locationService = locationService;
}
IUserService m_userService;
IUserAssociationService m_userAssociationService;
IAssignmentService m_assignmentService;
ILocationService m_locationService;
User CreateUser(string name, {other user data}, assignmentID, {assignment data}, locationID, {location data})
{
User user = null;
using (TransactionScope transaction = new TransactionScope())
{
var assignment = m_assignmentService.GetByKey(assignmentID);
if (assignment == null)
{
assignment = new Assignment { // ... };
assignment = m_assignmentService.Insert(assignment);
}
var location = m_locationService.GetByKey(locationID);
if (location == null)
{
location = new Location { // ... };
location = m_locationService.Insert(location);
}
user = new User
{
Name = name,
// ...
};
user = m_userService.Insert(user);
m_userAssociationService.AssociateWithAssignment(user, assignment);
m_userAssociationService.AssociateWithLocation(user, location);
}
return user;
}
}
class UserService: IUserService
{
public UserService(IUserDal userDal)
{
m_userDal = userDal;
}
IUserDal m_userDal;
public User GetByKey(int id)
{
if (id < 1) throw new ArgumentException("The User ID is invalid.");
User user = null;
using (var reader = m_userDal.GetByID(id))
{
if (reader.Read())
{
user = new User
{
UserID = reader.GetInt32(reader.GerOrdinal("id")),
Name = reader.GetString(reader.GetOrdinal("name")),
// ...
}
}
}
return user;
}
public User Insert(User user)
{
if (user == null) throw new ArgumentNullException("user");
user.ID = m_userDal.AddUser(user);
return user;
}
public User Update(User user)
{
if (user == null) throw new ArgumentNullException("user");
m_userDal.Update(user);
return user;
}
public void Delete(User user)
{
if (user == null) throw new ArgumentNullException("user");
m_userDal.Delete(user);
}
}
class UserAssociationService: IUserAssociationService
{
public UserAssociationService(IUserDal userDal, IAssignmentDal assignmentDal, ILocationDal locationDal)
{
m_userDal = userDal;
m_assignmentDal = assignmentDal;
m_locationDal = locationDal;
}
IUserDal m_userDal;
IAssignmentDal m_assignmentDal;
ILocationDal m_locationDal;
public Association FindByUser(User user)
{
if (user == null) throw new ArgumentNullException("user");
if (user.ID < 1) throw new ArgumentException("The user ID is invalid.");
Assignment assignment = null;
using (var reader = m_assignmentDal.GetByUserID(user.ID))
{
if (reader.Read())
{
assignment = new Assignment
{
ID = reader.GetInt32(reader.GetOrdinal("AssignmentID")),
// ...
};
return assignment;
}
}
}
}
class UserDal: IUserDal
{
public UserDal(DbConnection connection)
{
m_connection = connection;
}
DbConnection m_connection;
public User GetByKey(int id)
{
using (DbCommand command = connection.CreateCommand())
{
command.CommandText = "SELECT * FROM Users WHERE UserID = @UserID";
var param = command.Parameters.Add("@UserID", DbType.Int32);
param.Value = id;
var reader = command.ExecuteReader(CommandBehavior.SingleResult|CommandBehavior.SingleRow|CommandBehavior.CloseConnection);
return reader;
}
}
// ...
}
class AssignmentDal: IAssignmentDal
{
public AssignmentDal(DbConnection connection)
{
m_connection = connection;
}
DbConnection m_connection;
Assignment GetByUserID(int userID)
{
using (DbCommand command = connection.CreateCommand())
{
command.CommandText = "SELECT a.* FROM Assignments a JOIN Users u ON a.AssignmentID = u.AssignmentID WHERE u.UserID = @UserID";
var param = command.Parameters.Add("@UserID", DbType.Int32);
param.Value = id;
var reader = command.ExecuteReader(CommandBehavior.SingleResult|CommandBehavior.SingleRow|CommandBehavior.CloseConnection);
return reader;
}
}
// ...
}
// Implement other CRUD services similarly
Run Code Online (Sandbox Code Playgroud)
此架构产生的概念层和数据/对象流如下:
Task: UserManagementSvc
^
|
-------------------------------------------------
| | | |
Entity: UserSvc UserAssociationsSvc AssignmentSvc LocationSvc
^ ^ ^ ^
| | | |
--------- - -
| | |
Utility: UserDal AssignmentDal LocationDal
^ ^ ^
| | |
---------------------------------------------
|
DB: (SQL Database)
Run Code Online (Sandbox Code Playgroud)
关于组合和依赖关系,需要注意几个关键事项.通过添加UserManagementService并在其中组合实体服务,您可以实现以下目标:
如果您在设计和编写每个级别的服务时都非常小心,那么您可以提供许多不同的职责,复杂性和可组合性.应用程序不再是编写业务规则,而是编写部件以创建业务行为.如果需要编写一个部分,通常可以通过编写其他部分来编写,并可能添加少量的其他行为.构建应用程序变得更加简单,并且构建功能齐全,自包含,可重用的部件更容易,这些部件更易于单独测试,并且更易于部署.
您也将在最真实的意义上实现服务导向(无论如何,根据Thomas Erl),以及它的所有好处.;)
| 归档时间: |
|
| 查看次数: |
237 次 |
| 最近记录: |