介绍
工厂模式(Factory Pattern)属于设计模式中的创建型模式,它提供了一种创建对象的最佳方式。定义一个创建对象的接口,通过子类来完成对象的实例化,代码层面只提供实例化类的名称,无需关心实例化的过程,降低业务代码和创建对象的耦合。工厂模式又分为三种模式,简单工厂模式、工厂方法模式、抽象工厂模式。
简单工厂模式
模拟一个业务使用场景,现在要根据文件后缀来设置不同的处理方法,比如后缀为 .doc 的文件和后缀为 .xlsx 的文件都需要用 handleFile 方法处理,可以定义一个接口 File 在里边规定 handleFile 方法,代码示例如下:
<?php
interface File
{
public function handleFile();
}
class DocFile implements File
{
public function handleFile()
{
echo 'doc 文件的处理方式';
}
}
class XlsxFile implements File
{
public function handleFile()
{
echo 'xlxs 文件的处理方式';
}
}
//创建工厂类,通过调用静态方法完成类的实例化
class ChooseFile
{
public static function createDoc()
{
return new DocFile();
}
public static function createXlxs()
{
return new XlsxFile();
}
}
//调用 Doc 文件的处理方法
$doc = ChooseFile::createDoc();
$doc->handleFile();
//调用 Xlxs 文件的处理方法
$xlxs = ChooseFile::createXlxs();
$xlxs->handleFile();
通过这个例子可以看到,根据客户端的选择,可以实例化不同的类,可以使业务代码和接口完成解耦,但是该模式违反了面向对象编程原则中的 开放封闭原则(Open Closed Principle) ,并且只有一个工厂类负责所有方法的实现,如果后期需要扩展,只能修改工厂类,静态方法也无法继承,注定了该模式只适合实例化类少或是较为简单的应用场景。
关于开放封闭原则的知识补充
该原则的是面向对象编程的核心,对扩展开放,对修改封闭。软件需求总是会发生变化的,对应用的扩展是软件设计必须考虑的,减少对类的修改可以增强类的独立性,降低代码之间的耦合。在上边的例子中,ChooseFile 提供一个对客户端的访问接口,是一个已完成的类,如果需要引入其他的文件处理方式,就需要修改这个工厂类,这就违反了“对修改封闭”的原则。
工厂方法模式
常说的工厂模式,其实就是该模式,因为解决了简单工厂模式中的开放封闭原则的问题,扩展更加方便,所以使用最多。还以上边提到的应用场景为例,我们现在如果要加入新的文件格式 .php ,通过改造工厂类,定义接口,具体的类实例化工作由子类完成,如果需要添加扩展,就新增文件处理的扩展类和工厂子类示,例如下:
<?php
interface File
{
public function handleFile();
}
class DocFile implements File
{
public function handleFile()
{
echo 'doc 文件的处理方式';
}
}
class XlsxFile implements File
{
public function handleFile()
{
echo 'xlxs 文件的处理方式';
}
}
//新增PHP文件的处理类
class PhpFile implements File
{
public function handleFile()
{
echo 'PHP 文件的处理方式';
}
}
//创建工厂接口,由子类实现接口的方法
interface CreateFile
{
public function getInstance();
}
class CreateDoc implements CreateFile
{
public function getInstance()
{
return new DocFile();
}
}
class CreateXlsx implements CreateFile
{
public function getInstance()
{
return new XlsxFile();
}
}
class CreatePhp implements CreateFile
{
public function getInstance()
{
return new PhpFile();
}
}
//doc
$doc = new CreateDoc();
$docFile = $doc->getInstance();
$docFile->handleFile();
//xlsx
$xlsx = new CreateXlsx();
$xlsxFile = $doc->getInstance();
$xlsxFile ->handleFile();
//php
$php = new CreatePhp();
$phpFile = $php->getInstance();
$phpFile ->handleFile();
工厂方法模式解决了开闭原则的问题,扩展不需要修改原有代码,但是增加越多的文件处理方式,就需要同步增加相应的文件处理类和工厂子类,类的数量增加会带来系统复杂度的提升。
抽象工厂模式
相比工厂方法模式,该模式进一步对代码进行了抽象,通过接口的形式对产品进行归纳约束,并再通过抽象类组合多种产品,形成完整的对象,如下例子:
1.先是定义了文件接口 TextFile、系统接口 System;
2.再对每个接口具体实现 DocFile 、XlsxFile 、Windows 、Mac ;
3.定义抽象类 AbstractFactory,描述文件类和系统类的关系;
4.再对抽象类具体实现 WinFile 、MacFile;
5.创建类的构造器 FactoryFile->getFactory();
6.工厂输出产品。
<?php
//定义文件接口
interface TextFile
{
public function read();
public function write();
}
//Doc文件处理类的具体实现
class DocFile implements TextFile
{
public function read()
{
echo 'doc read';
}
public function write()
{
echo 'doc write';
}
}
//Xlsx文件处理类的具体实现
class XlsxFile implements TextFile
{
public function read()
{
echo 'xlsx read';
}
public function write()
{
echo 'xlsx write';
}
}
//系统接口定义
interface System
{
public function upload();
}
//windows 系统类具体实现
class Windows implements System
{
public function upload()
{
echo '上传到 Windows';
}
}
//Mac 系统类具体实现
class Mac implements System
{
public function upload()
{
echo '上传到 Mac OS';
}
}
//定义抽象类,描述文件和系统的关系
abstract class AbstractFactory
{
abstract public function getFile($fileType);
abstract public function getSystem($systemType);
}
//windows 操作系统的抽象类实现
class WinFile extends AbstractFactory
{
public function getFile($fileType)
{
return new $fileType;
}
public function getSystem($systemType)
{
return new $systemType;
}
}
//Mac 操作系统的抽象类实现
class MacFile extends AbstractFactory
{
public function getFile($fileType)
{
return new $fileType;
}
public function getSystem($systemType)
{
return new $systemType;
}
}
//实例化抽象类的子类
class FactoryFile
{
public function getFactory($factory)
{
return new $factory;
}
}
//测试类
class Client
{
public function getInfo()
{
$factoryFile = new FactoryFile();
$winFactory = $factoryFile->getFactory('WinFile');
$docFile = $winFactory->getFile('DocFile');
$docFile->read();
$docFile->write();
$system = $winFactory->getSystem('Windows');
$system->upload();
}
}
$client = new Client();
$client->getInfo();
抽象工厂模式是三种模式里最难理解的一种,并且该模式的扩展会违反开闭原则,它适合用来描述工厂中多产品之间的关联。
网友评论