如何以正确的方式实现存储库模式?

时间:2017-01-20 15:29:09

标签: c# asp.net architecture repository-pattern

在为我的ASP.NET项目实现存储库模式时,我遇到了一些我无法理解的问题。所以我对如何以正确的方式实现存储库模式有几个问题。

根据我的经验,我认为只有在我的应用程序中,没有行为的类/模型,在他们的存储库旁边是不好的OOP。但是,这是我实现存储库模式的方式。我只是到处都需要一个存储库实例,来执行一些操作。这种方法的结果是我的所有域类都没有行为。

它们只是在没有方法的情况下保存数据的对象。我的老师告诉我,我正在使用薄模型,我应该努力制作胖模型。 为了回应这些反馈,我在课程中实现了一些业务逻辑,但我遇到了一些问题:

情境:

我的User课程中有一个包含用户对象的好友列表,用于表示某个用户的好友。当向用户添加新朋友时,域类方法检查"朋友"已存在于好友列表中。如果没有,他将被添加到列表中。需要将这些更改发送到数据库以保持持久性。

我知道这必须在每个域类的存储库中完成,但是对存储库方法的调用在哪里属于应用程序的体系结构?

现在我调用域类方法本身的存储库方法,以保持对数据库的更改:

public void AddFriend(User friend)
    {
        foreach(User f in Friends)
        {
            if(f.Username == friend.Username)
            {
                throw new Exception(String.Format("{0} is already a friend.", friend.Username));
            }
        }

        Friends.Add(friend);
        userRepo.AddFriend(this.Id, friend.Id);
    }

这是一个好方法吗,因为某种原因我认为不是。关于单元测试,我们需要使用这种方法进行一些依赖注入,它告诉我它不是一个独立的类(良好的可测试单元)。我读过一些人说他们使用额外的服务层或其他东西的帖子。我认为这里需要这种抽象,但某个服务层是怎样的?它是什么,哪些方法等?

我见过其他一些学生在域类中使用静态方法,它提供了添加新对象,更新对象,删除对象和获取所有对象等功能。

示例:

public class Tram
{
    private static TramRepository Repo = new TramRepository(new DBTram());

    public static void AddTram(int tramID, TramType type, int lineNr)
    {
        Tram tram = new Tram(tramID, type, TramStatus.depot, lineNr, true, null);
        Repo.AddTram(tram);
    }

    public static List<Tram> GetAll()
    { 
        Repo.GetAll();
    }
}

我发现在域类中将一个新实体添加到数据库中的方法是一个奇怪的事情,即该实体本身。同样对于GetAll()方法,我认为在类本身中拥有一个获取所有trams的方法是很奇怪的。所以电车对象可以获得所有电车。我认为这是实现存储库模式的一种奇怪方式。我是对的吗?

那么,这里需要什么样的抽象?是否需要额外的图层?如果是这样,这个层怎么样? (示例代码)或者我正在寻找错误的方向,是否有另一种解决方案可以解决使用存储库模式的单元测试问题?

我每次遇到这个架构问题,确保我需要回答它。

我发现很难清楚地解释这个问题,但我希望你们能理解它。

2 个答案:

答案 0 :(得分:2)

您的问题绝对正常,但不要期望找到绝对的答案。欢迎来到软件行业!

以下是我的意见:

  
      
  1. 拥有依赖于其存储库旁边只有模型/类的体系结构的应用程序是否良好?   保持没有行为的价值?
  2.   

我认为您尝试实现存储库模式,但是您错过了更高的架构视图。大多数应用程序至少在3层中分离:查看(演示),业务和数据访问。 存储库模式发生在DataAccess中,您可以在此处找到纯数据对象。 但是,此数据访问层由业务层使用,您可以在其中找到域模型,具有业务行为和数据的类。 单元测试工作必须在业务层中的域模型上。 这些测试不应该关心数据的存储方式。

  
      
  1. 我在哪里调用应用程序架构中的存储库方法?
  2.   

同样没有绝对的答案,但通常使用像商业服务这样的东西是有意义的。这些服务可以安排不同域对象之间的流,并加载,并将它们保存在存储库中。 这基本上就是你在AddFriend类中所做的,它属于一个业务层。

  

关于单元测试,我们需要这种方法有一定的依赖性   注射,它告诉我它不是一个独立的阶层

商业服务通常依赖于存储库,这是单元测试的常见情况。 Tram类可以保持业务行为并且仍然是独立的。 AddTram业务服务需要一个存储库,依赖注入允许无论如何都要测试它。

  
      
  1. 在数据库中插入,更新和删除新实体的方法是   他们本来应该上课吗?
  2.   

对于这个我可以清晰而响亮:请不要这样做,是的,CRUD操作属于Tram Repository。它当然不是商业逻辑。这就是为什么在你的例子中你需要两个不同层的两个类:

  • Tram可以是业务层中的业务对象(此处为No Crud操作)
  • TramRepository是需要存储Tram数据的对象(您将在其中找到CRUD操作)
  

&#34;因为我见过其他一些学生使用静态方法   在提供这些功能的域类中#34;

使用静态方法显然不是一个好主意,它意味着任何人都可以通过您的对象存储数据,即使它应该处理业务案例。同样,数据存储不是商业案例,而是技术必需品。

现在公平地说,所有这些概念都需要在上下文中进行讨论才有意义,并且需要在每个新项目上进行调整。这就是为什么你的工作既艰难又令人兴奋:背景为王。

我还写了一个以MVVM为中心的blog article,但我认为这有助于理解我的答案。

答案 1 :(得分:-1)

  

这种方法的结果是我的所有域类都没有行为。它们只是没有方法保存数据的对象。

     
      
  1. 拥有依赖于其存储库旁边只有模型/类的体系结构的应用程序是否良好?   保持没有行为的价值?
  2.   

当然不是,但这就是Web开发人员最近被教授的方式。

它支持20世纪70年代的旧模块化编程风格(静态类+对象中的数据)。
模块化编程引发了许多问题,因此他们发明了封装和面向对象的语言来解决它们。

只要您制作简单的网站,公开所有数据就会很好:

  • 加载数据
  • 显示数据
  • 保存数据

如果您需要复杂的行为,问题就会出现 - 那么您的数据实际上是软件实施的一部分,并且您将其公之于众!当有多个开发人员在同一个项目上工作时,这会导致严重的维护问题。

Web开发人员没有被教授OOP。他们正在学习一种简单的编程方式 - 将他们引向简单的网站(这是政府需要的)。

相关问题