服务类是否应该不仅仅是存储库类的包装器?

时间:2010-08-18 17:55:21

标签: design-patterns service repository

我理解直接从表示代码使用数据访问例程被认为是邪恶的。所以我有一个单独的Repositories项目,以及一个Services项目。据我所知,服务层的典型用途是将数据访问与表示隔离开来。一切都很好。

我有一个非常简单的域,只是一个Movie类。匹配的存储库接口是:

public interface IMovieRepository
{
    void AddMovie(Movie movie);
    void UpdateMovie(Movie movie);
    void RemoveMovie(Movie movie);
    int GetMovieCount();
    Movie GetMovieById(int id);
    IEnumerable<Movie> GetAllMovies();
    IEnumerable<Movie> GetMoviesByGenre(Genre genre);
    IEnumerable<Movie> GetMoviesByYear(int year);
    IEnumerable<Movie> GetMoviesByActor(string actor);
    IEnumerable<Movie> GetMoviesByTitle(string title);
}

现在当我到服务类使用存储库时,我最终定义了一个这样的接口:

public interface IMovieService
{
    Movie CreateMovie(string title, int year, Genre genre, int length, IEnumerable<string> actors);
    void UpdateMovie(Movie movie);
    void RemoveMovie(Movie movie);
    int GetMovieCount();
    Movie GetMovieById(int id);
    IEnumerable<Movie> GetAllMovies();
    IEnumerable<Movie> GetMoviesByGenre(Genre genre);
    IEnumerable<Movie> GetMoviesByYear(int year);
    IEnumerable<Movie> GetMoviesByActor(string actor);
    IEnumerable<Movie> GetMoviesByTitle(string title);
}

这两个接口非常相似,这让我很奇怪。我希望IMovieService实现在内部使用IMovieRepository实现,基本上是后者的薄包装。可能有一些验证或缓存等,但前者似乎在大多数情况下会简单地传递给后者。

我是以正确的方式做到这一点,还是我缺少一些东西?

我知道对于这样一个简单的域名来说似乎有点过分,但我正试图确定分层和抽象的模式,以便在未来和更大的项目中使用。

编辑:要更清楚一点,我不是在谈论NHibernate或存储库模式,而是关注关注层次。

更新:感谢大家。我相信我会在服务类上保留特定的查询方法,对UI层很简单,并尝试通过将查询传递给查询函数来概括存储库。

4 个答案:

答案 0 :(得分:4)

我认为你是正确的。您的DataAccess API和ServiceAPI看起来如此相似的原因是您还没有为您的服务提供任何真正的业务逻辑。这里有一些可能最终出现在您的服务API上的头脑风暴,但是涉及一些比简单的CRUD(创建,读取,更新,删除)功能更复杂的操作。显然这些只是快速而肮脏的例子,但我相信你明白了这个想法:

  • RecommendMovieToFriend(int movieID,string friendEmail);
  • RateMovie(int movieID,int numberOfStars);
  • AddMovieToMyWishList(int movieID,int userID);

我认为ServiceLayer和DataLayer的分离是一个重要且有价值的分离,你不应该猜它,即使这两个API目前非常相似。随着服务功能的增长,这两个API将继续发散,以满足其呼叫者的需求。

答案 1 :(得分:1)

让Service类简单地包装存储库是IMO不必要的复杂性。

我通常最终在服务层中使用bool Try ...方法(TrySave,TryDelete等)(如果我有),然后将错误消息添加为out-parameters。我只让Repositories处理持久性问题 - 将它放入和移出存储库。

至于查询 - 除非我有以UI为中心的复杂过滤器对象需要在它们到达存储库之前进行“翻译”,否则我不会通过我的服务。

希望这有帮助!

答案 2 :(得分:1)

我通常喜欢在我的服务类中放置更复杂的查询。调用一些存储库方法然后使用其他Linq to Object方法来生成所需数据集的那些。

答案 3 :(得分:0)

根据您定义的IMovieRepository接口,IMovieService接口是多余的。如果存储库接口是通用的,如下所示,那么服务接口就有价值。我更喜欢更简单的存储库接口,因为对我来说它提供了更好的关注点分离

public interface IRepository<T> {
    IQueryable<T> Fetch();
    void Save(T item);
    void Remove(T item);
}