设计模式与服务容器
1.单例模式
<?php
namespace _1205;
use PDO;//引用PDO别名
//单例模式
//创建类
class Temp{
}
//创建两个对象
$obj1 = new Temp();
$obj2 = new Temp();
var_dump($obj1,$obj2);//查看对象
var_dump($obj1===$obj2);//查看对象是否完全相同,返回值是false
echo '<hr>';
//单例模式的原理
class Demo1{
//构造方法 private:私有化,在类外部就不可以被实例化了
private function __construct(){
}
//目前只能在类中的内部将类实例化
public static $instance = null;//当前类的实例,声明为静态
//实例化当前类的方法,声明为静态方法
public static function getInstance(){//不需要参数
//实例化当前类,并且返回类实例/对象
//判断当前类是否已被实例化了,如果没有就实例化,如果已实例化就返回
if (is_null(self::$instance)){
self::$instance = new self();
}
return self::$instance;
}
//禁用克隆魔术方法
private function __clone(){
}
}
$obj1 = Demo1::getInstance();//Demo1中的getInstance方法
$obj2 = Demo1::getInstance();//Demo2中的getInstance方法
var_dump($obj1 === $obj2);
var_dump($obj1, $obj2);
echo '<hr>';
// 单例模型应用场景==>数据库连接
class Db{
// 构造方法 private:私有化,在类的外部不可以被实例化,在内部可以调用
//...$connectParams 剩余参数
private function __construct(...$connectParams){
$dsn = $connectParams[0];
$username = $connectParams[1];
$password = $connectParams[2];
self::$pdo = new PDO($dsn, $username, $password);
}
// 目前 只能在类中的内部将类实例化
// 当前类的实例
public static $pdo = null;
// 实例化当前类的方法
public static function getInstance(...$connectParams){
// 实例化当前类,并返回类实例/对象
// 判断当前类是否已经被实例化过了,如果没有的话就实例化,如果已实例化,就返回它
if (is_null(self::$pdo)) {
// 构造函数不需要返回
new self(...$connectParams);
}
return self::$pdo;
}
// 禁用克隆魔术方法
private function __clone()
{
}
}
$connectParams = ['mysql:host=localhost;dbname=php2020', 'root', '123456'];
$pdo = Db::getInstance(...$connectParams);
print_r($pdo->query('SELECT * FROM `user`')->fetchAll());//获取到表中所有数据
2.工厂模式
<?php
namespace _1205;
//工厂模式:用于批量创建类的实例/对象
//创建类
class Demo2{
}
//创建类实例
$obj = new Demo2();
$obj = new Demo2();
$obj = new Demo2();
class Test1{
public function __construct($arg1){
echo '对象创建成功,参数是:'. $arg1;
}
}
class Test2{
public function __construct($arg1,$arg2){
echo '对象创建成功,参数是:'.$arg1.','. $arg2;
}
}
class Test3{
public function __construct($arg1,$arg2,$arg3){
echo '对象创建成功,参数是:'.$arg1 .','.$arg2.','.$arg3;
}
}
//创建工厂类,专用于创建类实例
class Factory{
public static function create($classname,...$argments){
return new $classname(...$argments);
}
}
//echo Test1::class 完整的类名,带有命名空间
Factory::create(Test1::class,100);
echo '<br>';
Factory::create(Test2::class,100,200);
echo '<br>';
Factory::create(Test3::class,100,200,221);
3.依赖注入
<?php
namespace _1205;
//依赖注入:解决对象调用之前的耦合
//工作类
class Person{
//要依赖的外部对象
private $car = null;
//在构造方法中将依赖的内部对象全部实例化
//注入点放到构造方法中
public function __construct(Car $car){
$this -> car = $car;
}
public function work(){
return $this->car->drive();
}
}
//依赖注入的目标就是将类方法中的new替换掉
//依赖的外部类
class Car{
public function drive(){
echo '开车去上班';
}
}
//实例化工作类
$car = new car();
$person = new Person($car);
echo $person->work();
4.接口实现 小案例
接口文件 iVehicle.php
<?php
namespace base\inc;
// 交通工具的接口
interface iVehicle{
public function drive();
}
汽车 Car.php
<?php
namespace base\inc;
class Car implements iVehicle
{
public function drive(){
return '开汽车';
}
}
飞机 Plane.php
<?php
namespace base\inc;
class Plane implements iVehicle{
public function drive(){
return '乘飞机';
}
}
自动加载文件 autoload.php
<?php
spl_autoload_register(function ($className){
$path = str_replace('\\', '/', $className);
require dirname(__DIR__) . DIRECTORY_SEPARATOR . $path . '.php';
});
Demo.php
<?php
namespace base;
// 设置引用的外部类名的别名
use base\inc2\Car;
use base\inc2\Plane;
use base\inc2\iVehicle;
require __DIR__ . '/autoload.php';
class Demo{
// 交通工具
private $vehicle;
// 构造方法
public function __construct(iVehicle $vehicle){
$this->vehicle = $vehicle;
}
// 调用外部一个依赖对象
public function travelModel(){
return $this->vehicle->drive() . ':去旅行';
}
}
// 客户端调用
$car = new Car();
echo (new Demo($car))->travelModel(), '<br>';
echo (new Demo(new Plane()))->travelModel(), '<br>';
手抄作业:
总结:
接口类型在类方法中的应用是个难点,但面向接口编程的好处多:降低程序的耦合性
- 其能够最大限度的解耦
- 易于程序的扩展;
- 有利于程序的维护