Вы можете создать класс BaseClient, который будет содержать базовую c группу свойств, и если вам нужно добавить что-то новое - просто унаследуйте его. Вы все сделали правильно, но я думаю, что лучше изменить модификатор publi c на protected в ваших свойствах AccountName и Task , чтобы предоставлять к ним доступ только из дочерних классов. Собственно, вы можете создать BaseClientModels (запрос / ответ) для каждого метода, если не уверены, что возвращаемый тип List всегда будет актуальным. Пример:
public abstract class BaseClient
{
#region Properties : Protected
protected abstract string AccountName { get; }
protected abstract string Task { get; set; }
#endregion
#region Methods : Public
public abstract BaseGetDataResponseModel GetData(BaseGetDataRequestModel model);
public abstract BaseProcessDataResponseModel ProcessData(BaseProcessDataRequestModel model);
public abstract BaseExportDataResponseModel ExportData(BaseExportDataRequestModel model);
#endregion
}
public class BaseGetDataResponseModel { }
public class BaseGetDataRequestModel { }
public class BaseProcessDataResponseModel { }
public class BaseProcessDataRequestModel { }
public class BaseExportDataResponseModel { }
public class BaseExportDataRequestModel { }
Затем давайте посмотрим на ваш класс CostcoClient и как он может выглядеть:
public class CostcoClient : BaseClient
{
#region Properties : Protected
protected override string AccountName { get; }
protected override string Task { get; set; }
protected virtual IDataReader<BaseGetDataRequestModel, BaseGetDataResponseModel> DataReader { get; }
protected virtual IDataProcessor<CostcoClientProcessDataRequestModel, CostcoClientProcessDataResponseModel> DataProcessor { get; }
protected virtual IExportDataHandler<CostcoClientExportDataRequestModel, CostcoClientExportDataResponseModel> ExportDataHandler { get; }
#endregion
#region Constructors
public CostcoClient(string accountName, string task)
{
//set DataReader, DataProcessor, ExportDataHandler
AccountName = accountName;
Task = task;
}
#endregion
#region Methods : Public
public override BaseGetDataResponseModel GetData(BaseGetDataRequestModel model)
{
if (model is CostcoClientGetDataRequestModel clientGetDataRequestModel)
{
return DataReader.ReadData(clientGetDataRequestModel);
}
return null; //wrong type has passed
}
public override BaseProcessDataResponseModel ProcessData(BaseProcessDataRequestModel model)
{
if (model is CostcoClientProcessDataRequestModel clientProcessDataRequestModel)
{
return DataProcessor.ProcessData(clientProcessDataRequestModel);
}
return null;
}
public override BaseExportDataResponseModel ExportData(BaseExportDataRequestModel model)
{
if (model is CostcoClientExportDataRequestModel clientExportDataRequestModel)
{
return ExportDataHandler.Handle(clientExportDataRequestModel);
}
return null;
}
#endregion
}
public class CostcoClientGetDataRequestModel : BaseGetDataRequestModel { }
public class CostcoClientGetDataResponseModel : BaseGetDataResponseModel { }
public class CostcoClientProcessDataRequestModel : BaseProcessDataRequestModel { }
public class CostcoClientProcessDataResponseModel : BaseProcessDataResponseModel { }
public class CostcoClientExportDataRequestModel : BaseExportDataRequestModel { }
public class CostcoClientExportDataResponseModel : BaseExportDataResponseModel { }
public interface IDataReader<TIn, TOut>
{
public TOut ReadData(TIn model);
}
public interface IDataProcessor<TIn, TOut>
{
public TOut ProcessData(TIn model);
}
public interface IExportDataHandler<TIn, TOut>
{
public TOut Handle(TIn model);
}
public class CostcoClientDataReader : IDataReader<CostcoClientGetDataRequestModel, CostcoClientGetDataResponseModel>
{
public CostcoClientGetDataResponseModel ReadData(CostcoClientGetDataRequestModel model)
{
throw new NotImplementedException();
}
}
//and so on
Вы должны реализовать IDataReader , IDataProcessor , IExportDataHandler , сделайте ваш лог c и вызовите его из GetData , ProcessData , ExportData методы, как пример, и получить экземпляры через внедрение зависимостей.
Затем мы можем изменить ваш завод на это:
public interface IClientFactory
{
BaseClient GetClientService(ClientServicesEnum value);
}
public class BaseClientFactory : IClientFactory
{
#region Propertied : Protected
protected virtual IEnumerable<BaseClient> Services { get; }
protected string AccountName { get; }
protected string Task { get; set; }
#endregion
#region Constructors
public BaseClientFactory(IEnumerable<BaseClient> services, string accountname, string task)
{
Services = services;
AccountName = accountname;
Task = task;
}
#endregion
public BaseClient GetClientService(ClientServicesEnum value)
=> Services.First(x => x.GetType().Equals(GetClientServiceByCode()[value]));
private Dictionary<ClientServicesEnum, Type> GetClientServiceByCode()
=> new Dictionary<ClientServicesEnum, Type>()
{
{ ClientServicesEnum.CostcoClient, typeof(CostcoClient) }
};
}
public enum ClientServicesEnum
{
CostcoClient = 1,
Another2 = 2,
Another3 = 3
}
Где
protected virtual IEnumerable<BaseClient> Services { get; }
вы также можно получить через DI, а затем получить правильный ServiceHandler с помощью enum.
И ваша основная функция для вызова всего этого:
switch (clientCode)
{
case 1:
baseClient = ClientFactory.GetClientService(ClientServicesEnum.CostcoClient);
break;
case 2:
baseClient = ClientFactory.GetClientService(ClientServicesEnum.Another2);
break;
default:
break;
}
bool status = baseClient.ProcessData(null); //your model
Главное - вы можете использовать более одного шаблона , например один из Creational patterns и один из Structural. Если мне нужна помощь в архитектуре кода, я использую это: https://refactoring.guru/
Я думаю, с помощью этого примера вы можете удалить свойства AccountName и Task , из-за моделей запросов в методах.