仓库模式 —— Repository Pattern

在上一篇文章《laravel/lumen —— 面向接口编程》中,举了个RedisConfig的栗子,涉及到了仓库模式这个概念,但是还不够深入。现在特别再写一篇来讲述仓库模式的使用方式以及优势。

Repository 模式主要思想是建立一个数据操作代理层,把controller里的数据操作剥离出来,这样做有几个好处:

  • 把数据处理逻辑分离使得代码更容易维护
  • 数据处理逻辑和业务逻辑分离,可以对这两个代码分别进行测试
  • 减少代码重复
  • 降低代码出错的几率
  • controller代码的可读性大大提高

以下演示时基于lumen框架的。

一般我们都会在controller中回去数据,然后处理展示到页面。如下:

但是这段代码有几个问题:

  1. 控制层与数据层耦合
  2. 严重依赖Model
  3. 无法写单元测试

所谓控制层与数据层耦合就是目前数据来源是本地数据库,如果将来该成服务化了,数据来源将会是远程服务,这个时候我们就不得不改写这个控制层。那么久违反了开闭原则。

严重依赖Model的意思就是,如果控制层和Model由2个开发人员开发,那么控制层不得不等待Model的完成才能继续工作。

由于数据严重依赖Model层,所以无法写出各种数据格式的单元测试来进行测试。

好的单元测试时重构的基础。也就无法进行重构。

接下来我们就引入仓库模式来进行改造。这里我们会借助一些laravel/lumen框架的基本特性,比如说:服务容器,依赖注入。如果你对这些不熟悉,那么请先进行了解。

第一步:完成“仓库”

我们在app目录下建立仓库文件夹。

  • app
    • Repositories
      • Interfaces
      • Instances

Interfaces里面是“面向接口编程”的接口,Instances里面是实现接口的类。

记下来我们编码工作。先写一个ContentRepositoryInterface的接口,建立规范。
再写3个类ContentLocalRepositoryContentHttpRepository以及ContentCustomerRepository,表示三个不同数据来源:本地、远程HTTP以及自定义数据。

第二步:服务注册

1、写一个服务提供者

2、 添加到bootstrap\app.php

第三步:改造源代码

接下来我们可以正常访问了。目前在服务提供者中,注册的是ContentLocalRepository。本地获取数据。如果说Model层还未完成,我们可以切换到ContentCustomerRepository自定义数据。将来做了服务化,可以切换到ContentHttpRepository获取数据。

着一些只需要东一行代码就可以完成。完全符合开闭原则,解耦了代码,并且使得代码职责明确,容易阅读。

关于单元测试我们可以用mockery/mockery插件,模拟各种操作,来进行生产数据。

composer安装mockery/mockery

编写单元测试

使用phpunit进行测试