Contract

简介

Laravel 中的 Contract 是一组定义了框架核心服务的接口。例如,Illuminate\Contracts\Queue\Queue contract 定义了实现队列任务所需实现的方法,而 Illuminate\Contracts\Mail\Mailer contract 定义了发送邮件所需要实现的方法。

框架为每个 contract 都提供了一个相对应的实现。例如,Laravel 为队列提供了各种驱动的实现,以及基于 SwiftMailer 对邮件功能的实现。

Laravel 所自带的所有 contract 都有自己的 GitHub 仓库。除了方便列出所有可用的 contract 外,也可以作为独立、解耦的工具包供其他开发者使用。

Contract Vs. Facade

Laravel 中的 facades 提供了一个简单的方法来使用 Laravel 自带的服务(service),而不需要使用使用类型提示(type-hint)和在服务容器(service container)之外解析 contract。然而,使用 contract 可以明确地为类定义其依赖。对于大部分应用程序而放眼,使用 facade 就足够了。然而,如果你需要更多的低耦合,contract 就适合你了,你可以继续往下看了解更多!

为什么使用 Contract ?

你可能对于 contract 还有很多疑问。为什么要使用接口(interface)?使用接口会不会更复杂了?接下来列出的两个标题能够解释这个问题:低耦合和简单性。

低耦合

首先,我们来看一下这段和缓存功能的实现具有强耦合的代码。如下:

<?php

namespace App\Orders;

class Repository
{
/**
* The cache.
*/
protected $cache; /**
* Create a new repository instance.
*
* @param \SomePackage\Cache\Memcached $cache
* @return void
*/
public function __construct(\SomePackage\Cache\Memcached $cache)
{
$this->cache = $cache;
} /**
* Retrieve an Order by ID.
*
* @param int $id
* @return Order
*/
public function find($id)
{
if ($this->cache->has($id)) {
//
}
}
}

在这个类中,代码和缓存功能的实现之间是强耦合的。因为它依赖第三方工具包中定义的缓存类。如果这个第三方工具包的 API 改变了,我们的代码也要跟着变。

同样的,如果我们希望用另一项技术(Redis)来替换掉现在所用的(Memcached),我们必须修改代码。我们所定义的类不应该依赖是谁提供了数据以及如何提供的等等细节。

比起上面代码中的做法,我们的代码应该依赖一个简单、不依赖第三方实现细节的接口:

<?php

namespace App\Orders;

use Illuminate\Contracts\Cache\Repository as Cache;

class Repository
{
/**
* Create a new repository instance.
*
* @param Cache $cache
* @return void
*/
public function __construct(Cache $cache)
{
$this->cache = $cache;
}
}

现在,上面的代码已经不再和具体的第三方代码甚至是 Laravel 有任何耦合了。由于 contract 工具包不包含任何实现,也不依赖其他工具包,你可以很方便地为任何 contract 创造一个实现,甚至在不需要修改任何涉及到调用缓存的代码的情况下替换为你自己的缓存实现。

简单性

当所有的 Laravel 服务(service)都通过简洁的接口进行定义,就能够很容易地确定这个服务提供的是什么功能了。可以将 contract 视为框架所提供的简洁明了的说明文档。

另外,当你依赖一个简单清晰的接口时,你的代码能够被别人轻松的理解并维护。比起在一个冗长、复杂的类中追踪哪些方法可用来说,你所面对的将是一个简洁、干净的接口。

Contract 索引

下面列出的是大部分 Laravel Contract 的索引文件,以及对应的 "facade" :

Contract 对应的Facade
Illuminate\Contracts\Auth\Guard Auth
Illuminate\Contracts\Auth\PasswordBroker Password
Illuminate\Contracts\Bus\Dispatcher Bus
Illuminate\Contracts\Broadcasting\Broadcaster  
Illuminate\Contracts\Cache\Repository Cache
Illuminate\Contracts\Cache\Factory Cache: driver()
Illuminate\Contracts\Config\Repository Config
Illuminate\Contracts\Container\Container App
Illuminate\Contracts\Cookie\Factory Cookie
Illuminate\Contracts\Cookie\QueueingFactory Cookie::queue()
Illuminate\Contracts\Encrption\Encrypter Crypt
Illuminate\Contracts\Events\Dispatcher Event
Illuminate\Contracts\Filesystem\Cloud  
Illuminate\Contracts\Filesystem\Factory File
Illuminate\Contracts\Filesystem\Filesystem File
Illuminate\Contracts\Foundation\Application App
Illuminate\Contracts\Hashing\Hasher Hash
Illluminate\Contracts\Logging\Log Log
Illuminate\Contracts\Mail\MailQueue Mail::queue()
Illuminate\Contracts\queue\Factory Queue:: driver()
Illuminate\Contracts\Queue\Queue Queue
Illuminate\Contracts\Redis\Database Redis
Illuminate\Contracts\Routing\Registar Route
Illuminate\Contracts/Routing\Responsefactory Response
Illuminate\Contracts\Routing\UrlGenerator URL
Illuminate\Contracts\Support\Arrayable  
Illuminate\Contracts\Support\Jsonable  
Illuminate\Contracts\Support\Renderable  
Illuminate\Contracts\Validation\Factory Validator::make()
Illuminate\Contracts\Validation\Validator  
Illuminate\Contracts\View\Factory View::make()
Illuminate\Contracts\View\View  

 

 

如何使用 Contract

那么,如何实例化一个 contract 呢?其实很简单。

Laravel 中的很多类都是由 服务容器 来解析的,包括控制器、事件监听器、中间件、队列任务,甚至路由闭包(route closure)。因此,要实例化一个 contract,你可以在,类的构造函数中加入“类型提示(type-hint)”。

例如,请看下面的事件监听器:

<?php

namespace App\Listeners;

use App\User;
use App\Events\NewUserRegistered;
use Illuminate\Contracts\Redis\Database; class CacheUserInformation
{
/**
* The Redis database implementation.
*/
protected $redis; /**
* Create a new event handler instance.
*
* @param Database $redis
* @return void
*/
public function __construct(Database $redis)
{
$this->redis = $redis;
} /**
* Handle the event.
*
* @param NewUserRegistered $event
* @return void
*/
public function handle(NewUserRegistered $event)
{
//
}
}

当事件监听器被解析的时候,服务容器将会读取构造函数的类型提示(type-hint),并注入适当的值。关于如何向服务容器注册,请参考此文档

Laravel5.1学习笔记13 系统架构5 Contract的更多相关文章

  1. Laravel5.1学习笔记i14 系统架构6 Facade

    Facades 介绍  使用 Facades Facade 类参考   #介绍 Facades provide a "static" interface to classes th ...

  2. Laravel5.1学习笔记12 系统架构4 服务容器

    Service Container 介绍 绑定的用法  绑定实例到接口 上下文绑定 标签 解析 容器事件 #介绍 The Laravel service container is a powerful ...

  3. Laravel5.1学习笔记11 系统架构3 服务提供者

    服务提供者 简介 写一个服务提供者 Register注册方法 Boot 方法 注册提供者 缓载提供者 简介 Service providers are the central place of all ...

  4. Laravel5.1学习笔记10 系统架构2 应用程序结构

    应用程序结构 简介 根目录 App 目录 为应用程序设置命名空间 简介 默认的 Laravel 应用程序结构是为了给无论构建大型还是小型应用程序都提供一个良好的开始.当然,你可以依照喜好自由地组织应用 ...

  5. Laravel5.1学习笔记9 系统架构1 请求生命周期 (待修)

    Request Lifecycle Introduction Lifecycle Overview Focus On Service Providers Introduction When using ...

  6. ODI学习笔记2--ODI产品架构

    ODI学习笔记2--ODI产品架构 ODI产品架构: ODI提供了以下几种管理工具:Designer 用于定义数据转换逻辑,这是最常用的开发工具,大部分的开发任务,包括data store的定义,in ...

  7. SQL反模式学习笔记13 使用索引

    目标:优化性能 改善性能最好的技术就是在数据库中合理地使用索引.  索引也是数据结构,它能使数据库将指定列中的某个值快速定位在相应的行. 反模式:无规划的使用索引 1.不使用索引或索引不足 2.使用了 ...

  8. springmvc学习笔记(13)-springmvc注解开发之集合类型參数绑定

    springmvc学习笔记(13)-springmvc注解开发之集合类型參数绑定 标签: springmvc springmvc学习笔记13-springmvc注解开发之集合类型參数绑定 数组绑定 需 ...

  9. Ext.Net学习笔记13:Ext.Net GridPanel Sorter用法

    Ext.Net学习笔记13:Ext.Net GridPanel Sorter用法 这篇笔记将介绍如何使用Ext.Net GridPanel 中使用Sorter. 默认情况下,Ext.Net GridP ...

随机推荐

  1. nyoj_116_士兵杀敌(二)_201404131107

    士兵杀敌(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:5   描述 南将军手下有N个士兵,分别编号1到N,这些士兵的杀敌数都是已知的. 小工是南将军手下的军师,南将军经常 ...

  2. Ubuntu 16.04下轻量级文件搜索工具Catfish

    Catfish搜索文件速度快,但是不支持正则表达式. 安装: sudo add-apt-repository ppa:catfish-search/ppa sudo apt-get update su ...

  3. springMvc把client传过来一个String类型,转换为日期类型为例

    springMvc--接受日期类型参数处理   目录 步骤 2.自定义类型转换规则 3.注册自定义的类型转换类 4.地址栏访问 这个问题,也即是springMvc如何进行参数类型的转换 , 以把cli ...

  4. Centos: Screen tips

    Install yum install screen Useful screen commands List a particular users screen sessions: screen -l ...

  5. 问答:怎样规划CSS 中 的命名方式 怎样看待 CSS 中 BEM 的命名方式?

    好多盆友 非常纠结 css命名规则 怎么弄,还没起步就被绊住了.那么今天蝈蝈就针对这个问题来讨论一下 没什么技术 含量.但却对效率开发至关重要的 "问题". 下文是一些知乎大神的个 ...

  6. Java序列化之readObjectNoData、readResolve方法

    Java序列化之readObjectNoData.readResolve方法 学习了:http://vyloy.iteye.com/blog/1240663 readResolve方法会在Object ...

  7. iOS开发之剖析&quot;秘密&quot;App内容页面效果(一)

    近期在玩"秘密",发现点击主界面的Cell进去后的页面效果不错,就写了个Demo来演示下. 它主要效果:下拉头部视图放大,上拉视图模糊并且到一定位置固定不动,其它Cell能够继续上 ...

  8. Python类私有方法的陷阱

    引言 Python不像C++.Java.C#等有明白的公共.私有或受保护的keyword来定义成员函数或属性,它使用约定的单下划线"_"和"__"双下划线作为函 ...

  9. wordpress 配置(ubuntu)---修改 linux hostname

    使用阿里云服务器的 ubuntu 系统时的 hostname 太扭曲,而且有些命令会受 hostname 的影响不能正常使用,所以,一定要改掉它! 永久修改 hostname: 使用 nano 命令: ...

  10. [DB][MySql]关于取得自增字段的值、及@@IDENTITY 与并发性问题

    对于刚从Oracle转向MySql的人都会为,MySql中没有Oracle里的Sequence而感到困惑.MySql中没有了Sequence,那么MySql的主键用什么方式来实现最好呢? 主要有下面几 ...