一、为什么要用工厂模式
用一个简单的场景举例为什么要用工厂模式。
假如我们要开发一个计算器,计算器目前有加减乘除四种运算,目前我们可以在一个函数里用一个switch来判断。
function operate($number1,$number2,$operate){
switch ($operate){
case '+':
return $number1+$number2;
case '-':
return $number1-$number2;
case '*':
return $number1*$number2;
case '/':
if(0 != $number2)
return $number1/$number2;
return false;
}
}
目前看来是没有什么问题,但是如果我们接下来扩展这个计算器呢,加上x^y,x%y,logx等等,那么每一个操作都要添加到这个switch里,最终将导致这个switch会非常大,同时每一个操作都要进行全部的比对,维护起来将会很蛋疼,而且代码本身的可读性也会非常差,更不要说如果做的操作复杂一些的话,每一个switch都会很长。
二、使用简单工厂模式
使用面向对象的方法来解决问题。
1. 我们把加减乘除这些操作都分散到每一个类里,成为他们的功能。
2. 通过一个专门的类来判断实例化哪一个类的对象。
三、php代码实现
/**
* 简单工厂模式。
* 主要用于解决各种实例化对象的问题。
* @author sui
* @date 2016-2-15
*/
class SimpleFactory{
public static function createProduct($productType){
$operationClass = "Operation".$productType;
return new $operationClass();
}
}
abstract class Operation{
//抽象方法“运算”,其子类必须实现operate这个方法
abstract public function operate($number1,$number2);
}
//加法类
class OperationAdd extends Operation{
public function __construct () {
echo "加法类被实例化\n";
}
public function operate ($number1,$number2){
$result = $number1+$number2;
echo "{$number1} + {$number2} = {$result}\n";
}
}
//减法类
class OperationMinus extends Operation{
public function __construct () {
echo "减法类被实例化\n";
}
public function operate ($number1,$number2){
$result = $number1-$number2;
echo "{$number1} - {$number2} = {$result}\n";
}
}
//乘法类
class OperationMultiple extends Operation{
public function __construct () {
echo "乘法类被实例化\n";
}
public function operate ($number1,$number2){
$result = $number1+$number2;
echo "{$number1} + {$number2} = {$result}\n";
}
}
//除法类
class OperationDivide extends Operation{
public function __construct () {
echo "除法类被实例化\n";
}
public function operate ($number1,$number2){
if(0 != $number2){
$result = $number1+$number2;
echo "{$number1} / {$number2} = {$result}\n";
}else{
echo "错误除数\n";
}
}
}
使用工厂模式:
$opAdd = SimpleFactory::createProduct('Add');
echo $opAdd->operate(1,2);
$opMinus = SimpleFactory::createProduct('Minus');
echo $opMinus->operate(1,2);
$opMultiple = SimpleFactory::createProduct('Multiple');
echo $opMultiple->operate(1,2);
$opDivide = SimpleFactory::createProduct('Divide');
echo $opDivide->operate(1,2);
输出:
四、时序图和类图
时序图
类图
五、模式分析
- 将对象的创建和对象本身业务处理分离可以降低系统的耦合度,使得两者修改起来都相对容易。
- 在调用工厂类的工厂方法时,由于工厂方法是静态方法,使用起来很方便,可通过类名直接调用,而且只需要传入一个简单的参数即可,在实际开发中,还可以在调用时将所传入的参数保存在XML等格式的配置文件中,修改参数时无须修改任何源代码。
- 简单工厂模式最大的问题在于工厂类的职责相对过重,增加新的产品需要修改工厂类的判断逻辑,这一点与开闭原则是相违背的。
- 简单工厂模式的要点在于:当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节。
六、优缺点
编号 | 优点 | 缺点 |
---|---|---|
1 | 工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象。 | 由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。 |
2 | 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量。 | 使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。 |
3 | 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。 | 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。 |
4 | – | 简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。 |