内容来源(公众号:PHP版WEB项目)工厂模式属于创建型模式,提供了一种创建对象的方式。工厂模式是先定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类。使用工厂模式的扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以了,其屏蔽了产品的具体实现,调用者只需关心产品的接口。工厂模式的精髓就是可以根据不同的参数生成不同的类实例。
比如我们定义一个类来实现两个数的加、减、乘、除,代码如下:
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
?>
当需要类再实现一个可以“求余”的运算时,便可在switch语句块中添加一个分支语句,代码需要做如下改动:
<?php
class Calc{
public function calculate($num1,$num2,$operator){
try {
$result=0;
switch($operator){
//………省略………
case '%':
$result= $num1%$num2;
break;
//………省略………
}
}catch(Exception $e){
echo "您输入有误:".$e->getMessage();
}
}
}
?>
用以上方法实现给计算器添加新的功能运算有以下几个缺点:
(1)需要改动原有的代码块,可能会在为了“添加新功能”而改动原有代码的时候不小心将原有的代码改错了。
(2)如果要添加的功能很多,比如“乘方”“开方”“对数”“三角函数”“统计”,或者添加一些程序员专用的计算功能,比如And、Or、Not、Xor,这样就需要在switch语句中添加N个分支语句。想象一下,一个计算功能的函数如果有二三十个case分支语句,代码将超过一屏,不仅令代码的可读性大大降低,关键是为了添加小功能,得不偿失,这令程序的执行效率大大降低。
为了解决以上问题,我们可以采用工厂模式,思路是定义“加减乘除”4个类,这4个类中都有getValue()方法,然后定义一个可以创建“加减乘除”的类,称之为工厂类,该工厂类中有一个工厂方法,我们根据可传入到工厂方法的不同参数(可以是“加减乘除”的数学符号)使用这个工厂类的工厂方法创建“加减乘除”类,然后调用其对应的getValue()方法获得返回结果。
工厂模式代码如下:
//定义接口
interface Calc{
public function getValue($num1,$num2);
}
//创建实现接口的实体类
class Add implements Calc{
public function getValue($num1,$num2) {
return $num1+ $num2;
}
}
class Sub implements Calc{
public function getValue($num1,$num2) {
return $num1 - $num2;
}
}
class Mul implements Calc{
public function getValue($num1,$num2) {
return $num1 * $num2;
}
}
class Div implements Calc{
public function getValue($num1,$num2) {
try {
if($num2 == 0) {
throw new Exception('除数不能为0');
} else {
return $num1/$num2;
}
} catch(Exception $e) {
echo "错误信息:" .$e->getMessage();
}
}
}
//创建一个工厂,生成基于给定信息的实体类的对象
class Factory{
public static function createObj($operate) {
switch($operate) {
case '+':
return new Add();
break;
case '-':
return new Sub();
break;
case '*':
return new Mul();
break;
case '/':
return new Div();
break;
}
}
$test = Factory:createObj('-');
echo $test->getValue(1,4);
?>
这样我们就实现了根据用户输入的操作符实例化相应的对象,进而可完成接下来相应的操作。在软件开发中,PHP可能要链接MySQL,也可能链接SQLServer或者其他数据库,这样我们就可以定义一个工厂类,动态产生不同的数据库链接对象。再比如设计一个连接服务器的框架,需要3个协议,即POP3、IMAP、HTTP,可以把这3个作为产品类,共同实现一个接口。工厂模式的使用场景很多,需要读者在实际开发中尝试应用。
网友评论