这是抽象工厂模式的合法用途吗?

时间:2013-11-26 17:46:33

标签: php design-patterns

以下是我正在尝试在我的程序中实现的内容:

  • 程序应该打开一个包含许多数据文件的zip文件
  • zip文件的数据文件格式可能不同(例如csv,制表符分隔,甚至可能是某种需要解码的二进制文件)
  • 但是,在zip文件中,所有数据文件都属于同一类型

我一直在阅读Gamma等人的“设计模式”,并一直在寻找抽象工厂模式来试图解决这个问题。

理想情况下,我希望Zip文件有一个类,它可以读取其中的任何类型的数据文件。我想我会有两个类 - FileTypeA和FileTypeB,它们可以处理不同格式的数据(尽管将来会有更多)。我想告诉我的ZipFile类在读取数据时使用哪种类型的文件。

到目前为止,这是我提出的:

<?php

/**
 * An abstract factory used for creating data files of any type
 */
abstract class DataFileFactory{
    abstract function createFile($id);
}

/**
 * A factory for creating and setting up a data file of type 'A'
 */
class FileAFactory extends DataFileFactory{
    public function createFile($id){
        $file = new FileA();
        $file->setSampleId($id);
        return $file;
    }
}

/**
 * A factory for creating and setting up a data file of type 'B'
 */
class FileBFactory extends DataFileFactory{
    public function createFile($id){
        $file = new FileB();
        $file->setSampleId($id);
        return $file;
    }
}

/**
 * An abstract class which defines some functionality of a data file
 */
abstract class DataFile{
    abstract function readData();
    abstract function setSampleId();
}

/**
 * Concrete class that processes a data file of type 'A'
 */
class FileA extends DataFile{
    public function readData(){
        echo "Reading data from a file A<br/>";
    }

    public function setSampleId(){
        echo "Setting sample id of a file A<br/>";
    }
}

/**
 * Concrete class that processes a data file of type 'B'
 */
class FileB extends DataFile{
    public function readData(){
        echo "Reading data from a file B<br/>";
    }

    public function setSampleId(){
        echo "Setting sample id of a file B<br/>";
    }
}

/**
 * Concrete class that reads a zip file and reads each file within the zip
 */
class ZipFile{
    private $files = array("file1.txt","file2.txt","file3.txt","file4.txt");//this would be an array read from the zip file
    private $sampleId = 1;//this would be derived from some other function

    /**
     * Read all the files in a zip archive.
     * $factory can be an instance of any class that extends DataFileFactory, and is used for creating each file
     */
    public function readFiles(DataFileFactory $factory){
        foreach($this->files as $fileName){//loop through each file in the zip
            $file = $factory->createFile($this->sampleId);//use the factory to create the desired file
            $file->readData();//now read the data from the file!
            echo "object created of type: ".get_class($file)."<hr/>";
        }
    }
}

/***********************************************************************************************
 * IMPLEMENTATION
 ***********************************************************************************************/
$zip = new ZipFile();//create a new zip file
$factory = new FileAFactory();//instantiate a new factory, depending on which type of file you want to create
$zip->readFiles($factory);//read the files, passing the correct factory object to it

谁能告诉我: (A)这是否是实现我正在寻找的好方法,还是有一些更简单的方法呢? (B)这实际上是抽象工厂模式,还是我完全被误解了?

提前致谢!

1 个答案:

答案 0 :(得分:7)

这是一个很好的实现,但如果你使用接口,它可以稍微调整一下。

带有所有虚拟方法的abtract类它只是一个接口所以不要使用抽象类,请使用interfaces

interface IDataFileFactory{
    public function createFile($id);
}

class FileAFactory implements IDataFileFactory
class FileBFactory implements IDataFileFactory

如果您在FileAFactoryFileBFactory方法中找到重复的代码,那么就可以重构您的类并创建继承。

interface IDataFileFactory{
    public function createFile($id);
}

abstract class BaseFileFactory implements IDataFileFactory {

//some methods implementation with common features to avoid repeating code
//some abstract methods to be implemented for A and B FileFactories
//absolute abstract base class has no sense because in php you can use interfaces.
//...
}

class FileAFactory extends BaseFileFactory
class FileBFactory extends BaseFileFactory

然后使用throug接口:

  public function readFiles(IDataFileFactory $factory){
           //create a file using factory
           return IDataFile; //return Interface implemented by all DataFile types.
        }

您可以使用DataFile基类执行相同的操作,依此类推。

我还建议不要在参数中传递工厂,因为工厂不在上下文中。尽量不要将架构实现与数据和信息处理工作流混合在一起。您可以在可供其他类访问的范围中创建容器来解析工厂。

例如,容器可以读取配置文件以在应用程序引导程序中创建具体工厂;读取某个值,由用户在用户案例的先前步骤中选择,存储在类实例中或在运行时接受参数以解析工厂。它是关于实现某种简单的依赖关系。

无论如何,这只是我的观点,可能是一个不同意见的分歧。

我希望它有所帮助。