Correcting teacher:天蓬老师
Correction status:qualified
Teacher's comments:谢谢鼓励, 设计模式是比较难学, 所以也比较难教 , 主要是原因是案例不容易写, 写复杂了一不小心写成了完整项目, 写简单了又担心会有地方说不清楚, 感谢大家的理解 , 以后会制作出更多精彩的课程
<?php
namespace _1205;
//设计模式 - 单例模式
//单例:类的唯一实例
//这个类只允许new一个对象。重复new还是那同一个对象
//举例Temp
class Temp
{
}
$obj1 = new Temp(); //object(_1205\Temp)#1 (0) { }
$obj2 = new Temp(); //object(_1205\Temp)#2 (0) { }
var_dump($obj1, $obj2);
echo '<br>';
var_dump($obj1 === $obj2); //bool(false)
echo '<hr>';
//比如单例模式用于数据库连接 (数据库连接数量有上限)
//单例Demo1
class Demo1
{
//1.new类的时候会自动调用类的构造方法
//那么将构造方法私有,这个类在外部将无法访问
private function __construct(){
//私有的构造方法 禁止外部new
}
//这个时候这个类一个实例都没有
//类中成员只能用类本身来访问 静态成员$instance
public static $instance = null;
//2.在类的内部写一个创建自己的实例的方法
//全球限量唯一发售
public static function getInstance(){
//先判断自己是否已经实例化过
if(is_null(self::$instance)){
self::$instance = new self();
}
return self::$instance;
//已创建过,返回自己的唯一对象
}
//3.禁止克隆这个类
private function __clone(){
//__clone方法在类被克隆时自动调用,用于重写克隆体的成员。
//把这个禁止就像禁用了构造方法无法new一样无法被克隆。
}
}
//调用
$obj1 = Demo1::getInstance(); //object(_1205\Demo1)#3 (0) { }
$obj2 = Demo1::getInstance(); //object(_1205\Demo1)#3 (0) { }
var_dump($obj1,$obj2);
echo '<br>';
var_dump($obj1===$obj2); //bool(true)
<?php
namespace _1205;
use PDO;
//单例模式连接数据库
class Db
{
private function __construct(...$connectParams){
$dsn = $connectParams[0];
$username = $connectParams[1];
$password = $connectParams[2];
self::$pdo = new PDO($dsn,$username,$password);
}
public static $pdo = null;
//2.方法接收参数
public static function getInstance(...$connectParams){
//先判断自己是否已经实例化过
if(is_null(self::$pdo)){
//构造函数不需要返回值
new self(...$connectParams);
}
return self::$pdo;
//已创建过,返回自己的唯一对象
}
private function __clone(){
}
}
//设置参数
$connectParams = [
'mysql:host=localhost;dbname=php_2019',
'root',
12341234
];
//获取对象
$pdo = Db::getInstance(...$connectParams);
//打印数据
echo '<pre>';
print_r($pdo->query('SELECT * FROM `user`')->fetchAll());
echo '</pre>';
<?php
namespace _1205;
//工厂模式
class Demo2
{
//...
}
//不同的file都要创建Demo2的实例
$obj = new Demo2();
$obj = new Demo2();
/******************************************/
class Test1
{
public function __construct($arg1)
{
echo '对象创建成功,参数为'.$arg1.'<br>';
}
}
class Test2
{
public function __construct($arg1,$arg2)
{
echo '对象创建成功,参数为'.implode(',', [$arg1,$arg2]).'<br>';
}
}
class Test3
{
public function __construct($arg1,$arg2,$arg3)
{
echo '对象创建成功,参数为'.implode(',', [$arg1,$arg2,$arg3]).'<br>';
}
}
//工厂 来生产类的实例
class Factory
{
public static function create($className,...$args){
return new $className(...$args);
}
}
//生产
//Test1::class 等于 _1205\Test1
Factory::create(Test1::class,100);
Factory::create(Test2::class,100,200);
Factory::create(Test3::class,100,200,300);
<?php
namespace _1205;
//依赖注入
//一般情况下
//工作类
class Person1
{
//人依赖汽车去上班
private $car = null;
//构造方法中将依赖的外部对象全部实例化
public function __construct(){
//类方法中出现了new 代表耦合很高
$this->car = new Car1();
}
public function toWork(){
return $this->car->drive();
}
}
//依赖类
class Car1
{
public function drive(){
return '开车去上班';
}
}
//客户端调用
//实例化
$p1 = new Person1();
echo $p1->toWork();
echo '<hr>';
/*************************************/
//将依赖注入 解决在类中使用new的情况
class Person2
{
//人依赖汽车去上班
private $car = null;
//构造方法中将依赖的外部对象全部实例化
//把$car2传入到构造方法
public function __construct(Car2 $car2){
//消除了new 用外部创建的$car2代替
$this->car = $car2;
}
public function toWork(){
return $this->car->drive();
}
}
//依赖类
class Car2
{
public function drive(){
return '开车去上班';
}
}
//客户端调用
//Car类在外部实例化 再将得到的$car注入到Person的构造方法中
$car2 = new Car2();
//这里记得new时候给类传参,因为构造方法需要参数
$p2 = new Person2($car2);
echo $p2->toWork();
echo '<hr>';
1.Maker
<?php
namespace _1205;
//制造商类
class Maker
{
public function get(){
return '华为';
}
}
2.Product
<?php
namespace _1205;
//产品类
class Product
{
//$maker Maker类的一个实例
public function get(Maker $maker){
return '该手机是由:<span style="color:red;font-weight:bolder">'. $maker->get() .'</span>生产的';
}
}
3.demo1 不使用容器的类调用
<?php
namespace _1205;
//客户端调用
require 'Product.php';
require 'Maker.php';
//不使用容器 对两个类进行调用
class Client1
{
public function show(){
//创建产品实例
$product = new Product();
//制造商实例
$maker = new Maker();
//制造商注入到产品类里
return $product->get($maker);
}
}
//客户端调用
//节省了一个对象
echo (new Client1())->show();
4.Container 写个容器
<?php
namespace _1205;
//引入闭包别名
use Closure;
class Container
{
//容器数组
protected $instance = [];
//类实例化过程绑定到容器中
public function bind($alias,Closure $process){
//类的实例化代码绑定到类名
$this->instance[$alias] = $process;
}
//取出保存在容器中的类实例化闭包 并执行它
public function make($alias){
//return $this->instance[$alias]();
return call_user_func_array($this->instance[$alias] , []);
}
}
5.demo 使用容器的类调用
<?php
namespace _1205;
//客户端调用
require 'Product.php';
require 'Maker.php';
require 'Container.php';
//使用容器 对两个类进行调用
class Client2
{
public function show(Product $product, Maker $maker){
//制造商注入到产品类里
return $product->get($maker);
}
}
//实例化Container
$container = new Container();
//开始绑定
//将产品类与实例化代码绑定到容器中
//这里别名随便取
$container->bind('product',function(){return new Product();});
//将制造商类与实例化代码绑定到容器中
$container->bind('maker',function(){return new Maker();});
//创建产品实例并返回给一个变量
//这里make传入的类名就是之前起的别名
$product = $container->make('product');
//创建制造商实例并返回给一个变量
$maker = $container->make('maker');
//客户端调用
echo (new Client2())->show($product,$maker);
结果:
autoload.php
<?php
spl_autoload_register(function($className){
$path = str_replace('\\', '/', $className);
require dirname(__DIR__).DIRECTORY_SEPARATOR.$path.'.php';
});
inc1
Car.php
<?php
namespace base\inc1;
class Car
{
public function drive(){
return '开汽车';
}
}
Train.php
<?php
namespace base\inc1;
class Train
{
public function drive(){
return '坐火车';
}
}
Plane.php
<?php
namespace base\inc1;
class Plane
{
public function drive(){
return '坐飞机';
}
}
Travel1
<?php
namespace base;
use base\inc1\Car;
use base\inc1\Train;
use base\inc1\Plane;
require __DIR__.'/autoload.php';
//最原始
class Travel1
{
private $vehicle;
//构造方法
public function __construct($vehicle){
//传入不同参数 实例化不同类
//严重依赖
switch (strtolower($vehicle)){
case 'car':
$this->vehicle = new Car();
break;
case 'train':
$this->vehicle = new Train();
break;
case 'plane':
$this->vehicle = new Plane();
}
}
public function travelModel(){
return $this->vehicle->drive().'去旅行';
}
}
//客户端调用
echo (new Travel1('car'))->travelModel().'<br>';
echo (new Travel1('plane'))->travelModel().'<br>';
echo (new Travel1('train'))->travelModel().'<br>';
Travel2
<?php
namespace base;
use base\inc1\Car;
use base\inc1\Train;
use base\inc1\Plane;
require __DIR__.'/autoload.php';
//用工厂
class Factory
{
protected static $instance = null;
public static function getInstance($vehicle){
//传入不同参数 实例化不同类
switch (strtolower($vehicle)){
case 'car':
static::$instance = new Car();
break;
case 'train':
static::$instance = new Train();
break;
case 'plane':
static::$instance = new Plane();
}
//返回
return self::$instance;
}
}
class Travel2
{
private $vehicle;
//构造方法
public function __construct($vehicle){
//一句代码从工厂获取实例对象
//依赖一个工厂。。
$this->vehicle = Factory::getInstance($vehicle);
}
public function travelModel(){
return $this->vehicle->drive().'===去旅行';
}
}
//客户端调用
echo (new Travel2('car'))->travelModel().'<br>';
echo (new Travel2('plane'))->travelModel().'<br>';
echo (new Travel2('train'))->travelModel().'<br>';
inc2
Car.php、Train.php、Plane.php 外添加一个 Ship.php 都实现了iVehicle接口
<?php
namespace base\inc2;
class Ship implements iVehicle
{
public function drive(){
return '坐轮船';
}
}
接口 iVehicle.php
<?php
namespace base\inc2;
//交通工具接口
interface iVehicle
{
public function drive();
}
Travel3
<?php
namespace base;
use base\inc2\Car;
use base\inc2\Train;
use base\inc2\Plane;
use base\inc2\Ship;
use base\inc2\iVehicle;
//自动加载
require __DIR__.'/autoload.php';
//用接口
class Travel3
{
private $vehicle;
//构造方法 这里需要接收一个对象,就是实现了vehicle接口的对象
public function __construct(iVehicle $vehicle){
$this->vehicle = $vehicle;
}
public function travelModel(){
return $this->vehicle->drive().'@@@去旅行';
}
}
//客户端调用
//这里new 的时候 传入一个对象
echo (new Travel3(new Car()))->travelModel().'<br>';
echo (new Travel3(new Plane()))->travelModel().'<br>';
echo (new Travel3(new Train()))->travelModel().'<br>';
echo (new Travel3(new Ship()))->travelModel().'<br>';
手写:
总结:类里面的方法调用相互传参的步骤还是会晕。一步一步看好像又明白了。。其实没啥难的。。。吧。。设计模式这种东西真的蛮烧脑的。很耐人寻味。老师讲课真的很认真也特别用心。作为听讲者也要好好学啊。