From 67cfe41359f2f67a1b822b7123dfe09d889ff0f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=90=E6=B0=B8=E5=B7=9D?= Date: Fri, 26 Jun 2026 13:36:19 +0000 Subject: [PATCH] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6=20docs/doc?= =?UTF-8?q?s/framework=5Farchitecture-repository.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../docs/framework_architecture-repository.md | 339 ------------------ 1 file changed, 339 deletions(-) delete mode 100644 docs/docs/framework_architecture-repository.md diff --git a/docs/docs/framework_architecture-repository.md b/docs/docs/framework_architecture-repository.md deleted file mode 100644 index 8bb4c5c..0000000 --- a/docs/docs/framework_architecture-repository.md +++ /dev/null @@ -1,339 +0,0 @@ ---- -url: framework_architecture-repository ---- - -# Repository - -> **使用 Repository 辅助 Model**
- - -若将数据库逻辑都写在 model,会造成 model 的肥大而难以维护,基于 SOLID 原则,我们应该使用 Repository 模式辅助 model,将相关的数据库逻辑封装在不同的 repository,方便中大型项目的维护。 - - -## 数据库逻辑 - -在 CRUD 中,CUD 比较稳定,但 R 的部分则千变万化,大部分的数据库逻辑都在描述R 的部分,若将数据库逻辑写在 controller 或 model 都不适当,会造成 controller 与 model 肥大,造成日后难以维护。 - - -## Model - -如果使用 Eloquent ORM 来实现 Repository 模式,需要修改 model 不要包含数据库逻辑,仅保留以下部分: - -- Property : 如$table,$fillable…等。 -- Mutator: 包括 mutator 與 accessor。 -- Method : relation 類的 method,如使用 hasMany() 與 belongsTo()。 - -简化后的Eloquent 的 model 类我们可以称之为`Eloquent Class`,由于继承了`Illuminate\Database\Eloquent\Model` 类,所以`Eloquent Class`仍然有很多方法可以操作数据库。 - -Eloquent Class 代码结构如下: - -```php -namespace MyBlog; - -use Illuminate\Database\Eloquent\Model; -/** - * MyBlog\User - * - */ -class User extends Model { - - /** - * The database table used by the model. - * - * @var string - */ - protected $table = 'users'; - - /** - * The attributes that are mass assignable. - * - * @var array - */ - protected $fillable = ['name', 'email', 'password']; - - /** - * The attributes excluded from the model's JSON form. - * - * @var array - */ - protected $hidden = ['password', 'remember_token']; -} -``` - -而在 ECShopX 中,由于我们采用了 Doctrine ORM,其自带Repository模式。在 Doctrine ORM 中也有简化的 model 类: `Entity Class`。 - -相比 `Eloquent Class` `Entity Class` 更简单,其只包含 `protected` 或 `private`的属性和`getter` 和 `setter` 方法(在 JAVA 中,这种对象成为值对象)。 - -Entity Class 代码结构如下: - -```php - -## Repository - -初学者常会在 controller 直接调用 model 写数据库逻辑: - -```php -public function index() -{ - $users = User::where('age', '>', 20) - ->orderBy('age') - ->get(); - - return view('users.index', compact('users')); -} -``` - -数据库逻辑是`获取 20 岁以上的用户`。 - -在中大型项目中,会有几个问题 : - -- 将数据库逻辑写在 controller,造成 controller 的肥大难以维护。 -- 违反 SOLID 的单一职责原则 : 数据库逻辑不应该写在 controller。 -- controller 直接相依于model,使得我们无法对 controller 做单元测试。 - -比较好的方式是使用 repository : - -- 将 model 依赖注入到 repository。 -- 将数据库逻辑写在 repository。 -- 将 repository 依赖注入到 service。 - -以此原则,我们看下,采用 Eloquent ORM 如何使用 Repository 模式。 - -UserRepository.php - -```php -namespace MyBlog\Repositories; - -use Doctrine\Common\Collections\Collection; -use MyBlog\User; - -class UserRepository -{ - /** @var User 注入的User model */ - protected $user; - - /** - * UserRepository constructor. - * @param User $user - */ - public function __construct(User $user) - { - $this->user = $user; - } - - /** - * 返回年龄大于$age的用户 - * @param integer $age - * @return Collection - */ - public function getAgeLargerThan($age) - { - return $this->user - ->where('age', '>', $age) - ->orderBy('age') - ->get(); - } -} -``` - -第 8 行 - -```php -/** @var User 注入的User model */ -protected $user; - -/** - * UserRepository constructor. - * @param User $user - */ -public function __construct(User $user) -{ - $this->user = $user; -} -``` - -将依赖的 User model 依赖注入到 UserRepository。 - -UserController.php - -```php -userRepository = $userRepository; - } - - /** - * Display a listing of the resource. - * - * @return \Illuminate\Http\Response - */ - public function index() - { - $users = $this->userRepository - ->getAgeLargerThan(20); - - return view('users.index', compact('users')); - } -} -``` - -将依赖的 UserRepository 依赖注入到 UserController。 - -26行 - -```php -/** - * Display a listing of the resource. - * - * @return \Illuminate\Http\Response - */ -public function index() -{ - $users = $this->userRepository - ->getAgeLargerThan(20); - - return view('users.index', compact('users')); -} -``` - -从原本直接依赖 User model,改成依赖注入的 UserRepository。 - -改用这种写法,有几个优点: - -- 将数据库逻辑写在存储库中,解决控制器肥大问题。 -- 符合SOLID的单一职责原则:数据库逻辑写在repository,没写在controller。 -- 符合SOLID的依赖转换原则:controller 并非直接相依于存储库,而是将存储库依赖注入进controller。 - -> - -**实际上建议repository仅依赖注入于service,而不要直接注入在controller,本范例因为还没介绍到servie模式,以便简化起见,所以直接注入于controller**。
-
- -> - -**是否该建立存储库接口?**
- - -理论上使用依赖注入时,应该使用接口,不过接口目的在于通过抽象化,方便在后期更换接口的具体实现,以便让程序达到开放封闭的要求,但是实际上要更换存储库的机会不高,除非你有更换资料库的需求,如从MySQL抽换到MongoDB,此时就该建立存储库接口。 - -不过由于我们使用了依赖注入,将来要从类改成interface也很方便,只要在构造方法的类型提示改成interface即可,维护成本很低,所以在此大可使用的存储库类,用接口反而会造成设计过度,等真正需求来时再重构成接口即可。 - -采用 Doctrine ORM 如何使用 Repository 模式。 - -由于 Doctrine ORM 自带 Repository 模式,所以直接使用即可。 - -UserRepository.php - -```php -user - ->where('age', '>', $age) - ->orderBy('age') - ->get(); - } -} -``` - -UserController.php - -```php -namespace App\Http\Controllers; - -use App\Http\Requests; -use MyBlog\Repositories\UserRepository; - -class UserController extends Controller -{ - /** @var UserRepository 注入的UserRepository */ - protected $userRepository; - - /** - * UserController constructor. - * - * @param UserRepository $userRepository - */ - public function __construct(UserRepository $userRepository) - { - $this->userRepository = $userRepository; - } - - /** - * Display a listing of the resource. - * - * @return \Illuminate\Http\Response - */ - public function index() - { - $users = $this->userRepository - ->getAgeLargerThan(20); - - return view('users.index', compact('users')); - } -} -```