典型 3 层业务层中的静态方法与实例方法
Static method vs. instance method in typical 3-tier business layer
目前,我正在使用 ASP.NET MVC 构建一个典型的 3 层 Web 应用程序。我已经使用依赖注入 (Autofac) 进行设置,如下所示:
public class UserController : BaseController
{
private readonly IUserService _userService;
public UserController(IUserService userService)
{
this._userService = userService;
}
}
public class IUserService
{
void InsertUser(User user);
void UpdateUser(User user);
void DeleteUser(User user);
}
public class UserService : IUserService
{
private readonly IRepository<User> _userRepository;
public UserService(IRepository<User> userRepository)
{
this._userRepository = userRepository;
}
public void InsertUser(User user)
{
_userRepository.Insert(user);
}
public void UpdateUser(User user)
{
_userRepository.Update(user);
}
public void DeleteUser(User user)
{
_userRepository.Delete(user);
}
}
Repository 是一个典型的使用 EF 的通用存储库。
public interface IRepository<T> where T : BaseEntity
{
void Insert(T entity);
void Update(T entity);
void Delete(T entity);
}
问题是我的应用程序有很多实体,对于每个实体,我必须在服务层中为 CRUD 操作复制上述代码。例如:对于实体 "Role",我有 "InsertRole"、"UpdateRole"、"DeleteRole"... 以及更多其他实体。
因此,我尝试通过使用如下静态方法将 CRUD 操作提取到静态 CLASS "CommonService" 来重构以删除重复代码:
public static class CommonService
{
public static void Insert<T>(T entity) where T : BaseEntity
{
var repository = EngineContext.Current.Resolve<IRepository<T>>();
repository.Insert(entity);
}
public static void Update<T>(T entity) where T : BaseEntity
{
var repository = EngineContext.Current.Resolve<IRepository<T>>();
repository.Update(entity);
}
public static void Delete<T>(T entity) where T : BaseEntity
{
var repository = EngineContext.Current.Resolve<IRepository<T>>();
repository.Delete(entity);
}
}
有了这个 class,我将删除服务中用于 CRUD 操作的重复代码。
在 Controller 中,我只调用 CommonService.Insert(user);...
现在对我真的很好。我还有其他正常的服务方法,并且没有重复的 CRUD。
但我想知道这种方法是否有任何缺点,除了单元测试(我不会对 CRUD 进行单元测试)。 Web 环境(ASP.NET MVC)中的内存管理和并发处理有什么问题吗?
我还没有使用 EF 实现数据处理的并发机制(同时更新一个实体...)
提前致谢!
MillDol.
如果您决定保留该静态实现,请创建一个使用它的接口和代理 class,您仍然可以对使用它的实现进行单元测试。您不想丢弃单元测试。
public interface ICommonService<T>
{
void Insert<T>(T entity);
void Update<T>(T entity);
void Delete<T>(T entity);
}
并实现一个简单的代理类型,它实现 ICommonService<T>
并将调用转发到静态 class。然后你可以依赖 ICommonService<T>
并在以后模拟它是测试,就像你以前一样。
我不会有静态 class。我不认识 EngineContext.Current
,但它看起来像服务定位器模式。这通常是不鼓励的,因为它隐藏了你所依赖的明显检查。
你仍然可以有一个像 ICommonService<T>
这样的通用接口,然后实现依赖于 IRepository<T>
、
的代理
public class CommonService<T> : ICommonService<T> where T : BaseEntity
{
private readonly IRepository<T> repository;
public CommonService(IRepository<T> repository)
{
if (repository == null) throw new ArgumentNullException(nameof(repository));
this.repository = repository;
}
// and other methods
}
然后你可以让你的控制器依赖于 ICommonService
,你不必在幕后调用静态方法。
我知道这已经很老了,但刚遇到这个,我想知道你为什么不直接采用静态实现并使其成为抽象的 class - 类似于 BaseService。
这样您就可以实现您的方法,以删除您提到的所有重复代码,但如果任何特定实体需要任何特殊处理,您仍然可以在每个特定服务实现中处理它。
目前,我正在使用 ASP.NET MVC 构建一个典型的 3 层 Web 应用程序。我已经使用依赖注入 (Autofac) 进行设置,如下所示:
public class UserController : BaseController
{
private readonly IUserService _userService;
public UserController(IUserService userService)
{
this._userService = userService;
}
}
public class IUserService
{
void InsertUser(User user);
void UpdateUser(User user);
void DeleteUser(User user);
}
public class UserService : IUserService
{
private readonly IRepository<User> _userRepository;
public UserService(IRepository<User> userRepository)
{
this._userRepository = userRepository;
}
public void InsertUser(User user)
{
_userRepository.Insert(user);
}
public void UpdateUser(User user)
{
_userRepository.Update(user);
}
public void DeleteUser(User user)
{
_userRepository.Delete(user);
}
}
Repository 是一个典型的使用 EF 的通用存储库。
public interface IRepository<T> where T : BaseEntity
{
void Insert(T entity);
void Update(T entity);
void Delete(T entity);
}
问题是我的应用程序有很多实体,对于每个实体,我必须在服务层中为 CRUD 操作复制上述代码。例如:对于实体 "Role",我有 "InsertRole"、"UpdateRole"、"DeleteRole"... 以及更多其他实体。 因此,我尝试通过使用如下静态方法将 CRUD 操作提取到静态 CLASS "CommonService" 来重构以删除重复代码:
public static class CommonService
{
public static void Insert<T>(T entity) where T : BaseEntity
{
var repository = EngineContext.Current.Resolve<IRepository<T>>();
repository.Insert(entity);
}
public static void Update<T>(T entity) where T : BaseEntity
{
var repository = EngineContext.Current.Resolve<IRepository<T>>();
repository.Update(entity);
}
public static void Delete<T>(T entity) where T : BaseEntity
{
var repository = EngineContext.Current.Resolve<IRepository<T>>();
repository.Delete(entity);
}
}
有了这个 class,我将删除服务中用于 CRUD 操作的重复代码。 在 Controller 中,我只调用 CommonService.Insert(user);... 现在对我真的很好。我还有其他正常的服务方法,并且没有重复的 CRUD。 但我想知道这种方法是否有任何缺点,除了单元测试(我不会对 CRUD 进行单元测试)。 Web 环境(ASP.NET MVC)中的内存管理和并发处理有什么问题吗? 我还没有使用 EF 实现数据处理的并发机制(同时更新一个实体...)
提前致谢! MillDol.
如果您决定保留该静态实现,请创建一个使用它的接口和代理 class,您仍然可以对使用它的实现进行单元测试。您不想丢弃单元测试。
public interface ICommonService<T>
{
void Insert<T>(T entity);
void Update<T>(T entity);
void Delete<T>(T entity);
}
并实现一个简单的代理类型,它实现 ICommonService<T>
并将调用转发到静态 class。然后你可以依赖 ICommonService<T>
并在以后模拟它是测试,就像你以前一样。
我不会有静态 class。我不认识 EngineContext.Current
,但它看起来像服务定位器模式。这通常是不鼓励的,因为它隐藏了你所依赖的明显检查。
你仍然可以有一个像 ICommonService<T>
这样的通用接口,然后实现依赖于 IRepository<T>
、
public class CommonService<T> : ICommonService<T> where T : BaseEntity
{
private readonly IRepository<T> repository;
public CommonService(IRepository<T> repository)
{
if (repository == null) throw new ArgumentNullException(nameof(repository));
this.repository = repository;
}
// and other methods
}
然后你可以让你的控制器依赖于 ICommonService
,你不必在幕后调用静态方法。
我知道这已经很老了,但刚遇到这个,我想知道你为什么不直接采用静态实现并使其成为抽象的 class - 类似于 BaseService。 这样您就可以实现您的方法,以删除您提到的所有重复代码,但如果任何特定实体需要任何特殊处理,您仍然可以在每个特定服务实现中处理它。