设计模式之单例模式探究

      这周好像没安排什么博客任务唉,那就随便写点吧,说说单例模式在php中的玩法好了

      首先吧,单例模式在我们项目开发中经常要用到,比如商城系统的购物车类吧,我们不能每次买完商品后都要创建一个购物车对象吧,这样前边买的商品岂不是被覆盖掉了??卖东西的也会有损失吧,这样岂不是恶心了别人,郁闷了自己??所以嘛,单例模式还是很重要滴!!!!!!

      那我们先写一个类好了,鉴于我比较懒,所以就写个dog类吧,诸位看客不要对号入座哈。

class Dog
{
   public $name;
   public $age;
   
   public function __construct($name,$age)
   {
      $this->name=$name;
      $this->age=$age;
   }
}

  学过编程的人都知道,当我们需要某个类的一个实例的时候,基本都是new出来一个(当然还有其它创建方式,在此不一一列举,就以new为例),那么我们来new一下好了

$dog1=new Dog('小白',6);
$dog2=new Dog('小明',7);

在上边的代码中,我们new出来了两个对象dog1和dog2,那么在你看来,这是不是一个对象呢?(吐槽:你脑残啊,你都说了是new了俩对象了!!),咳咳,确实是俩对象,那么问题来了,你new一个出来一个新的对象,怎么实现上边所说的单例模式呢???(吐槽:笨蛋,你都说了new一个出来一个新对象,那就不要new了呗),可是,我们怎么才能不new呢?当然,不new怎么产生那个单例对象呢?所以,不new还是不行滴。可是怎么才能解决这个问题呢?(沉思10万年中。。。。。。)

----------------------------------------------------------------10万年后--------------------------------------------------------------------------------------

众所周知,我们在new的时候,都是在调用类的构造函数,来产生一个对象,我们new一个,出来一个新对象,那么,我们就把上边的构造函数改造一下不就好了??废话先不说了,看看代码好了:

class Dog
{
   public $name;
   public $age;
   
   protected function __construct($name,$age)
   {
      $this->name=$name;
      $this->age=$age;
   }
}

  看见区别了没?我把构造函数的权限改了,由public改为了protected,这时候你看,这样就没法再new出新对象了。(吐槽:是没法new了,可是你给我生出来那个单例对象啊???)。先别急,我们是没法在外边new出对象了,可是。。。可是。。。我们能在类里边new出来一个啊,在类内部是可以调用被protected保护的构造函数的,于是,代码变成了下边这样:

class Dog
{
   public $name;
   public $age;
   
   public function getIns()
   {
      return new Dog('小白',6);
   }
   protected function __construct($name,$age)
   {
      $this->name=$name;
      $this->age=$age;
   }
}

  恩,这样就好多了,我们不让鬼子进村随便new对象了,还提供了一个public的方法,可以创建一个对象,问题好像解决了,那么真的就结束了么??别忘了,我们的获得对象的函数是写在类内部的啊,没有对象我们怎么调用啊?可是话又说过来,有了对象我们还调用它干嘛啊?于是新的问题出现了,我们没法调用产生对象的函数,这真是一个令人忧桑的问题。。。。。。那么我再想想怎么解决吧(沉思10万年中。。。。。。)

------------------------------------------------------------------------10万年后-----------------------------------------------------------------------------

      好了,继续说这个问题吧(吐槽:终于睡醒了),我们要产生对象,就要调用类内的函数,可是没有对象,我们又没法调用那个函数(系统陷入了死循环)。那么问题的关键就落在了在没有对象的情况下,怎么调用那个函数上。这时候请打开记忆的阀门,在我们上c++课的时候,老师是不是讲了一个东西,它属于全类,而不属于某个具体的对象??(观众:好像真的有哎,叫什么来着??好像叫static)。。。。Bingo!!!答对了,就是它,我们可以把那个得到对象的函数写成static的是,这样它就成全狗类的了,再也不属于某个对象的私藏物品了(PS:女神是大家的,谁也不能私藏。。。),于是代码出现了:

class Dog
{
   public $name;
   public $age;
   
   public static function getIns()
   {
      return new Dog('小白',6);
   }
   protected function __construct($name,$age)
   {
      $this->name=$name;
      $this->age=$age;
   }
}

  问题解决了,我们终于得到了一个单例模式的类,这时候我们满心欢喜的交给了老师,炫耀自己的劳动成果,老师认真看了一下,说:可是,我们每调用一次getIns()函数就产生了一个新的对象,这跟最开始没改的时候有区别嘛???我又看了一下,还真是。。。。。。。。。又回到了最初的起点,记忆中你青涩的脸。。。(吐槽:咳咳,跑题了)。。。

     于是啊,我又陷入了沉思。。。(沉思1万年中。。。(这次少点,别让你看瞌睡了))

-------------------------------------------------------------------------1万年后------------------------------------------------------------------------------

    终于想明白了,虽然这时候看起来是回到了最初的起点,可还是有很大区别的,你看,代码量起码上去了不是??好吧,不扯淡了,言归正传,我们这时候得到了这么个情况,跟起点最大的区别就是:以前new对象是靠构造函数,现在是靠调用getIns()函数,既然不是构造函数,我们可处理的权限就大多了,我们适当的加入一些逻辑判断就能解决这个问题,不信???让代码说话:

class Dog
{
   public $name;
   public $age;
   public static $ins=null;
   
   public static function getIns()
   {
      if(Dog::$ins)
	  {
	     return Dog::$ins;
	  }
      Dog::$ins=new Dog('小白',6);
      return Dog::$ins;
   }
   protected function __construct($name,$age)
   {
      $this->name=$name;
      $this->age=$age;
   }
}

  在上边的代码中,我们加了一个static变量,定义为$ins,用来存储产生的单例对象,在getIns()函数中,我们判断这个$ins对象是否存在且不为空,如果存在且不为空,那么就直接返回它,不然创建一个对象,并把创建的对象给它,告诉下次调用该函数时说对象已经存在了,就不用新new直接返回原先的对象就好了,那么单例对象也就完美(自以为)解决了,这时候拿给老师看,老师欣慰一笑,说:恩,不错,已经基本上能用了。

      可是,如果我用一个新的类叫Dog1,继承你的Dog类,我把构造函数的权限给扩大,改成public,这时候就可以随便new了,你又怎么解决呢??(熟悉php的人知道,在子类继承父类的时候,是能够把父类函数的权限扩大的,也可以维持不变,但不能缩小)。。。。。。。。。。(吐槽:尼玛,这老师跟我有仇啊,我好不容易写个代码容易吗??你还要拆台??),咳咳,要尊敬老师。。。。。。。。。。。。。。。。。。。。。。于是,继续沉思(沉思10万年中。。。。。。。。。。。。。。。。。。。。。。)

------------------------------------------------------------------------10万年后-----------------------------------------------------------------------------

    经过十万年的积淀,我终于能够解决这个问题了,怎么解决呢??既然老师要继承我的类,要扩大权限,那事情好办,我就不让它继承了,我在类前边加个final关键字,这样就好了(妈妈再也不用担心有人继承我的类了)。。。。。。(吐槽:感情你睡了十万年就想出来这么个办法啊??),可是,在实际开发中,如果这个类必须要被继承咋办??不然项目会麻烦许多,这时候又改如何解决呢??既然想到了final,为什么不想想它的别的用法呢???脑袋瓜一亮:我可以让别人继承我的类,我不让别人重写我的构造函数不就行了??反正类是我的,自己不愿意继承自己写去。。。。。所以,我把final加到了构造函数上,代码如下:

class Dog
{
   public $name;
   public $age;
   public static $ins=null;
   
   public static function getIns()
   {
      if(Dog::$ins)
	  {
	     return Dog::$ins;
	  }
      Dog::$ins=new Dog('小白',6);
      return Dog::$ins;
   }
   protected final function __construct($name,$age)
   {
      $this->name=$name;
      $this->age=$age;
   }
}

  于是,经过31万年的努力,终于写出来这个单例对象了,为了防止老师再挑别的毛病,我还是不去找他看了,我自己藏着好了!!(吐槽:。。。。。。)

原文地址:https://www.cnblogs.com/jakii/p/4419597.html