PHP设计模式之 单例模式 工厂模式 实例讲解
单例模式又称为职责模式,它用来在程序中创建一个单一功能的访问点,通俗地说就是实例化出来的对象是唯一的。
所有的单例模式至少拥有以下三种公共元素:
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 ?>
总结
区别
简单工厂模式(静态方法工厂模式) : 用来生产同一等级结构中的任意产品。(不能增加新的产品)
工厂模式 :用来生产同一等级结构中的固定产品。(支持增加任意产品)
抽象工厂 :用来生产不同产品种类的全部产品。(不能增加新的产品,支持增加产品种类)
适用范围
简单工厂模式:
工厂类负责创建的对象较少,操作时只需知道传入工厂类的参数即可,对于如何创建对象过程不用关心。
工厂方法模式:
满足以下条件时,可以考虑使用工厂模式方法
当一个类不知道它所必须创建对象的类时
一个类希望由子类来指定它所创建的对象时
当类将创建对象的职责委托给多个帮助子类中得某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时
抽象工厂模式:
满足以下条件时,可以考虑使用抽象工厂模式
系统不依赖于产品类实例如何被创建,组合和表达的细节。
系统的产品有多于一个的产品族,而系统只消费其中某一族的产品
同属于同一个产品族是在一起使用的。这一约束必须在系统的设计中体现出来。
系统提供一个产品类的库,所有产品以同样的接口出现,从而使客户端不依赖于实现。
以上几种,归根结底,都是将重复的东西提取出来,以方便整体解耦和复用,修改时方便。可根据具体需求而选择使用。
如果帮到了您,可以支持一下,谢谢您的支持!
PHP设计模式之 单例模式 工厂模式 实例讲解的更多相关文章
- PHP 工厂模式 实例讲解
简单工厂模式:①抽象基类:类中定义抽象一些方法,用以在子类中实现②继承自抽象基类的子类:实现基类中的抽象方法③工厂类:用以实例化对象 看完文章再回头来看下这张图,效果会比较好 1 采用封装方式 2 3 ...
- PHP中“简单工厂模式”实例讲解
原创文章,转载请注明出处:http://www.cnblogs.com/hongfei/archive/2012/07/07/2580776.html 简单工厂模式:①抽象基类:类中定义抽象一些方法, ...
- PHP中“简单工厂模式”实例讲解(转)
? 1 2 3 4 5 6 7 8 原创文章,转载请注明出处:http://www.cnblogs.com/hongfei/archive/2012/07/07/2580776.html 简单 ...
- C#设计模式(2)-简单工厂模式
引言 上一遍中介绍了设计模式中的单例模式-C#设计模式(1)-单例模式,本篇将介绍简单工厂模式,也是比较容易理解的一种模式: 简单工厂模式简介 什么是简单工厂模式? 定义一个工厂类,它可以根据参数的不 ...
- Java设计模式之二 ----- 工厂模式
在上一篇中我们学习了单例模式,介绍了单例模式创建的几种方法以及最优的方法.本篇则介绍设计模式中的工厂模式,主要分为简单工厂模式.工厂方法和抽象工厂模式. 简单工厂模式 简单工厂模式是属于创建型模式,又 ...
- Java进阶篇设计模式之二 ----- 工厂模式
前言 在上一篇中我们学习了单例模式,介绍了单例模式创建的几种方法以及最优的方法.本篇则介绍设计模式中的工厂模式,主要分为简单工厂模式.工厂方法和抽象工厂模式. 简单工厂模式 简单工厂模式是属于创建型模 ...
- C#设计模式(2)——简单工厂模式(转)
C#设计模式(2)——简单工厂模式 一.引言 这个系列也是自己对设计模式的一些学习笔记,希望对一些初学设计模式的人有所帮助的,在上一个专题中介绍了单例模式,在这个专题中继续为大家介绍一个比较容易理 ...
- Java设计模式之二工厂模式
在上一篇中我们学习了单例模式,介绍了单例模式创建的几种方法以及最优的方法.本篇则介绍设计模式中的工厂模式,主要分为简单工厂模式.工厂方法和抽象工厂模式. 简单工厂模式 简单工厂模式是属于创建型模式,又 ...
- java设计模式---三种工厂模式
工厂模式提供创建对象的接口. 工厂模式分为三类:简单工厂模式(Simple Factory), 工厂方法模式(Factory Method)和抽象工厂模式(Abstract Factory).GOF在 ...
随机推荐
- 获取端口号且stiop
- Struts/Hibernate/Spring源码下载
Struts: https://olex.openlogic.com/packages/struts Hibernate: https://olex.openlogic.com/packages/hi ...
- java多线线程停止正确方法
//军队线程 //模拟作战双方的行为 public class ArmyRunnable implements Runnable { //volatile保证了线程可以正确的读取其他线程写入的值 // ...
- 拓扑排序(Topological Order)
Date:2019-06-17 14:43:59 算法描述 1.定义队列Q,并把所有入度为0的结点加入队列 2.取队首结点,输出.然后删除所有从它除法的边,并令这些边到达的顶点的入度-1,若某个顶点的 ...
- UI Testing
UI Test能帮助我们去验证一些UI元素的属性和状态.Apple 在 Xcode 7 中新加入了一套 UI Testing 的工具,其目的就是解决自动化UI测试这个问题.新的 UI Testing ...
- 洛谷P1616 疯狂的采药【完全背包】
题目描述 LiYuxiang是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师.为此,他想拜附近最有威望的医师为师.医师为了判断他的资质,给他出了一个难题.医师把他带到一个到处都是草药的山洞里对他说 ...
- [luogu4290 HAOI2008]玩具取名(DP)
传送门 Solution 裸区间DP Code #include <map> #include <cmath> #include <cstdio> #include ...
- Nginx Rewrite(伪静态)
一.作用: 实现URL地址改写. 二.语法: 例:rewrite ^/(.*) http://bbs.wangguangtao.com/$1 permanent; 注:应用位置server.loeat ...
- 面试官问你如何解决web高并发这样回答就好了
所谓高并发,就是同一时间有很多流量(通常指用户)访问程序的接口.页面及其他资源,解决高并发就是当流量峰值到来时保证程序的稳定性. 我们一般用QPS(每秒查询数,又叫每秒请求数)来衡量程序的综合性能,数 ...
- 什么是hashMap,初始长度,高并发死锁,java8 hashMap做的性能提升
问题1:HashM安排的初始长度,为什么? 初始长度是 16,每次扩展或者是手动初始化,长度必须是 2的幂. 因为: index = HashCode(Key) & (length - 1), ...