If you have different interchangeable implementations of data providers, then this s is a place where Strategy pattern can be used:
Strategy pattern is a behavioral software design pattern that enables
selecting an algorithm at runtime. Instead of implementing a single
algorithm directly, code receives run-time instructions as to which in
a family of algorithms to use.
Let me show an example.
We need to have some common behaviour that will be shared across all strategies. In our case, it would be just one Get()
method from different data providers:
public interface IDataProvider
{
string Get();
}
And its concrete implementations. These are exchangeable strategies:
public class RabbitMQDataProvider : IDataProvider
{
public string Get()
{
return "I am RabbitMQDataProvider";
}
}
public class ApiDataProvider : IDataProvider
{
public string Get()
{
return "I am ApiDataProvider";
}
}
public class CsvDataProvider : IDataProvider
{
public string Get()
{
return "I am CsvDataProvider";
}
}
We need a place where all strategies can be stored. And we should be able to get necessary strategy from this store. So this is a place where simple factory can be used. Simple factory is not Factory method pattern and not Abstract factory.
public enum DataProviderType
{
RabbitMq, Api, Csv
}
public class DataProviderFactory
{
private Dictionary<DataProviderType, IDataProvider> _dataProviderByType
= new Dictionary<DataProviderType, IDataProvider>()
{
{ DataProviderType.RabbitMq, new RabbitMQDataProvider() },
{ DataProviderType.Api, new ApiDataProvider() },
{ DataProviderType.Csv, new CsvDataProvider() },
};
public IDataProvider GetInstanceByType(DataProviderType dataProviderType) =>
_dataProviderByType[dataProviderType];
}
and then you can get instance of desired storage easier:
DataProviderFactory dataProviderFactory = new();
IDataProvider dataProvider = dataProviderFactory
.GetInstanceByType(DataProviderType.Api);
string data = dataProvider.Get();
This design is compliant with the open/closed principle. So if you would need to add other storages, then:
- you would add new class with new strategy
- you will not edit
StorageService
class
And it is compliant with open closed principle.