单例模式又称为职责模式,它用来在程序中创建一个单一功能的访问点,通俗地说就是实例化出来的对象是唯一的。
所有的单例模式至少拥有以下三种公共元素:
1. 它们必须拥有一个构造函数,并且必须被标记为private
2. 它们拥有一个保存类的实例的静态成员变量
3. 它们拥有一个访问这个实例的公共的静态方法
单例类不能再其它类中直接实例化,只能被其自身实例化。它不会创建实例副本,而是会向单例类内部存储的实例返回一个引用。
单例模式的优缺点:

主要优点:

1、提供了对唯一实例的受控访问。

2、由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能。

3、允许可变数目的实例。

主要缺点:

1、由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。

2、单例类的职责过重,在一定程度上违背了“单一职责原则”。

3、滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。

例子:

 1 class Single {
2 private $name;//声明一个私有的实例变量
3 private function __construct(){//声明私有构造方法为了防止外部代码使用new来创建对象。
4
5 }
6
7 static public $instance;//声明一个静态变量(保存在类中唯一的一个实例)
8 static public function getinstance(){//声明一个getinstance()静态方法,用于检测是否有实例对象
9 if(!self::$instance) self::$instance = new self();
10 return self::$instance;
11 }
12
13 public function setname($n){ $this->name = $n; }
14 public function getname(){ return $this->name; }
15 }
16
17
18 $oa = Single::getinstance();
19 $ob = Single::getinstance();
20 $oa->setname('hello world');
21 $ob->setname('good morning');
22 echo $oa->getname();//good morning
23 echo $ob->getname();//good morning

再来一个例子:

class Test{
private static $_instance;//保存类的静态成员变量
//定义一个私有的构造函数,确保单例类不能通过new关键字实例化,只能被其自身实例化
private final function __construct()
{
echo 'test_consttuct';
}
//定义克隆方法,确保单例类只能被克隆或者复制
private function __clone()
{
// TODO: Implement __clone() method. }
//公共的静态方法
public static function getInstance()
{
//检测类是否被实例化
if(!(self::$_instance instanceof self))
{
self::$_instance = new test();
}
return self::$_instance;
}
}
test::getInstance();

简单工厂模式:
①抽象基类:类中定义抽象一些方法,用以在子类中实现
②继承自抽象基类的子类:实现基类中的抽象方法
③工厂类:用以实例化对象

看完文章再回头来看下这张图,效果会比较好

 1 采用封装方式
2
3 <?php
4 class Calc{
5 /**
6 * 计算结果
7 *
8 * @param int|float $num1
9 * @param int|float $num2
10 * @param string $operator
11 * @return int|float
12 */
13 public function calculate($num1,$num2,$operator){
14 try {
15 $result=0;
16 switch ($operator){
17 case '+':
18 $result= $num1+$num2;
19 break;
20 case '-':
21 $result= $num1-$num2;
22 break;
23 case '*':
24 $result= $num1*$num2;
25 break;
26 case '/':
27 if ($num2==0) {
28 throw new Exception("除数不能为0");
29 }
30 $result= $num1/$num2;
31 break;
32 }
33 return $result;
34 }catch (Exception $e){
35 echo "您输入有误:".$e->getMessage();
36 }
37 }
38 }
39 $test=new Calc();
40 // echo $test->calculate(2,3,'+');//打印:5
41 echo $test->calculate(5,0,'/');//打印:您输入有误:除数不能为0
42 ?>

优点:以上代码使用了面向对象的封装特性,只要有了include这个类,其他页面就可以随便使用了

缺点:无法灵活的扩展和维护
比如:想要增加一个“求余”运算,需要在switch语句块中添加一个分支语句,代码需要做如下改动

 1 添加分支语句
2
3 <?php
4 class Calc{
5 public function calculate($num1,$num2,$operator){
6 try {
7 $result=0;
8 switch ($operator){
9 //......省略......
10 case '%':
11 $result= $num1%$num2;
12 break;
13 //......省略......
14 }
15 }catch (Exception $e){
16 echo "您输入有误:".$e->getMessage();
17 }
18 }
19 }
20 ?>

代码分析:用以上方法实现给计算器添加新的功能运算有以下几个缺点

①需要改动原有的代码块,可能会在为了“添加新功能”而改动原有代码的时候,不小心将原有的代码改错了
②如果要添加的功能很多,比如:‘乘方’,‘开方’,‘对数’,‘三角函数’,‘统计’,或者添加一些程序员专用的计算功能,比如:And, Or, Not, Xor,这样就需要在switch语句中添加N个分支语句。想象下,一个计算功能的函数如果有二三十个case分支语句,代码将超过一屏,不仅令代码的可读性大大降低,关键是,为了添加小功能,还得让其余不相关都参与解释,这令程序的执行效率大大降低
 解决途径:采用OOP的继承和多态思想

 1 简单工厂模式的初步实现
2 <?php
3 /**
4 * 操作类
5 * 因为包含有抽象方法,所以类必须声明为抽象类
6 */
7 abstract class Operation{
8 //抽象方法不能包含函数体
9 abstract public function getValue($num1,$num2);//强烈要求子类必须实现该功能函数
10 }
11 /**
12 * 加法类
13 */
14 class OperationAdd extends Operation {
15 public function getValue($num1,$num2){
16 return $num1+$num2;
17 }
18 }
19 /**
20 * 减法类
21 */
22 class OperationSub extends Operation {
23 public function getValue($num1,$num2){
24 return $num1-$num2;
25 }
26 }
27 /**
28 * 乘法类
29 */
30 class OperationMul extends Operation {
31 public function getValue($num1,$num2){
32 return $num1*$num2;
33 }
34 }
35 /**
36 * 除法类
37 */
38 class OperationDiv extends Operation {
39 public function getValue($num1,$num2){
40 try {
41 if ($num2==0){
42 throw new Exception("除数不能为0");
43 }else {
44 return $num1/$num2;
45 }
46 }catch (Exception $e){
47 echo "错误信息:".$e->getMessage();
48 }
49 }
50 }
51 ?>

这里采用了面向对象的继承特性,首先声明一个虚拟基类,在基类中指定子类务必实现的方法(getValue())

分析:通过采用面向对象的继承特性,我们可以很容易就能对原有程序进行扩展,比如:‘乘方’,‘开方’,‘对数’,‘三角函数’,‘统计’等等。

<?php
/**
* 求余类(remainder)
*
*/
class OperationRem extends Operation {
public function getValue($num1,$num2){
return $num1%$num12;
}
}
?>

我们只需要另外写一个类(该类继承虚拟基类),在类中完成相应的功能(比如:求乘方的运算),而且大大的降低了耦合度,方便日后的维护及扩展

现在还有一个问题未解决,就是如何让程序根据用户输入的操作符实例化相应的对象呢?
解决办法:使用一个单独的类来实现实例化的过程,这个类就是工厂
代码如下:

 1 <?php
2 /**
3 * 工程类,主要用来创建对象
4 * 功能:根据输入的运算符号,工厂就能实例化出合适的对象
5 *
6 */
7 class Factory{
8 public static function createObj($operate){
9 switch ($operate){
10 case '+':
11 return new OperationAdd();
12 break;
13 case '-':
14 return new OperationSub();
15 break;
16 case '*':
17 return new OperationSub();
18 break;
19 case '/':
20 return new OperationDiv();
21 break;
22 }
23 }
24 }
25 $test=Factory::createObj('/');
26 $result=$test->getValue(23,0);
27 echo $result;
28 ?>


总结

区别

  1. 简单工厂模式(静态方法工厂模式) : 用来生产同一等级结构中的任意产品。(不能增加新的产品)

  2. 工厂模式 :用来生产同一等级结构中的固定产品。(支持增加任意产品)

  3. 抽象工厂 :用来生产不同产品种类的全部产品。(不能增加新的产品,支持增加产品种类)

适用范围

简单工厂模式:

工厂类负责创建的对象较少,操作时只需知道传入工厂类的参数即可,对于如何创建对象过程不用关心。

工厂方法模式:

满足以下条件时,可以考虑使用工厂模式方法

  1. 当一个类不知道它所必须创建对象的类时

  2. 一个类希望由子类来指定它所创建的对象时

  3. 当类将创建对象的职责委托给多个帮助子类中得某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时

抽象工厂模式:

满足以下条件时,可以考虑使用抽象工厂模式

  1. 系统不依赖于产品类实例如何被创建,组合和表达的细节。

  2. 系统的产品有多于一个的产品族,而系统只消费其中某一族的产品

  3. 同属于同一个产品族是在一起使用的。这一约束必须在系统的设计中体现出来。

  4. 系统提供一个产品类的库,所有产品以同样的接口出现,从而使客户端不依赖于实现。

以上几种,归根结底,都是将重复的东西提取出来,以方便整体解耦和复用,修改时方便。可根据具体需求而选择使用。


如果帮到了您,可以支持一下,谢谢您的支持!


PHP设计模式之 单例模式 工厂模式 实例讲解的更多相关文章

  1. PHP 工厂模式 实例讲解

    简单工厂模式:①抽象基类:类中定义抽象一些方法,用以在子类中实现②继承自抽象基类的子类:实现基类中的抽象方法③工厂类:用以实例化对象 看完文章再回头来看下这张图,效果会比较好 1 采用封装方式 2 3 ...

  2. PHP中“简单工厂模式”实例讲解

    原创文章,转载请注明出处:http://www.cnblogs.com/hongfei/archive/2012/07/07/2580776.html 简单工厂模式:①抽象基类:类中定义抽象一些方法, ...

  3. PHP中“简单工厂模式”实例讲解(转)

      ? 1 2 3 4 5 6 7 8 原创文章,转载请注明出处:http://www.cnblogs.com/hongfei/archive/2012/07/07/2580776.html   简单 ...

  4. C#设计模式(2)-简单工厂模式

    引言 上一遍中介绍了设计模式中的单例模式-C#设计模式(1)-单例模式,本篇将介绍简单工厂模式,也是比较容易理解的一种模式: 简单工厂模式简介 什么是简单工厂模式? 定义一个工厂类,它可以根据参数的不 ...

  5. Java设计模式之二 ----- 工厂模式

    在上一篇中我们学习了单例模式,介绍了单例模式创建的几种方法以及最优的方法.本篇则介绍设计模式中的工厂模式,主要分为简单工厂模式.工厂方法和抽象工厂模式. 简单工厂模式 简单工厂模式是属于创建型模式,又 ...

  6. Java进阶篇设计模式之二 ----- 工厂模式

    前言 在上一篇中我们学习了单例模式,介绍了单例模式创建的几种方法以及最优的方法.本篇则介绍设计模式中的工厂模式,主要分为简单工厂模式.工厂方法和抽象工厂模式. 简单工厂模式 简单工厂模式是属于创建型模 ...

  7. C#设计模式(2)——简单工厂模式(转)

    C#设计模式(2)——简单工厂模式   一.引言 这个系列也是自己对设计模式的一些学习笔记,希望对一些初学设计模式的人有所帮助的,在上一个专题中介绍了单例模式,在这个专题中继续为大家介绍一个比较容易理 ...

  8. Java设计模式之二工厂模式

    在上一篇中我们学习了单例模式,介绍了单例模式创建的几种方法以及最优的方法.本篇则介绍设计模式中的工厂模式,主要分为简单工厂模式.工厂方法和抽象工厂模式. 简单工厂模式 简单工厂模式是属于创建型模式,又 ...

  9. java设计模式---三种工厂模式

    工厂模式提供创建对象的接口. 工厂模式分为三类:简单工厂模式(Simple Factory), 工厂方法模式(Factory Method)和抽象工厂模式(Abstract Factory).GOF在 ...

随机推荐

  1. golang 随机数/域名校验

    //随机数生成要用到的 const letterBytes = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ...

  2. MySQL学习笔记之右连接

    MySQL的右连接 #右连接,以右表为基表 select course.stuid,course.stuname,sex,course,city from class1 right join cour ...

  3. MYSQL日期时间字符串互转

    --MYSQL date_format(date,'%Y-%m-%d') -------------->oracle中的to_char(); 日期时间转字符串 --MYSQL str_to_da ...

  4. 5.26 idea生成javadoc

  5. Django学习案例一(blog):五. 开发主页(博客列表展示)

    主页是一个“博客列表”页.博客要按发布时间的倒序来排列,每个博客都要包含标题.作者.分类.发布时间的显示(年-月-日 时:分)及节选的正文内容(前 100 个字).点击单独的博客可以进入其详情页. 1 ...

  6. Model2

    Model1: Model2:

  7. centos7下安装python3 解决openssl等一系列问题

    最近折腾了下centos7,发现按正常方法安装python3.7后面会出现各种操蛋的问题. 主要的问题有三个,openssl版本过低,'_ctypes'缺失,以及安装后sqlite3缺失.下面我会贴出 ...

  8. node jsonwebtoken

     jsonwebtoken是node版本的JWT(JSON Web Tokens)的实现.1.什么是JWT?Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于J ...

  9. Python 集合 day3

    集合(set)是一个无序的不重复元素序列. 可以使用大括号 { } 或者 set() 函数创建集合,集合用{},里面是一个一个元素,不同于key-value形式的字典: 注意:创建一个空集合必须用 s ...

  10. Redis 应用场景【商品拼团抢购】

    使用到 redis-list llen 命令:获取列表的长度,如果列表key不存在那么也是返回0,如果给的key不是一个列表类型会返回一个错误 lpush命令:将值插入到列表头部,如果 key 不存在 ...