php面向对象之工厂模式示例
简单工厂模式:
①抽象基类:类中定义抽象一些方法,用以在子类中实现
②继承自抽象基类的子类:实现基类中的抽象方法
③工厂类:用以实例化对象
先看一种代码:
<?php
class Calc{
/**
* 计算结果
*
* @param int|float $num1
* @param int|float $num2
* @param string $operator
* @return int|float
*/
public function calculate($num1,$num2,$operator){
try {
$result=0;
switch ($operator){
case '+':
$result= $num1+$num2;
break;
case '-':
$result= $num1-$num2;
break;
case '*':
$result= $num1*$num2;
break;
case '/':
if ($num2==0) {
throw new Exception("除数不能为0");
}
$result= $num1/$num2;
break;
}
return $result;
}catch (Exception $e){
echo "您输入有误:".$e->getMessage();
}
}
}
$test=new Calc();
// echo $test->calculate(2,3,'+');//打印:5
echo $test->calculate(5,0,'/');//打印:您输入有误:除数不能为0
?>
优点:以上代码使用了面向对象的封装特性,只要有了include这个类,其他页面就可以随便使用了
缺点:无法灵活的扩展和维护
比如:想要增加一个“求余”运算,需要在switch语句块中添加一个分支语句,代码需要再加一个case进行判断
于是产生了以下问题
①需要改动原有的代码块,可能会在为了“添加新功能”而改动原有代码的时候,不小心将原有的代码改错了
②如果要添加的功能很多,比如:‘乘方’,‘开方’,‘对数’,‘三角函数’,‘统计’,或者添加一些程序员专用的计算功能,比如:And, Or, Not, Xor,这样就需要在switch语句中添加N个分支语句。想象下,一个计算功能的函数如果有二三十个case分支语句,代码将超过一屏,不仅令代码的可读性大大降低,关键是,为了添加小功能,还得让其余不相关都参与解释,这令程序的执行效率大大降低。
解决途径:采用OOP的继承和多态思想
<?php
/**
* 操作类
* 因为包含有抽象方法,所以类必须声明为抽象类
*/
abstract class Operation{
//抽象方法不能包含函数体
abstract public function getValue($num1,$num2);//强烈要求子类必须实现该功能函数
}
/**
* 加法类
*/
class OperationAdd extends Operation {
public function getValue($num1,$num2){
return $num1+$num2;
}
}
/**
* 减法类
*/
class OperationSub extends Operation {
public function getValue($num1,$num2){
return $num1-$num2;
}
}
/**
* 乘法类
*/
class OperationMul extends Operation {
public function getValue($num1,$num2){
return $num1*$num2;
}
}
/**
* 除法类
*/
class OperationDiv extends Operation {
public function getValue($num1,$num2){
try {
if ($num2==0){
throw new Exception("除数不能为0");
}else {
return $num1/$num2;
}
}catch (Exception $e){
echo "错误信息:".$e->getMessage();
}
}
}
?>
<?php
/**
* 操作类
* 因为包含有抽象方法,所以类必须声明为抽象类
*/
abstract class Operation{
//抽象方法不能包含函数体
abstract public function getValue($num1,$num2);//强烈要求子类必须实现该功能函数
}
/**
* 加法类
*/
class OperationAdd extends Operation {
public function getValue($num1,$num2){
return $num1+$num2;
}
}
/**
* 减法类
*/
class OperationSub extends Operation {
public function getValue($num1,$num2){
return $num1-$num2;
}
}
/**
* 乘法类
*/
class OperationMul extends Operation {
public function getValue($num1,$num2){
return $num1*$num2;
}
}
/**
* 除法类
*/
class OperationDiv extends Operation {
public function getValue($num1,$num2){
try {
if ($num2==0){
throw new Exception("除数不能为0");
}else {
return $num1/$num2;
}
}catch (Exception $e){
echo "错误信息:".$e->getMessage();
}
}
}
?>
这里采用了面向对象的继承特性,首先声明一个虚拟基类,在基类中指定子类务必实现的方法(getValue())
分析:通过采用面向对象的继承特性,我们可以很容易就能对原有程序进行扩展,比如:‘乘方’,‘开方’,‘对数’,‘三角函数’,‘统计’等等。
我们只需要另外写一个类(该类继承虚拟基类),在类中完成相应的功能(比如:求乘方的运算),而且大大的降低了耦合度,方便日后的维护及扩展.
现在还有一个问题未解决,就是如何让程序根据用户输入的操作符实例化相应的对象呢?
解决办法:使用一个单独的类来实现实例化的过程,这个类就是工厂.
<?php
/**
* 工程类,主要用来创建对象
* 功能:根据输入的运算符号,工厂就能实例化出合适的对象
*
*/
class Factory{
public static function createObj($operate){
switch ($operate){
case '+':
return new OperationAdd();
break;
case '-':
return new OperationSub();
break;
case '*':
return new OperationSub();
break;
case '/':
return new OperationDiv();
break;
}
}
}
$test=Factory::createObj('/');
$result=$test->getValue(23,0);
echo $result;
?>
我对些的总结就是:根据传递的参数(对象)不同,调用不同的工厂(类)。然后用以实现指定的功能。比较大的好处就是简化了以前函数化编程的switch case,if else之类,进行类的分发,不同的东西调用不同的类。
观察者模式也是php面向对象中的一个不常用的模式了,下面我们一起来看看php面向对象:观察者模式示例,希望对给各位带来帮助。意图:
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新【GOF95】
又称为发布-订阅(Publish-Subscribe)模式、模型-视图(Model-View)模式、源-监听(Source-Listener)模式、或从属者(Dependents)模式
结构图:
主要角色
抽象主题(Subject)角色:主题角色将所有对观察者对象的引用保存在一个集合中,每个主题可以有任意多个观察者。抽象主题提供了增加和删除观察者对象的接口。
抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在观察的主题发生改变时更新自己。
具体主题(ConcreteSubject)角色:存储相关状态到具体观察者对象,当具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个具体子类实现。
具体观察者(ConcretedObserver)角色:存储一个具体主题对象,存储相关状态,实现抽象观察者角色所要求的更新接口,以使得其自身状态和主题的状态保持一致。
优点和缺点
优点:观察者和主题之间的耦合度较小,支持广播通信。
缺点:由于观察者并不知道其它观察者的存在,它可能对改变目标的最终代价一无所知。这可能会引起意外的更新。
适用场景
当一个抽象模型有两个方面,其中一个方面依赖于另一个方面。
当对一个对象的改变需要同时改变其它对象,而不知道具体有多少个对象待改变。
当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换句话说,你不希望这些对象是紧密耦合的。
实现代码
<?php
/**
* 观察者模式
* @package design pattern
*/
/**
* 抽象主题角色
*/
interface Subject {
/**
* 增加一个新的观察者对象
* @param Observer $observer
*/
public function attach(Observer $observer);
/**
* 删除一个已注册过的观察者对象
* @param Observer $observer
*/
public function detach(Observer $observer);
/**
* 通知所有注册过的观察者对象
*/
public function notifyObservers();
}
/**
* 具体主题角色
*/
class ConcreteSubject implements Subject {
private $_observers;
public function __construct() {
$this->_observers = array();
}
/**
* 增加一个新的观察者对象
* @param Observer $observer
*/
public function attach(Observer $observer) {
return array_push($this->_observers, $observer);
}
/**
* 删除一个已注册过的观察者对象
* @param Observer $observer
*/
public function detach(Observer $observer) {
$index = array_search($observer, $this->_observers);
if ($index === FALSE || ! array_key_exists($index, $this->_observers)) {
return FALSE;
}
unset($this->_observers[$index]);
return TRUE;
}
/**
* 通知所有注册过的观察者对象
*/
public function notifyObservers() {
if (!is_array($this->_observers)) {
return FALSE;
}
foreach ($this->_observers as $observer) {
$observer->update();
}
return TRUE;
}
}
/**
* 抽象观察者角色
*/
interface Observer {
/**
* 更新方法
*/
public function update();
}
class ConcreteObserver implements Observer {
/**
* 观察者的名称
* @var <type>
*/
private $_name;
public function __construct($name) {
$this->_name = $name;
}
/**
* 更新方法
*/
public function update() {
echo 'Observer', $this->_name, ' has notified.<br />';
}
}
$subject = new ConcreteSubject();
/* 添加第一个观察者 */
$observer1 = new ConcreteObserver('Martin');
$subject->attach($observer1);
echo '<br /> The First notify:<br />';
$subject->notifyObservers();
/* 添加第二个观察者 */
$observer2 = new ConcreteObserver('phppan');
$subject->attach($observer2);
echo '<br /> The Second notify:<br />';
$subject->notifyObservers();
/* 删除第一个观察者 */
$subject->detach($observer1);
echo '<br /> The Third notify:<br />';
$subject->notifyObservers();
排序算法的种类是多种多样,各有各的长处,这几天会一一进行分析。学习应该有一个先后递进的过程,从容易的开始。
先说比较简单的 — 插入排序(由PHP代码实现,这里不讲究效率!)
/**
* 插入排序 -- 比冒泡稍微复杂一点的排序算法 *
*
**/
$array = array('5','6','3','1','2','4');
/**
* 插入排序1 -- 使用最暴力的排序
*
**/
function insertSort($array)
{
$count = count($array); //先取出一个数据最为比较数据
for($i=1;$i<$count;$i++)
{
$key = $array[$i];
$j = $i-1;
while($j>=0 && $array[$j]>$key)
{
$array[$j+1] = $array[$j];
$j = $j-1;
$array[$j+1] = $key;
}
var_dump($array);
}
}
insertSort($array);
下面是运行结果:
嗯,整个算法已经完了!如果你只想要代码的。你事情已经完成了,下面开始讲原理。
插入排序之所以叫插入排序,我们可以形象的理解为:
你摸牌的时候,你手里的牌是有序的,而你从牌堆里摸的牌是随机出现的,你只需跟你手里的牌进行比较排序,就能确定新牌的位置
插入的排序的逻辑可以简单的理解为,从第二个元素前,开始跟第一个元素进行比较,如果比对一个元素小,该元素就插入到第一个元素的前面
如果大,则跟第二个元素进行比较,以此类推。(从效果图中,可以看出来)
再来看看插入排序的时间发杂度:
最优的情况,所有的N-1个元素只需要跟前面的元素比较一次,那么时间复杂度是n-1;
最差的勤快,所有的N-1个元素都需要跟前面的所有元素比较一次,那么时间复杂度是一个等差数列 ((n-1)*(n-2))/2+(n-1);
综上所述:插入排序的时间复杂度应该是位于这两则之间。
空间复杂度: 插入排序是一种线性排序。所有空间复杂度跟参与排序的N有关。
PHPExcel是一个php 操作excel表格的插件了,我们可以使用它来进行数据导入或导入操作,但有时我们需要一些特殊的列名,那么要如何操作。今天导出Excel的时候,列不是固定的,而且有差不多几十个,横轴由’A’变为了’AA’,给导出时增加了难度,因为要去算列名称,不过换个方式想一下,发现是很有规律的26进制数。 发现秘诀后就好办了,发一个10进制转26进制的方法。
private function numberToStr26($n)
{
$s = '';
while ($n > 0) {
$m = $n % 26;
if ($m == 0) $m = 26;
$s = chr($m + 64) . $s;
$n = ($n - $m) / 26;
}
return $s;
}
看张效果图片
“PHP不用第三个变量交换两个变量的值”这个题看到过好多次了,看来面试确实喜欢考这道题。今天,对于这个题目,我自己总结了几种方法,可能不全,大家来互相补充。
方法一:使用字符串截取
<?php
$a = "fsdfds";
$b = "xiaorui";
$a = $a.$b;
$b = substr($a,0,strlen($a)-strlen($b));
$a = substr($a,strlen($b));
echo $a."-".$b;
?>
方法二:使用list()
<?php
$a = "php";
$b = "java";
//list()不是函数,是语言结构,它是将数组中的值赋给一些变量
list($a,$b) = array($b,$a);
echo $a.'---'.$b; //java---php
?>
方法三:使用数组分割
<?php
$a = "fsdfds";
$b = "xiaorui";
$b = $a."#$".$b;
$b = explode("#$",$b);
$a = $b[1];
$b = $b[0];
echo $a."-".$b;
?>
说明:这种方法也可以用于交换两个变量的值,但是这个方法听说好像不太标准,因为有人说这里的数组$b也算是一个新变量了(我有点不同意,看怎么理解了)。
方法四:使用异或运算
<?php
$a = "fsdfds";
$b = "xiaorui";
$a = $a^$b;
$b = $b^$a;
$a = $a^$b;
echo $a."-".$b;
?>
说明:这个方法是网上看到的,我仔细试了一下,发现这个居然是有BUG的。用次方法只能交换字符相同的两个字符串型的变量,不然结果是不正确的。
网上又找到一些方法
//字符串版本 结合使用substr,strlen两个方法实现
$a="a";
$b="b";
echo '交换前 $a:'.$a.',$b:'.$b.'<br />';
$a.=$b;
$b=substr($a,0,(strlen($a)-strlen($b)));
$a=substr($a, strlen($b));
echo '交换后$a:'.$a.',$b:'.$b.'<br />';
echo '-----------------------<br/>';
//字符串版本 使用str_replace方法实现
$a="a";
$b="b";
echo '交换前 $a:'.$a.',$b:'.$b.'<br />';
$a.=$b;
$b=str_replace($b, "", $a);
$a=str_replace($b, "", $a);
echo '交换后$a:'.$a.',$b:'.$b.'<br />';
echo '-----------------------<br/>';
//字符串版本 结合使用list方法和array实现
$a="a";
$b="b";
echo '交换前 $a:'.$a.',$b:'.$b.'<br />';
list($b,$a)=array($a,$b);
echo '交换后$a:'.$a.',$b:'.$b.'<br />';
echo '-----------------------<br/>';
//字符串和数字都适用 使用异或运算
$a='a';
$b='b';
echo '交换前 $a:'.$a.',$b:'.$b.'<br />';
$a=$a^$b;
$b=$b^$a;
$a=$a^$b;
echo '交换后$a:'.$a.',$b:'.$b.'<br />';
echo '-----------------------<br/>';
//只适用于数字
$a=3;
$b=5;
echo '交换前 $a:'.$a.',$b:'.$b.'<br />';
$a=$a+$b;
$b=$a-$b;
$a=$a-$b;
echo '交换后$a:'.$a.',$b:'.$b.'<br />';
相关文章
- 这篇文章主要介绍了java8如何用Stream查List对象某属性是否有重复的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-11
- 这篇文章主要介绍了R语言删除指定变量或对象的操作方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-05-06
- 这篇文章主要介绍了JavaScript预解析,对象的的相关资料,小编觉得这篇文章写的还不错,需要的朋友可以参考下,希望能够给你带来帮助...2021-11-10
- 这篇文章主要为大家介绍了JavaScript设计模式中的装饰者模式,对JavaScript设计模式感兴趣的小伙伴们可以参考一下...2016-01-21
- 神马是“解释器模式”?先翻开《GOF》看看Definition:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。在开篇之前还是要科普几个概念: 抽象语法树: 解释器模式并未解释如...2014-06-07
- 这篇文章主要介绍了Postgresl 如何选择正确的关闭模式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-18
如何在Spring WebFlux的任何地方获取Request对象
这篇文章主要介绍了如何在Spring WebFlux的任何地方获取Request对象,帮助大家更好的理解和使用springboot框架,感兴趣的朋友可以了解下...2021-01-26牛叉的Jquery――Jquery与DOM对象的互相转换及DOM的三种操作
只有jQuery对象才能调用jQuery类库的各种函数,同样有些dom对象的属性和方法在jQuery上也是无法调用的,不过基本上jQuery类库提供的函数包含了所有的dom操作。这就需要我们知道如何将jQuery对象和DOM的相互转换的方法。1...2015-10-30- 很多集成的PHP环境(PHPnow WAMP Appserv等)自带的MySQL貌似都没有开启MySQL的严格模式,何为MySQL的严格模式,简单来说就是MySQL自身对数据进行严格的校验(格式、长度、类型等),比如一个整型字段我们写入一个字符串类型的数...2013-10-04
- js调试中经常会碰到输出的内容是对象而无法打印的时候,光靠alert只能打印出object标示,却不能打印出来里面的内容,甚是不方便,于是各方面整理总结了如下一个函数,能够将数组或者对象这类的结果一一打印出来,具体代码如下: fu...2015-10-21
- 这篇文章主要介绍了JavaScript设计模式之职责链模式,对设计模式感兴趣的同学,可以参考下...2021-04-25
- 这篇文章主要介绍了javascript self对象使用详解的相关资料,需要的朋友可以参考下...2016-10-20
- 本文给大家介绍如何替换json对象中的key,通过实例代码给大家介绍key的替换方法,代码也很简单,需要的朋友参考下吧...2021-06-02
- 下面将把C#里实现IDispose模式的代码展现出来,大家一起来学习一下,它的使用场合也很多的,当我们手动对网站,数据库作封装时,都会用的到...2020-06-25
- 这篇文章主要介绍了详解Javascript中的Object对象,需要的朋友可以参考下...2016-03-01
C# MVC模式中应该怎样区分应用程序逻辑(Controller层)和业务逻辑(Model层)?
这篇文章主要介绍了C# MVC模式中应该怎样区分应用程序逻辑(Controller层)和业务逻辑(Model层)?,这也小编做.NET项目时经常思考和让人混乱的一个问题,这篇文章写的挺好,一下清晰了许多,需要的朋友可以参考下...2020-06-25- 在web页面中,图片居左,内容居右排列,是非常常见的效果,它也就是媒体对象,它是一种抽象的样式,可以用来构建不同类型的组件。本文给大家介绍Bootstrap媒体对象的实现,感兴趣的朋友一起学习吧...2016-05-04
- 这篇文章主要为大家介绍了JavaScript设计模式中的状态模式,对JavaScript设计模式感兴趣的小伙伴们可以参考一下...2016-01-12
ActiveX部件不能创建对象:dm.dmsoft代码:800A01AD
vbs调用插件报:ActiveX部件不能创建对象,代码:800A01AD,一般是因为病毒导致dll文件丢失或者64系统问题导致,需要的朋友可以参考下...2020-06-30- 这篇文章主要为大家介绍了JavaScript事件对象,了解JavaScript事件...2016-01-26