博客列表 >5.28 谈谈对容器注入的理解以及门面Facade的认识

5.28 谈谈对容器注入的理解以及门面Facade的认识

Allen的php博客
Allen的php博客原创
2018年05月29日 16:37:55885浏览

在实现用户登录功能时,使用普通的new对象方法使工作类(User)对工具类(Db,Validate,View)产生了严重的依赖关系及耦合问题。虽然可以使用依赖注入解决耦合问题,但必须要对工具类的方法或参数了解,很容易造成意想不到的问题出现。

容器注入可以最大限度的简化外部对象调用,即创建容器、服务注册、容器依赖,但容器依赖必须使用User()工作类进行调用,灵活性不高。因此使用facade门面外观模式与容器注入相结合,即对调用者来说,他不需要事先知道工作类(User)中具体操作是哪个类中,只需要调用Facade即可完成操作,并且facade门面静态化方法较纯容器注入代码执行效率更高。

实例代码如下:

〓 依赖容器

◇ 创建Demo1.php:普通的new对象方法

<?php

/**

* 用户登录

* 1. 涉及到三个操作:链接数据、数据验证、模板输出

* 2. 创建三个类:Db,validate,view:这三个类是工具类

* 3. User类负责调用工具类,实现用户登录:是工作类

*/

//数据库链接类

class Db

{

//数据连接

public function connect()

{

return '数据库链接成功!<br>';

}

}


//数据验证类

class Validate

{

//数据验证

public function check()

{

return '数据验证成功!<br>';

}

}


//视图类

class View

{

//内容输出

public function display()

{

return '用户登录成功!<br>';

}

}



//用户类:工作类

class User

{

//登录操作

public function login()

{

//实例化Db类,并调用connect()方法,连接数据库

$db = new Db();

echo $db->connect();


//实例化Validate类,并调用check()方法,验证数据

$validate = new Validate();

echo $validate->check();


//实例化View类,并调用display()方法,完成用户登录

$view = new View();

echo $view->display();


}

}


//客户端进行调用

//实例化User类

$user = new User();

echo $user->login();



//工作类User对三个工具类:Db,Validate,View产生了严重的依赖,并且要求不仅要对User类熟悉,还要对工具类十分了解,这种耦合如何解耦?



◇ 创建Demo2.php:依赖注入解耦


<?php

/**

 * 使用依赖注入来进行解耦:DI

 * 对工具类(Db,Validate,View)的实例化不要在工作类(User)中完成,应在客户端完成

 * 在工作类中必须要有接收器,来保存工具类的实例

 * 将工作类依赖的对象,以方法参数的方式注入到当前的类中

 */


//数据库链接类

class Db

{

//数据连接

public function connect()

{

return '数据库链接成功!<br>';

}

}


//数据验证类

class Validate

{

//数据验证

public function check()

{

return '数据验证成功!<br>';

}

}


//视图类

class View

{

//内容输出

public function display()

{

return '用户登录成功!<br>';

}

}



//用户类:工作类

class User

{

//创建三个接收器,成员属性

protected $db = null; //保存数据对象

protected $validate = null; //保存数据验证对象

protected $view = null; //保存视图对象


//登录操作

public function login(Db $db, Validate $validate, View $view)

{

//实例化Db类,并调用connect()方法,连接数据库

echo $db->connect();


//实例化Validate类,并调用check()方法,验证数据

echo $validate->check();


//实例化View类,并调用display()方法,完成用户登录

echo $view->display();


}

}


//客户端进行调用

//将工具类在客户端全部实例化

$db = new Db();

$validate = new Validate();

$view = new View();


////实例化User类

$user = new User();

echo '<h2>用依赖注入完成解耦</h2>';

echo $user->login($db,$validate,$view);


/**

 * 依赖注入仍然要求在客户端进行类的实例化

 * 遗留问题:还是无法解决对工具类需要十分了解的问题

 * 期望:能不能把这个调用者的实例化过程也省略掉,我们只要给出一个类名,以及如何去实例化这个类就可以了,其他工作一概不管

 * 解决办法:用容器来实现统一注入,文件在Demo3.php

 */


◇ 创建Demo3.php:容器依赖解耦


<?php

/**

 * 容易:也叫服务容器(IOC)

 * 基本思路:拿来就用,最大限度简化外部对象调用,类似于 即插即用

 * 基本实现分三步:

 * 1. 创建容器:本质就是将一个类与他的实现绑定到一个关联数组;

 * 2. 服务注册:初始化这个关联数组,将工具类绑定到容器中;

 * 3. 容器依赖:也叫依赖容器,调用的时候直接传一个容器对象,不用再一个一个传具体对象

 */


//数据库链接类

class Db

{

//数据连接

public function connect()

{

return '数据库链接成功!<br>';

}

}


//数据验证类

class Validate

{

//数据验证

public function check()

{

return '数据验证成功!<br>';

}

}


//视图类

class View

{

//内容输出

public function display()

{

return '用户登录成功!<br>';

}

}


//1. 创建容器

class Container

{

//创建一个空数组,用来保存工具类及实现方法

protected $instance = [];


//将需要实例化的类与它的实现方法进行绑定

public function bind($abstract, Closure $process)

{

$this->instance[$abstract] = $process;

}


//创建特定类的实例

public function make($abstract, $process=[])

{

return call_user_func_array($this->instance[$abstract], []); //执行对象方法

}


}


//2. 服务注册:就是调用容器的bind()将对象(对象===实例)注册到容器中

$container = new Container();


//将Db类绑定到容器中

$container->bind('Db', function(){

return new Db();

});


//将Validate类绑定到容器中

$container->bind('Validate', function(){

return new Validate();

});


//将View类绑定到容器中

$container->bind('View', function(){

return new View();

});


// var_dump($container->instance);die(); //查看容器的instance属性,测试是否成功


//3. 容器依赖:所有用到的对象,以容器的方式,注入到当前的工作类中

//用户类:工作类

class User

{

public function login(Container $container)

{

//$container->make('Db')实例化Db类创建Db对象

echo $container->make('Db')->connect();

echo $container->make('Validate')->check();

echo $container->make('View')->display();

}

}


//控制台调用方法

$user = new User();

echo '<h2>用依赖容器实现解耦</h2>';

echo $user->login($container);


//问题遗留:容器依赖必须使用User()工作类进行调用,我们用facade门面模式进行简化,见Demo4.php



〓 Facade门面外观模式



◇ 创建Demo4.php和Container.php:容器依赖结合facade解耦


Demo4.php-----------------------------------------------------


<?php

/**

 * facade:门面模式,也叫外观模式

 * 就是将一些操作进行封装,对外提供一个统一的接口

 * facade模式与容器依赖是黄金搭档

 */

require 'Container.php'; //导入容器


/**

 * Facade类实现三个功能

 * 1. 链接数据库

 * 2. 数据验证

 * 3. 输出提示

 * 对于调用者来说,他不需要实现知道这三个操作在哪个具体的类中,他只需要调用Facade就可以执行以上三个操作

 */


class Facade

{

// 1. 链接数据库

public static function connect(Container $container)

{

return $container->make('Db')->connect();

}


// 2. 数据验证

public static function check(Container $container)

{

return $container->make('Validate')->check();

}


// 3. 输出提示

public static function display(Container $container)

{

return $container->make('View')->display();

}


}


//客户端调用

echo '<h2>用facade门面外观模式统一调用User类</h2>';

echo Facade::connect($container);

echo Facade::check($container);

echo Facade::display($container);


Container.php----------------------------------------------------


<?php

/**

 * 容易:也叫服务容器(IOC)

 * 基本思路:拿来就用,最大限度简化外部对象调用,类似于 即插即用

 * 基本实现分三步:

 * 1. 创建容器:本质就是将一个类与他的实现绑定到一个关联数组;

 * 2. 服务注册:初始化这个关联数组,将工具类绑定到容器中;

 * 3. 容器依赖:也叫依赖容器,调用的时候直接传一个容器对象,不用再一个一个传具体对象

 */


//数据库链接类

class Db

{

//数据连接

public function connect()

{

return '数据库链接成功!<br>';

}

}


//数据验证类

class Validate

{

//数据验证

public function check()

{

return '数据验证成功!<br>';

}

}


//视图类

class View

{

//内容输出

public function display()

{

return '用户登录成功!<br>';

}

}


//1. 创建容器

class Container

{

//创建一个空数组,用来保存工具类及实现方法

protected $instance = [];


//将需要实例化的类与它的实现方法进行绑定

public function bind($abstract, Closure $process)

{

$this->instance[$abstract] = $process;

}


//创建特定类的实例

public function make($abstract, $process=[])

{

return call_user_func_array($this->instance[$abstract], []); //执行对象方法

}


}


//2. 服务注册:就是调用容器的bind()将对象(对象===实例)注册到容器中

$container = new Container();


//将Db类绑定到容器中

$container->bind('Db', function(){

return new Db();

});


//将Validate类绑定到容器中

$container->bind('Validate', function(){

return new Validate();

});


//将View类绑定到容器中

$container->bind('View', function(){

return new View();

});



◇ 创建Demo5.php: 进一步简化facade门面外观模式


<?php

/**

 * facade门面外观模式简化

 * 

 */

require 'Container.php'; //导入容器


class Facade

{

//保存容器对象

protected static $container = null;


//创建初始化方法,给容器对象赋值

public static function initalize(Container $container)

{

static::$container = $container;

}


// 1. 链接数据库

public static function connect()

{

return static::$container->make('Db')->connect();

}


// 2. 数据验证

public static function check()

{

return static::$container->make('Validate')->check();

}


// 3. 输出提示

public static function display()

{

return static::$container->make('View')->display();

}


}


//客户端调用

echo '<h2>简化了的facade门面外观模式调用</h2>';

Facade::initalize($container);

echo Facade::connect();

echo Facade::check();

echo Facade::display();


声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议