Какой шаблон проектирования использовать, когда у нас есть классы, которые выполняют аналогичную высокоуровневую функциональность, но возвращают разные типы в методах?
У меня есть существующее консольное приложение C#, которое принимает аргументы и на основе этих аргументов создает экземпляр markets (UK, US, MX..) с помощью инъекции зависимостей.
Каждый рынок выполняет данную строку метода GetData()', 'строка ProcessData()' и 'bool ExportData()'.
Приложение изначально было создано для рынков одного поставщика электронной коммерции. Теперь мне говорят изменить его для другого поставщика, который выполняет другой процесс. Поток высокого уровня остается тем же самым.
'GetData' для извлечения записей из БД,
"ProcessData" для любой трансформации или тому подобного
'ExportData'.
Разница в том, что Getdata() извлекает записи из БД и сопоставляет их объекту. Я планирую использовать Petapoco. 'ProcessData' может возвращать аналогичный класс. 'Exportdata' в настоящее время выполняет вызов API, но для нового поставщика я должен записать его в файл.
Я читал о паттернах, которые совершенно сбили меня с толку. Сначала я думал, что мне нужен абстрактный фабричный шаблон, а теперь я думаю, что фабричный метод-это то, что я должен использовать, но я не уверен, что делаю это правильно. Здесь вам нужно некоторое руководство/обзор. Пример cs-файла, который я создал из своего понимания фабричного шаблона. Настоящий Кодекс основывается на головой примеров кода.
Как вы думаете, это правильный подход к дизайну?
Я также хочу, чтобы консольный проект был независим от проекта поставщика. Так, может, 'StatusExport.Программа' для консольного приложения. DLL-проекты StatusExport.Common содержат интерфейс и абстрактные классы' и 'StatusExport.Клиент(например:StatusExport.Costco)' для каждого материала поставщика.
Что я уже пробовал:
using System; using System.Collections.Generic; using StatusExport.Models; namespace factorymethod { class Program { static void Main(string[] args) { ClientFactory factory = null; Console.WriteLine("Enter client code:"); string clientCode= Console.ReadLine(); switch (clientCode.ToLower()) { case "costco": factory = new CostcoFactory("accountname", "taskname"); break; //NEw vendor might be added //case "walmart" //factory = new WalmartFactory("taskname", "type"); //break default: break; } bool status = factory.ProcessData(); Console.ReadKey(); } } abstract class Client { public abstract string AccountName { get; } public abstract string Task { get; set; } //More properties might be added. Some may not even be used by some of the new vendors. For example, Costco Might need accountname and task. Tomorrow if walmart comes, they might not need these two or may need task and a new property 'type' public abstract List<T> GetData<T>(); public abstract List<T> ProcessData<T>(); public abstract bool ExportData(); } class CostcoClient : Client { public override string AccountName { get; } public override string Task { get; set; } public CostcoClient(string accountName, string task) { AccountName = accountName; Task = task; } public override List<DBRecord> GetData<DBRecord>() //DBRecord class is specific to Costco. { List<DBRecord> dbresult = new List<DBRecord>(); //dbresult = db return data mapped to an object DBRecord using petapoco. Another vendor might have a different class to which DB records are mapped. So the return type can be generic return asn; } public override List<T> ProcessData<T>() { throw new NotImplementedException(); //Any data transformation or business logic. Return type might be DBRecord or a new class altogether } public override bool ExportData() { throw new NotImplementedException();//Call API or write data to file and if success send true else false } } abstract class ClientFactory { public abstract bool ProcessData(); } class CostcoFactory : ClientFactory { public string AccountName { get; } public string Task { get; set; } public CostcoFactory(string accountname, string task) { AccountName = accountname; Task = task; } public override bool ProcessData() { CostcoClient gc = new CostcoClient(AccountName, Task); var result = gc.GetData<DBRecord>(); return true; } } }
Gerry Schmitz
Посмотрите на "интерфейсы" вместо абстрактных классов. В этом случае абстрактный клиентский класс ничего вам не даст. в частности, у вас есть "абстрактные" свойства, которые не должны быть абстрактными, создавая избыточный код переопределения.