PHP 设计模式之最全面,最简单的讲解

本文详细介绍了单例模式的实现原理、优点以及代码示例,展示了如何通过单例模式确保资源的唯一实例。随后,讲解了工厂模式的几种形式,包括简单工厂、工厂方法、抽象工厂和策略模式,及其在解耦和代码灵活性方面的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.单例模式

单例模式是指只创建一个资源(对象、数据库链接等),防止外部实例+判断是否有返回或创建后返回对象。

三个要点:
1.需要一个保存类的唯一实例的静态成员变量
2.构造函数和克隆函数必须声明为私有的,防止外部程序new类从而失去单例模式的意义
3.必须提供一个访问这个实例的公共的静态方法(通常为getInstance方法),从而返回唯一实例的一个引用
优点:

1.单例模式减少资源浪费,保证整个环境只有一个实例对象,特别适合编写资源连接类

代码:
#代码:
	class RedisServer
	{
	    #创建一个静态变量 保存类的唯一实例的静态成员变量
	    private static $instance=[];
	    private $redis;
	    private $host='127.0.0.1';#ip
	    private $post=6379;#端口号
	    private $timeout=0;#闲置时间后关闭
	    private $table=0;#指定哪个库
	    private $connect=1;# 1 长连接 0 短连接
	    //私有的构造方法,禁止外部使用new创建对象 走完这里 3再走方法
	    #指定 ip 端口 这两个是基本不会变的 但是 库的会变 所以根据库的不同 可以new 不同的对象
	    private function __construct($config){
	        $this->redis = new Redis();
	        if(isset($config['host']))  $this->host = $config['host'];
	        if(isset($config['post']))  $this->post = $config['post'];
	        if(isset($config['timeout']))  $this->timeout = $config['timeout'];
	        if(isset($config['table']))  $this->table = $config['table'];
	        if(isset($config['connect']))  $this->connect = $config['connect']>=1 ?1:0;
	
	        # 连接
	        if($this->connect){
	            $this->redis->pconnect($this->host,$this->post,$this->timeout);
	        }else{
	            $this->redis->connect($this->host,$this->post,$this->timeout);
	        }
	
	        if($this->table>15 || $this->table<0 || !is_int($this->table) ){
	            echo '数据库表只能填写0~15的整数';
	            exit;
	        }
	        #选择库
	        $this->redis->select($config['table']);
	    }
	    #1先走这里
	    public static function getInstance($config=[]){
	        $table = array_key_exists('table',$config) ?$config['table']:0;
	        #为啥这里的私有变量 需要加数组呢 如果不加的话 他已经存在了 但他指定的表可能不是你所需要的 就会存在bug
	        if(!isset(self::$instance[$table])){
	            # 这里创建一个对象 赋值给变量
	            echo '重新新建一个表为'.$table.'的对象!';
	            self::$instance[$table] = new self($config);//2然后再走 __construct
	        }
	
	        return self::$instance[$table];
	    }
	    //私有的克隆函数 将克隆方法设为私有,禁止外部克隆对象
	    private function __clone(){}
	    # 4 方法
	        
	        public function close(){
	            return $this->redis->close();
	        }
	        public function getString($str){
	           return $this->redis->get($str);
	        }
	        public function setString($key,$value){
	            return $this->redis->set($key,$value);
	        }
	
	}
	
	$config =[
	    'host'=>'127.0.0.1',#ip
	    'post'=>'6379',#端口号
	    'timeout'=>'0',#闲置时间后关闭
	    'table'=>1,#指定哪个库
	    'connect'=>0,# 1 长连接 0 短连接
	];
	$config1 =[
	    'host'=>'127.0.0.1',#ip
	    'post'=>'6379',#端口号
	    'timeout'=>'0',#闲置时间后关闭
	    'table'=>2,#指定哪个库
	    'connect'=>0,# 1 长连接 0 短连接
	];
	$Server = RedisServer::getInstance($config);
	$Server1 = RedisServer::getInstance($config1);

2.工厂模式

工厂模式其实是一种类,它具有创建对象的某些方法。我们可以使用工厂类来创建对象,而不直接使用 new。这样做的好处是,如果你想要更改所实例化的类名,则只需更改该工厂方法内容即可,不需要逐一寻找代码中具体实例化的地方来修改了。为系统结构提供灵活的动态扩展机制,减少了耦合。

优点:

帮助封装:简单工厂虽然简单,但是非常友好地帮助我们实现了组件的封装,然后让组件外部能真正面向接口编程。
解耦 :通过简单工厂,实现了客户端和具体实现类的解耦。

缺点:

可能增加客户端的复杂度。

工厂模式其实可以划分为:简单工厂模式、工厂方法模式、抽象工厂模式等。

1.简单工厂模式

定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂模式使一个类的实例化延迟到其子类。一般用在具体产品很少扩展的情况下,不用经常修改,且不修改代码的话是不能实现扩展的。

例子:去商店卖手机 一个是苹果厂商提供的手机 一个是小米厂商提供的手机。

#简单工厂模式
	#定义一个接口 手机类商品 等电子产品
	interface Mobile
	{
	    #手机
	    public function mobile();
	    #充电器
	    public function charger();
	}

	#苹果手机厂商
	class Iphone_Mobile implements Mobile {
	    public function __construct()
	    {
	        echo '苹果旗舰店:';
	    }
	    public function mobile(){
	        echo '手机;';
	    }
	    public function charger(){
	        echo '充电器;';
	    }
	}
	#小米手机厂商
	class XiaoMI_Mobile implements Mobile {
	    public function __construct()
	    {
	        echo '小米旗舰店:';
	    }
	    public function mobile(){
	        echo '手机;';
	    }
	    public function charger(){
	        echo '充电器;';
	    }
	}
	# 商店
	class Shopping
	{
	    public static function create($class){
	        switch ($class)
	        {
	            case 'Iphone_Mobile':
	                return new Iphone_Mobile();#选择苹果厂商的商品
	                break;
	            case 'XiaoMI_Mobile':
	                return new XiaoMI_Mobile();#选择小米厂商的商品
	            default: echo '不好意思,我这里没有 '.$class.' 这个手机卖!';
	        }
	    }
	}
	#商店 下单买苹果手机
	$Iphone = Shopping::create('Iphone_Mobile');#苹果旗舰手机店:
	$Iphone->mobile();#买苹果手机:;
	$Iphone->charger();#买苹果充电器:;
	#商店 下单买小米手机
	$XiaoMI = Shopping::create('XiaoMI_Mobile');#小米旗舰店:
	$XiaoMI->mobile();#买小米手机:;
	$XiaoMI->charger();#买小米充电器:;
	#商店 下单买华为手机
	$HUAWEI = Shopping::create('HUAWEI_Mobile');#不好意思,我这里没有 HUAWEI_Mobile 这个手机卖!

2.工厂方法模式

例子:去店铺买手机。发现只有苹果的柜台和小米的柜台。而且柜台只有手机和充电器买。

通过定义了一个抽象出来的核心工厂类,并同时定义创建产品对象的接口,而创建具体实例的工作延迟到工厂子类中去完成


#工厂模式方法
	#定义一个接口 手机类商品 等电子产品
	interface Mobile
	{
	    #手机
	    public function mobile();
	    #充电器
	    public function charger();
	}

	#苹果手机厂商
	class Iphone_Mobile implements Mobile {
	    public function __construct()
	    {
	        echo '苹果手机:';
	    }
	    public function mobile(){
	        echo '手机;';
	    }
	    public function charger(){
	        echo '充电器;';
	    }
	}
	#小米手机厂商
	class XiaoMI_Mobile implements Mobile {
	    public function __construct()
	    {
	        echo '小米手机:';
	    }
	    public function mobile(){
	        echo '手机;';
	    }
	    public function charger(){
	        echo '充电器;';
	    }
	}
	
	#区别
		#定义一个抽象类
		#淘宝
		abstract class Taobao{
			abstract static function shop();# 开店 
		}
		
		# 苹果手机的厂家在淘宝开店
		class Iphone function extends Taobao{
			
			public static function shop(){
				return new Iphone_Mobile();#卖的是自己的苹果手机
			} 
		}
		
		# 小米手机的厂家在淘宝开店
		class XiaoMI function extends Taobao{
			
			public static function shop(){
				return new XiaoMI_Mobile();#卖的是自己的小米手机
			} 
		}
		 
		$one = Iphone::shop();#去苹果手机店里面
		$one->mobile();//手机
		$one->charger();//充电器
		
		$two = XiaoMI::shop();#去小米手机店里面
		$two->mobile();//手机
		$two->charger();//充电器
		
3.抽象工厂模式

提供一个创建一系列相关或相互依赖对象的接口。

例子:去淘宝买电子产品 只有两个电脑和手机两个种类的产品。 而且电脑产品只有:电脑和鼠标卖,手机产品只有:手机和充电器买。

#抽象工厂
 	#定义一个手机类电子产品的接口
	interface Mobile
	{
		#手机
	    public function mobile();
	 	#充电器
	    public function charger();
	}
 	# 苹果厂商
	class IPhone implements Mobile
	{
	    public function mobile()
	    {
	        echo "购买苹果手机";
	    }
	 
	    public function charger()
	    {
	        echo "购买苹果充电器";
	    }
	}
 	#定义一个电脑类电子产品的接口
	interface Computer
	{
		#电脑
	    public function computer();
	 	#鼠标
	    public function mouse();
	}
 	#小米厂商
	class XiaomiComputer implements Computer
	{
	    public function computer()
	    {
	        echo "购买小米电脑";
	    }
	 
	    public function mouse()
	    {
	        echo "购买小米鼠标";
	    }
	}
 	#定义一个抽象类的 店铺 里面提供手机产品和电脑产品
	abstract class Shop
	{
		#手机产品
	    abstract public static function createMobile();
	 	#电脑产品
	    abstract public static function createComputer();
	}
 	#淘宝
	class Taobao extends Shop{
		#手机产品
	    public static function createMobile()
	    {
	        return new IPhone();#只有苹果的手机产品买
	    }
	 	#电脑产品
	    public static function createComputer()
	    {
	        return new XiaomiComputer();#只有小米的电脑产品买
	    }
	}
 	#用户去淘宝选手机
	$one = Taobao::createMobile();#发现只有苹果的手机买
	$one->mobile();#买了一个苹果手机
	$one->charger();#买了一个苹果充电器
	
	#用户去淘宝选电脑
	$two = Taobao::createComputer();#发现只小米的电脑买
	$two->computer();#购买小米电脑
	$two->mouse()#购买小米鼠标
	

3.策略模式

定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。

代码示例:

#通过需要不同的日期信息来调用不同的类实现功能。
 #策略模式:
        #定义一个接口  日期转换
        interface Time
        {
            public function timeString();
        }

        # 当前的年份
        class Year implements Time{
            public function timeString(){
                   echo date('Y',time()).'年';
            }
        }
        # 当前的月份
        class Month implements Time{
            public function timeString(){
                echo date('m',time()).'月';
            }
        }
        # 当前的日期
        class Day implements Time{
            public function timeString(){
                echo date('Y-m-d',time());
            }
        }

        class Times {
            private $class;
            #根据所需的日期 来选择调用哪个类的方法
            public function timess(Time $class){
                 $this->class = $class;
                 return $this->class->timeString();
            }
        }

        $Year = new Times();
        #查看当前的年份
        $Year->timess(new Year());#2022年
        #查看当前的月份
        $Year->timess(new Month());#07月
        #查看当前的日期
        $Year->timess(new Day());#2022-07-20
        

4.适配器模式

将一个类的接口转成我们希望的另外一个接口,使得原本接口不兼容不能在一起工作的类可以在一起工作。

优点:灵活性和扩展性都非常好,符合开闭原则。
缺点:过多地使用适配器,会让系统非常零乱,不易整体进行把握。

代码示例:

#例如:封装一个缓存类,它支持  redis 和 memcache,只需切换使用时只需修改相关配置就能实现切换了,而不需要修改大量的代码。
#减少代码间的耦合,可以方便增减需要实现的类。
# 适配器模式
        #定义一个缓存类
        interface Cache
        {
            public function connect();
            public function set($key,$value,$time=0);
            public function get($key);
            public function del($key);
            public function close();
        }
		# 使用 redis 做为缓存
        class Rediss implements Cache
        {
            private $redis;

            public function __construct()
            {
                $this->connect();
            }
            public function connect()
            {
                $this->redis = new Redis();
                return $this->redis->connect('127.0.0.1','6379');
            }

            public function set($key,$value,$time=0)
            {
                if($time==0){
                    return $this->redis->set($key,$value);
                }else{
                    return $this->redis->setex($key,$time,$value);
                }
            }

            public function get($key)
            {
                return $this->redis->get($key);
            }

            public function del($key)
            {
                return $this->redis->delete($key);
            }
            public function close()
            {
                return $this->redis->close();
            }
        }
        
		#使用 memcache 做为缓存
	    class Memcaches implements Cache
	    {
	        private $memcache;
	
	        public function __construct()
	        {
	            $this->connect();
	        }
	        public function connect()
	        {
	            $this->memcache = new Memcache();
	            return $this->memcache->connect('127.0.0.1','11211');
	        }
	
	        public function set($key,$value,$time=0)
	        {
	            return $this->memcache->set($key,$value,false,$time);
	        }
	
	        public function get($key)
	        {
	            return $this->memcache->get($key);
	        }
	
	        public function del($key)
	        {
	            return $this->memcache->delete($key);
	        }
	        public function close()
	        {
	            return $this->memcache->close();
	        }
	    }
	    
    	#调用
		if($cache_config == 'redis'){
			# 使用 redis 
			$cache = new Rediss();  
		}else{
			# 使用 memcache
		    $cache = new Memcaches();
		}
		
		$cache->set('key','value');
        $cache->get('key'));
        $cache->del('key');
        $cache->close();	
    
		


5.注册模式

注册树模式通过将对象示例注册到一颗全局的对象树上, 需要的时候从对象树上采摘的模式设计方法。

代码示例:

 #注册模式
    class Register
    {
        #定义一个私有的变量
        private static $objects;
        # 注册类
        public static function set($key,$class)
        {
           if(!isset(self::$objects[$key])){
               self::$objects[$key] = $class;
           }
           return true;
        }
        #获取类的对象
        public static function get($key){
            if(!isset(self::$objects[$key])){
                return false;
            }
            return self::$objects[$key];
        }
        #取消注册类
        public static function unset_class($key){
            if(!isset(self::$objects[$key])){
                return false;
            }
            unset(self::$objects[$key]);
            return true;
        }
        #查看所有的类
        public static function all(){
            return self::$objects;
        }
    }
    # 定义一个类
    
	    #苹果手机类
	    class Apple{
	            public function __construct(){
	                echo '苹果手机:';
	            }
	            public function open(){
	                echo '开机';
	            }
	            public function close(){
	                echo '关机';
	            }
	    }
	    
	    #华为手机类
	    class HuaWei{
	        public function __construct(){
	            echo '华为手机:';
	        }
	        public function open(){
	            echo '开机';
	        }
	        public function close(){
	            echo '关机';
	        }
	    }
	    
	    #注册类
        Register::set('apple',new Apple());
        Register::set('huawei',new HuaWei());
		#获取类
       echo Register::get('apple')->close();#苹果手机:关机
       echo Register::get('huawei')->close();#华为手机:关机
       #查看所有注册类
        var_dump(Register::all());
        
6.观察者模式

观察者模式(Observer Pattern)也叫做发布订阅模式(Publish/subscribe),它是一个在项目中经常使用的模式定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。

优点:降低了类对象之间的耦合度。
缺点:观察者较多时,可能会花费一定的开销来发消息,但这个消息可能仅一个观察者消费。

代码示例:

 #观察者模式 
	 #把购买商品这个接口 当做被观察的对象 
	 #把通知商户 , 通知用户,记录日志 当做观察者
        #例子 购买商品成功 需要通知商户 通知用户 记录日志等操作

            #定义一个通知的接口
            interface Send{
                public function sendMsg();
            }

            #给商户发消息 观察者
            class Shop implements Send{
                public function sendMsg(){
                   echo '<pre> 用户下单成功 </pre>';
                }
            }
            #给用户发消息 观察者
            class User implements Send{
                public function sendMsg(){
                    echo '<pre> 购买商品成功 </pre>';
                }
            }
            #给日志发消息 观察者
            class Loggs implements Send{
                public function sendMsg(){
                    echo '<pre> xx用户在xx商户购买xx商品成功 </pre>';
                }
            }

            #定义一个接口
            interface obeject{
                public function addObeject($key);
            }

            # 被观察的对象
            class Order implements obeject{
                private $obeject;
                #绑定通知
                public function addObeject($key){
                        $this->obeject[]=$key;
                }
                #购买逻辑
                public function addOrder(){
                    #写下单逻辑
                    #下单成功通知
                    foreach ($this->obeject as $value){
                        $value->sendMsg();
                    }
                }
            }
            $order = new Order();
            $order->addObeject(new Loggs());#<pre> xx用户在xx商户购买xx商品成功 </pre>
            $order->addObeject(new Shop());#<pre> 购买商品成功 </pre>
            $order->addOrder();
            
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值