提到工厂,流水线的工作,不停的重复重复着,真是比我们码农还苦逼。

工厂模式使用的频率也是非常高,它的官方解释为:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂模式使一个类的实例化延迟到其子类。

苦逼的工厂模式(Factory Method Pattern)-LMLPHP


如图所示,系统中有超级用户与普通用户两种,定义一个公共接口User类,定义一个公共抽象工厂类abstractUserFactory,userFactory类通过继承abstractUserFactory类实现创建User类的方法createUser,从而实现工厂模式,实现代码如下:

Php代码

<?php  
abstract class abstractUserFactory {  
    public abstract function createUser();  
}  
  
class userFactory extends <span style="font-size: 1em; line-height: 1.5;">abstractUserFactory </span><span style="font-size: 1em; line-height: 1.5;">{</span>  
Php代码  
    public function createUser( $className ) {  
        try{  
            if(class_exists($className))  
                return new $className();  
            else{  
                $error = "no class";  
                throw new Exception($error);  
            }  
        }catch( Exception $e ) {  
            echo 'Caught exception: ',  $e->getMessage(), "\n";  
        }  
    }  
}  
  
  
interface User{  
    public function getGrade();  
}  
  
class superUser implements User{  
    public function getGrade() {  
        echo 1;  
    }  
}  
  
class commonUser implements User{  
    public function getGrade() {  
        echo 0;  
    }  
}  
  
$userFactory = new userFactory();  
$userFactory->createUser( 'superUser' )->getGrade();  
$userFactory->createUser( 'commonUser' )->getGrade();  
  
运行结果:10Caught exception: no class
登录后复制

工厂模式的优点:

1.良好的封装性,代码结构清晰。一个对象创建是有条件约束的,如一个调用者需要一个具体的产品对象,只要知道这个产品的类名(或约束字符串)就可以了,不用知道创建对象的艰辛过程,降低模块间的耦合。

2.扩展性非常好。在增加产品类的情况下,只要适当地修改具体的工厂类或扩展一个工厂类,就可以完成“拥抱变化”。例如在上面的例子中,需要增加一个蓝钻用户,则只需要增加一个blueUser类,工厂类不用修改任务就可完成系统扩展。

3.屏蔽产品类。这一特点非常重要,产品类的实现如何变化,调用者都不需要关心,它只需要关心产品的接口,只要接口保持不变,系统中的上层模块就不要发生变化。

4.典型的解耦框架。高层模块值需要知道产品的抽象类,其他的实现类都不用关心,符合迪米特法则,我不需要的就不要去交流,也符合依赖倒置原则,只依赖产品类的抽象,当然也符合里氏替换原则,使用产品子类替换产品父类,没问题!

工厂模式的使用场景:

1.工厂模式是new一个对象的替代品,所以在所有需要生成对象的地方都可以使用,但是需要慎重地考虑是否要增加一个工厂类进行管理,增加代码的复杂度。

2.需要灵活的,可扩展的框架时,可以考虑采用工厂模式。万物皆对象,那万物也就是皆产品类。

3.工厂模式可以用在异构项目中。

4.可以使用测试驱动开发的框架下。例如,测试一个类A,就需要把与类A有关联关系的类B也同时产生出来,我们可以用工厂模式把类B虚拟出来,避免类A与类B的耦合。(目前java有jmock和easymock,该场景已弱化)。

工厂模式的扩展:

1.简单工厂模式(PHP常用)

一个模块仅需要一个工厂类,没有必要把它产生出来,使用静态的方法就可以了,根据这一要求,我们把上例中的abstractUserFactory修改一下,如图:

苦逼的工厂模式(Factory Method Pattern)-LMLPHP
去掉了abstractUserFactory抽象类,同时把createUser设置为静态类,简化了类的创建过程。其缺点是工厂类的扩展比较困难,不符合开闭原则,但它仍然是一个非常实用的设计模式。

2.升级为多个工厂类(产品与工厂一对一)

每一个产品类都对应一个创建类,好处是创建类的职责清晰,而且结构简单,但是给可扩展性和可维护性带来了一定的影响。如果要扩展一个产品类,就需要建立一个相应的工厂类,这样就增加了扩展的难度。因为工厂类和产品的数量相同,维护时需要考虑两个对象之间的关系。

当然,在复杂的应用中一般采用多工厂的方法,然后再增加一个协调类,避免调用者与各个子工厂交流,协调类的作用是封装子工厂类,对高层模块提供统一的访问接口。

3.替代单例模式

此模式通过反射将一个定义了private的无参构造方法的类实例化而实现的。目测PHP还无法实现,此处略过。

4.延迟初始化

一个对象被消费完毕后,并不立刻释放,工厂类保持其初始状态,等待再次被使用。对于PHP解释型语言,可以扩展为延迟加载(lazy loading),即在工厂类准备创建新对象时才载入相应的类文件,而不用每次脚本执行期间都加载可能的类。


09-04 11:34