2013-11-26 48 views
4

这里就是我想在我的程序来实现:这是抽象工厂模式的合法使用吗?

  • 程序应该打开一个压缩文件,其中包含许多数据文件
  • 数据文件的格式可以zip文件之间的差异(如CSV ,制表符分隔的,甚至可能是某种二进制文件这就需要解码)
  • 然而,一个zip文件中的所有数据文件是相同类型

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

理想情况下,我想为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)这实际上是抽象工厂模式,还是我完全误解了?

在此先感谢!

+0

刚刚在这里切线,但你有没有考虑使用特征来处理你的一些“复制和粘贴”方法?在你的例子中:readData()和setSampleId()。 –

+0

感谢您的建议 - 但是,我使用的是PHP v5.3.5,并且只有v5.4.0的特性!任何其他建议/答案将受到欢迎! – user1578653

+0

是的,我还有另一个建议...改为5.4^_ ^。但是,如果我有一些有用的补充,我会:) –

回答

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 

然后使用通过量接口:

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

你可以做同样的事情DataFile基类等。

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

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

无论如何,这只是我的观点而已,可能是一笔巨大的分歧。

我希望它有帮助。

+0

非常感谢您的回答。我同意你关于使用接口 - 我认为在这种情况下没有理由使用抽象类。关于依赖注入,像这样做会更好吗? http://pastebin.com/3R7JH9nK – user1578653

+0

虽然在本书中,我正在阅读的示例代码显示将工厂作为参数传递 - 我只是想知道是否将它放入DI容器会导致不必要的混乱... – user1578653

+0

我的意思是一个静态类(无实例)解析工厂(从配置文件中读取,在前一个流程步骤中设置静态属性,在应用程序初始化或传递参数中)在可访问的范围内。无论如何,这是我个人的喜好,从我的经验。我喜欢从架构实施中保持流程数据工作流的清洁。对我来说,最好在参数中传递$ id(工作流中的过程数据),而不是工厂或DI容器实例(架构实现)。 – jlvaquero