Quantcast
Channel: Planet Python
Viewing all articles
Browse latest Browse all 22462

Krzysztof Żuraw: Factory pattern in python

$
0
0

What is factory pattern all about? It introduces abstraction. In other words: helps software developers with the problem of creating objects without knowing exact class of the object that will be created.

Why use it? From programmers stack exchange:

(...) they allow the project to follow the SOLID principles more closely. In particular, the interface segregation and dependency inversion principles.

Factories and interfaces allow for a lot more long term flexibility. It allows for a more decoupled - and therefore more testable - design. (...)

  • It allows you to introduce an IoC container easily
  • It makes your code more testable as you can mock interfaces
  • It gives you a lot more flexibility when it comes time to change the application (i.e. you can create new implementations without changing the dependent code)

As we know why to use it let's jump into the code:

classBaseArchive(object):EXTENSION=Nonedef__init__(self,location_path,files_to_pack):self.location_path=location_pathself.files_to_pack=files_to_packdefgenerate(self):raiseNotImplementedError()

At first, I created a simple base class to have a common interface for all archive classes. There is nothing sophisticated here: only setting up all necessary arguments in __init__ and telling that all children of BaseArchive have to implement generate method. Let's look how these children look like:

fromzipfileimportZipFileimporttarfileclassZIPArchive(BaseArchive):defgenerate(self):withZipFile(self.location_path,'w')aszip_file:forfile_inself.files_to_pack:zip_file.write(file_)classTARArchive(BaseArchive):defgenerate(self):withtarfile.open(self.location_path,'w')astar_file:forfile_inself.files_to_pack:tar_file.add(file_)

Basically, ZIPArchive and TARArchive classes have generate method to create archives in given format using ZipFile or tarfile modules from standardlib as follows:

zip_archive=ZIPArchive(os.path.join(os.getcwd(),'zip.zip'),['for_zip'])zip_archive.generate()tar_archive=TARArchive(os.path.join(os.getcwd(),'tar.tar'),['for_tar.txt'])tar_archive.generate()

Then the real fun begins. Say I want to generate archive just only by providing path and files to pack into the archive. For this purpose I use something called ArchiveManager which is factory:

classArchiveManager(object):ARCHIVE_ENGINES=[ZIPArchive,TARArchive]def__init__(self,location_path,files_to_pack):self.location_path,self.extension=os.path.splitext(location_path)self.files_to_pack=files_to_packself.archive_engine=self.choose_archive_engine()defchoose_archive_engine(self):forengineinself.ARCHIVE_ENGINES:ifengine.check_extenstion(self.extension):returnengine(self.location_path,self.files_to_pack)defcreate_archive(self):self.archive_engine.generate()

Here I have ARCHIVE_ENGINES class attribute for every archive engine that I want to use. Below in __init__ I setup all necessary attributes with extension to use in choose_archive_engine. Here is the place where factory pattern starts to work: I iterate through all engines to check_extenstion and if there is a match I simply return the correct engine to self.archive_engine. To use that I need to write some more code in ZIPArchive and TARArchive:

classZIPArchive(BaseArchive):EXTENSION='.zip'@classmethoddefcheck_extenstion(cls,extension):ifextension==cls.EXTENSION:returnTrueelse:returnFalseclassTARArchive(BaseArchive):EXTENSION='.tar'@classmethoddefcheck_extenstion(cls,extension):ifextension==cls.EXTENSION:returnTrueelse:returnFalse

These check_extenstion that are classmethods helps me in figuring out which underlying archive class should I use. Thanks to that in ArchiveManager.create_archive I only need to provide self.archive_engine.generate(). This method doesnt't know if there is ZIPArchive or TARArchive class being used.

This was quick introduction how to use factory pattern in python. The code for this is available in this repo. Do you know more usages? Or maybe you don't agree with what I write- feel free to comment.

Cover image by Tpsdave released into public domain.


Viewing all articles
Browse latest Browse all 22462

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>