mercredi 1 avril 2020

How to avoid circular dependencies when using a facade pattern across multiple modules

I'm trying to implement a facade pattern to access two different file types, but I keep on running into circular dependencies. Is this common and if so what is the standard way to avoid it?

I have two file-types (A and B) in separate modules which are accessed by a facade in another separate interface.py module. The facade module needs to import the FileType classes from each module in order to return the objects, and also implements a method determine_file_type(path) and a custom error class IncorrectFileType.

I now wish to add an add_data_from_another_file method to FileTypeA. The first thing it needs to do is determine what type of file it's adding data from, but it can't access the interface.determine_file_type method without creating a circular dependency. I'm also unable to raise the IncorrectFileType error from within either file_type_a,b module for the same reason.

## Module: interface.py

from file_type_a import FileTypeA
from file_type_b import FileTypeB

def get_file(path):
    if determine_type(path) == "typeA":
        return FileTypeA(path)
    elif determine_type(path) == "typeB":
        return FileTypeB(path)

def determine_file_type(path):
    ...
    return file_type

class IncorrectFileTypeError(ValueError):
    pass


## Module: file_type_a.py

class FileTypeA():
    def add_data_from_another_file(self, path):
        file_type = determine_file_type(path) ### CAN'T IMPORT THIS
        if file_type == "typeB":
           raise IncorrectFileTypeError() ### CAN'T IMPORT THIS


## Module: file_type_b.py

class FileTypeB():
    pass

One solution could be to implement the determine_file_type as a staticmethod on a AbstractFileType class but this doesn't help me if I need to raise an exception in one of the concrete classes. (It also feels like it might be messy in my real example, but that's probably a separate issue!)

This feels like a classic use of the Facade pattern, so what is the obvious trick I'm missing here?

Aucun commentaire:

Enregistrer un commentaire