资源库模式(Repository)

目的

该模式通过提供集合风格的接口来访问领域对象,从而协调领域和数据映射层。 资料库模式封装了一组存储在数据存储器里的对象和操作它们的方面,这样子为数据持久化层提供了更加面向对象的视角。资料库模式同时也达到了领域层与数据映射层之间清晰分离,单向依赖的目的。

例子

  • Doctrine 2 ORM: 通过资料库协调实体和 DBAL,它包含检索对象的方法。
  • Laravel 框架

UML 图例

file

代码

你也可以在 GitHub 上查看此代码

Post.php

  1. <?php
  2. namespace DesignPatterns\More\Repository;
  3. class Post
  4. {
  5. /**
  6. * @var int|null
  7. */
  8. private $id;
  9. /**
  10. * @var string
  11. */
  12. private $title;
  13. /**
  14. * @var string
  15. */
  16. private $text;
  17. public static function fromState(array $state): Post
  18. {
  19. return new self(
  20. $state['id'],
  21. $state['title'],
  22. $state['text']
  23. );
  24. }
  25. /**
  26. * @param int|null $id
  27. * @param string $text
  28. * @param string $title
  29. */
  30. public function __construct($id, string $title, string $text)
  31. {
  32. $this->id = $id;
  33. $this->text = $text;
  34. $this->title = $title;
  35. }
  36. public function setId(int $id)
  37. {
  38. $this->id = $id;
  39. }
  40. public function getId(): int
  41. {
  42. return $this->id;
  43. }
  44. public function getText(): string
  45. {
  46. return $this->text;
  47. }
  48. public function getTitle(): string
  49. {
  50. return $this->title;
  51. }
  52. }

PostRepository.php

  1. <?php
  2. namespace DesignPatterns\More\Repository;
  3. /**
  4. * 这个类位于实体层(Post 类)和访问对象层(内存)之间。
  5. *
  6. * 资源库封装了存储在数据存储中的对象集以及他们的操作执行
  7. * 为持久层提供更加面向对象的视图
  8. *
  9. * 在域和数据映射层之间,资源库还支持实现完全分离和单向依赖的目标。
  10. *
  11. */
  12. class PostRepository
  13. {
  14. /**
  15. * @var MemoryStorage
  16. */
  17. private $persistence;
  18. public function __construct(MemoryStorage $persistence)
  19. {
  20. $this->persistence = $persistence;
  21. }
  22. public function findById(int $id): Post
  23. {
  24. $arrayData = $this->persistence->retrieve($id);
  25. if (is_null($arrayData)) {
  26. throw new \InvalidArgumentException(sprintf('Post with ID %d does not exist', $id));
  27. }
  28. return Post::fromState($arrayData);
  29. }
  30. public function save(Post $post)
  31. {
  32. $id = $this->persistence->persist([
  33. 'text' => $post->getText(),
  34. 'title' => $post->getTitle(),
  35. ]);
  36. $post->setId($id);
  37. }
  38. }

MemoryStorage.php

  1. <?php
  2. namespace DesignPatterns\More\Repository;
  3. class MemoryStorage
  4. {
  5. /**
  6. * @var array
  7. */
  8. private $data = [];
  9. /**
  10. * @var int
  11. */
  12. private $lastId = 0;
  13. public function persist(array $data): int
  14. {
  15. $this->lastId++;
  16. $data['id'] = $this->lastId;
  17. $this->data[$this->lastId] = $data;
  18. return $this->lastId;
  19. }
  20. public function retrieve(int $id): array
  21. {
  22. if (!isset($this->data[$id])) {
  23. throw new \OutOfRangeException(sprintf('No data found for ID %d', $id));
  24. }
  25. return $this->data[$id];
  26. }
  27. public function delete(int $id)
  28. {
  29. if (!isset($this->data[$id])) {
  30. throw new \OutOfRangeException(sprintf('No data found for ID %d', $id));
  31. }
  32. unset($this->data[$id]);
  33. }
  34. }

4.3.5. 测试

Tests/RepositoryTest.php

  1. <?php
  2. namespace DesignPatterns\More\Repository\Tests;
  3. use DesignPatterns\More\Repository\MemoryStorage;
  4. use DesignPatterns\More\Repository\Post;
  5. use DesignPatterns\More\Repository\PostRepository;
  6. use PHPUnit\Framework\TestCase;
  7. class RepositoryTest extends TestCase
  8. {
  9. public function testCanPersistAndFindPost()
  10. {
  11. $repository = new PostRepository(new MemoryStorage());
  12. $post = new Post(null, 'Repository Pattern', 'Design Patterns PHP');
  13. $repository->save($post);
  14. $this->assertEquals(1, $post->getId());
  15. $this->assertEquals($post->getId(), $repository->findById(1)->getId());
  16. }
  17. }