美文网首页PHP开发PHP经验分享
编程中的设计模式之工厂模式

编程中的设计模式之工厂模式

作者: phpworkerman | 来源:发表于2020-07-06 21:56 被阅读0次
    介绍

    工厂模式(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();
    

    抽象工厂模式是三种模式里最难理解的一种,并且该模式的扩展会违反开闭原则,它适合用来描述工厂中多产品之间的关联。

    相关文章

      网友评论

        本文标题:编程中的设计模式之工厂模式

        本文链接:https://www.haomeiwen.com/subject/mwgiqktx.html