Design pattern for supporting transferring data from multiple sources to destinations

I am working on a small program - the main feature of the program it to 'transfer' 'data' from one 'place' to another, and also record stats (like timestamps, success or not, etc.) to sqlite db. Besides, the program should be able to retry for a few times if transfer fails.

Currently, the assumptions for 'data', 'place' and 'transfer' is simple:

  • the data can only be a file in the host machine
  • the destination can be a location in the host machine or a remote server
  • the methods for transferring the data can only be 'rsync' (which uses rsync command in the host machine)

I have 2 main questions:

  1. What is an appropiate design pattern for this program, if the program may scale in the future. There could be more methods for transferring data such as ftp, cloud server command line tools, etc. The program may need to handle if the the data is a directory (in which case, it will transfer the entire directory to the destination). The database it records stats to could be other types like mysql or postgres.
  2. How should 'record stats to sqlite db' be related to the transfer feature? Is it better to separate them?


  • If I got this right, you want to design your system to be open to new features such as new transferring methods and data types.

    To implement all transferring methods, you should expose an interface to define the transferring service. This interface plays an important role in your design and should be simple to keep the implementation details separated from the client's requirements. For example, don't include credential information on the interface definition. Keep it in the concrete classes and inject the information into the constructor.

    All your transferring methods must implement the ITransferService interface (they will be the strategies as in the strategy pattern)

    It's better to use the command pattern to handle the transfer. For example, use a command class to express the input argument of the interface method.

    It's better to use the factory pattern to choose which transferring service to use.

    To support future data types, you should use the composite pattern to define your data structures.

    All these suggestions help you to comply with the SOLID principles, especially the open-close principle. This design makes the software easy to change and add new features.