免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1952 | 回复: 0

小议大型开发中php的设计模式之单件模式 [复制链接]

论坛徽章:
0
发表于 2011-02-25 15:48 |显示全部楼层
本帖最后由 bs 于 2011-03-06 23:42 编辑

以往在php环境下谈到的设计模式往往都是理论一大堆,加之php较少在实现大型应用方面,所以很多时候设计模式成了一种摆设,本文从较简单的设计模型中的单件模式说起,谈谈应用,阐述设计模型对于复杂环境中的大内涵.



从一个简单的例子着手,在一些应用中,我们希望有些对象是全局作用的,如下:

  1. include('example.class.php');
  2. $obj = new example();

  3. class a1
  4. {
  5. function ex()
  6. {
  7.   global $obj;
  8.   $obj->v = 1;  //注意这里,需要调用外部对象
  9. }
  10. }

  11. class a2
  12. {
  13. function ex()
  14. {
  15.   global $obj;
  16.   $obj->v ++;        //注意这里,再次调用外部对象
  17. }
  18. }

  19. $a1 = new a1;
  20. $a1->ex();
  21. $a2 = new a2;
  22. $a2->ex();
复制代码
从上面简单的例子看到,$obj对象被其它多个对象所使用,这时通常需要的几个步骤:
1. include类文件
2. 实例化
3. 在使用时global声明全局性

倘若有种情况需要在不同的对象中调用多个外部对象,那么情况有可能就是如下:

  1. include('example.class.php');
  2. $obj = new example();
  3. include('example2.class.php');
  4. $obj2 = new example2();
  5. ...
  6. $obj3
  7. $obj4
  8. $obj_n
  9. ...
  10. class a1
  11. {
  12. function ex()
  13. {
  14.   global $obj;
  15.   $obj->v = 1;
  16.   global $obj2;
  17.   $obj2->v = 1;
  18.   ...
  19.   global $obj_n;
  20.   $obj_n->v = 1;
  21. }
  22. }
  23. class a2
  24. {
  25. ...
复制代码
局面开始不好收拾了,于是我们使用一种方法封装这个过程,首先定义一个类,这个类专门负责将另一个指定的类自动实例化成对象:

  1. class Singleton
  2. {
  3. private $objs;
  4. public function instance($obj)
  5. {
  6.    if($this->objs[$obj] == null)        //判断是否已经实例化
  7.    {
  8.     include($obj.'.class.php');
  9.     $this->objs[$obj] = new $obj;
  10.    }
  11.    return $this->objs[$obj];
  12. }
  13. }
  14. $Singleton = new Singleton();
复制代码
那么之前的局面就演变成如下:

  1. ...
  2. class a1
  3. {
  4. function ex()
  5. {
  6.   global $Singleton;                //只需一次global声明
  7.   $Singleton->reg('example')->v = 1;
  8.   $Singleton->reg('example2')->v = 1;
  9.   ...
  10.   $Singleton->reg('example_n')->v = 1;
  11.   ...
  12. }
  13. }

  14. class a2
  15. {
  16. ...
复制代码
那么其中通过$Singleton对象访问类就是经典的单件模式了,这边仅仅是说明了单件模式概念,以下说明使用单件模式的好处.


一.文件包含与对象实例化的透明化

我们发现上边在使用$Singleton仍然需要global声明,这时可以使用函数来"包装"

  1. function instance($class_name)
  2. {
  3. static $instance;
  4. if($instance == false)
  5.   $instance = new Singleton();
  6. return $instance->reg($class_name);        //调用Singleton对象,实例化类并返回对象
  7. }
复制代码
那么最终的调用就是这样的

  1. ...
  2. class a1
  3. {
  4. function ex()
  5. {
  6.   //这里我们无需使用global,直接使用example类生成的对象
  7.   instance('example')->v = 1;
  8.   instance('example2')->v = 1;
  9.   ...
  10. }
  11. }
  12. class a2
  13. {
  14. ...
复制代码
这时我们看到使用一个外部对象就变得简单而清晰了,我们无需关注example类所在文件的包含和实例化就能直接使用,
这就是使用单件模式对对象透明化的作用.




二.全局(作用域)应用
通过之前的代码得知,我们可以在任何时候使用Singleton得到我们希望使用的对象:

  1. class a1
  2. {
  3. function ex()
  4. {
  5.   instance('example')->v = 1;        //使用单件模式针对example类生成对象并进行操作
  6.   ...
  7. }
  8. }
  9. ...
  10. class a2
  11. {
  12. function ex()
  13. {
  14.   instance('example')->v ++;        //在不同作用域对同一个对象进行操作
  15.   ...
  16. }
  17. }
复制代码
在a1和a2的类中调用example实现的对象时,无需考虑作用域及global声明,实现跨全局对象的应用.
       

三.事务性/一致性的应用
在一些多线程的语言中,有时希望在同一时间只能有一个线程对对象进行操作,这是线程安全问题,而在php中,类似的情况是资源竞争的解决,如对共享数据的读写,而使用单件模式则很容易做到,在原有单件模式的基础上,增加了事务性

  1. class Singleton_safe
  2. {
  3. private $objs;
  4. private $mutex;       
  5. public function reg($obj)
  6. {
  7.    if($objs[$obj] == null)        //判断是否已经实例化
  8.    {
  9.     include($obj.'.class.php');
  10.     $this->mutex[$obj] = sem_get(fileinode($obj.'.class.php'),1,0666,true);
  11.     sem_acquire($this->mutex[$obj]);        //这边使用信号量做同步
  12.     $this->objs[$obj] = new $obj;
  13.    }
  14.    return $this->objs[$obj];
  15. }

  16. function __destruct()
  17. {
  18.    foreach($this->mutex as $sem_id)
  19.    {
  20.     sem_release($sem_id);        //单件模式下析构时删除所有对象的信号量锁
  21.    //sem_remove($sem_id);       
  22.    }
  23. }
  24. }
复制代码
当然,和其它语言不一样,这个简单的例子实现的事务周期是对象在整个php进程的运行期间,这样保证了在调用Singleton_safe实现单例模式下,派生对象的所有操作是系统唯一的.


*四.其它扩展
有时在使用或调试对象时,需要记录对象的调用次数,可增加一些记数功能,

  1. class Singleton
  2. {
  3. private $objs;
  4. private $record = 0;
  5. public function reg($obj)
  6. {
  7.    if($this->objs[$obj] == null)        //判断是否已经实例化
  8.    {
  9.     include($obj.'.class.php');
  10.     $this->objs[$obj] = new $obj;
  11.    }
  12.    $this->record[$obj]++;                //累计对象的使用次数
  13.    return $this->objs[$obj];
  14. }

  15. public get_record($obj_name)
  16. {
  17.   return $this->record[$obj_name];     //获取对象的使用次数
  18. }
  19. }
  20. ....
  21. function instance($class_name == null)
  22. {
  23. static $instance;
  24. if($instance == false)
  25.   $instance = new Singleton();
  26. if($class_name == null) return $instance;
  27. return $instance->reg($class_name);
  28. }
复制代码
使用时

  1. instance('example')->v = 1;
  2. instance('example')->v++;
  3. echo 'example被使用次数为:',instance()->get_record('example');//2
复制代码
此外在一些其它语言上,如Cpp上也可结合对象的创建与销毁等内存管理工作.



单件模式是设计模式中较简单同时也是使用最为频繁的模式之一,仅仅这样一个简单的实现便可以帮我们做很多事,也让我们更多更有必要地去了解设计模式的价值所在.

另外在代码中存在Multiton模式的争议

更纯粹的Singleton如下

  1. //同上
  2. function instance($class_name)
  3. {
  4. static $instance;
  5. if($instance[$class_name] == false)
  6.   $instance[$class_name] = new Singleton($class_name);
  7. return $instance[$class_name]        
  8. }
  9. ...

  10. class Singleton
  11. {
  12. function __construct($class_name)
  13. {
  14.     include($class_name.'.class.php');
  15.     return new $class_name;
  16. }
  17. ...
  18. }
复制代码
调用上完全相同,算是重新做了Singleton和Multiton区别
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP