Шаблон проектирования для перевода нескольких форматов данных из нескольких источников в один формат
Я работаю в компании, которая имеет несколько веб-сайтов, и существующая инфраструктура... ну, ужасно.
Прямо сейчас у каждого магазина есть своя таблица, которая различается по структуре. Это быстро становится проблемой (если это еще не было).
Поэтому мне нужно найти способ принимать заказы из нескольких каналов, форматировать их в единый, унифицированный способ, сохранять их с нашей стороны и переводить обратно в формат, ожидаемый API хранилища (который может быть любым: от RESTful JSON до МЫЛО).
Моей первоначальной реакцией на интуицию была смесь шаблонов фабрики, посетителя и строителя (плюс некоторый умный полиморфизм), но она стала слишком сложной слишком быстро. Прежде чем я пойду и закодирую себя в углу с решением, которое может быть неоптимальным, обслуживаемым или расширяемым, есть ли шаблон или набор шаблонов, которые были бы более эффективными?
В принципе, я думаю, что это будет что-то вроде:
Source -> Translator -> Our Format
Our Format -> Translator -> Source
Мне не нужен переводчик, чтобы фактически действовать на основе данных. Все, за что он должен отвечать, - это получить его в правильном формате, и мы можем получить его из пункта А в пункт Б (и наоборот).
Несколько предположений о системе:
- Формат с нашей стороны вряд ли изменится, и поэтому наши объекты вряд ли изменятся
- Когда данные переведены обратно в исходный источник, мы можем предположить, что все, что требуется, будет там. Фактическое поведение для исходящих запросов является небольшим, сфокусированным и четко определенным
3 ответа
Адаптер Pattern ваш друг. Допустим, у вас есть унаследованный класс Customer.
public class CustomerLegacy
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime Birthday { get; set; }
}
Первое, что вы можете сделать, это извлечь этот класс. Этот шаг не является обязательным, но он делает новый класс тестируемым. Итак, у вас будет интерфейс ICustomerLegacy, который выглядит как показано ниже.
public interface ICustomerLegacy
{
string FirstName { get; set; }
string LastName { get; set; }
DateTime Birthday { get; set; }
}
Затем рефакторинг CustomerLegacy
класс для реализации нового интерфейса.
public class CustomerLegacy
: ICustomerLegacy
Следующим шагом является создание адаптера, который принимает ICustomerLegacy
в качестве аргумента конструктора. Вы можете добавить новые свойства для удовлетворения ваших потребностей.
public class CustomerAdapter
{
private readonly ICustomerLegacy customer;
public CustomerAdapter(ICustomerLegacy customer)
{
this.customer = customer;
}
public string FullName
{
get
{
return this.customer.FirstName + " " + this.customer.LastName;
}
}
public int Age
{
get
{
return DateTime.UtcNow.Year - this.customer.Birthday.Year;
}
set
{
// your logic here.
}
}
public void Save()
{
//this.customer.DoSomething();
}
}
Как видите, Adapter Pattern может помочь вам реорганизовать существующий продукт, сделать его тестируемым и привести в порядок устаревший код в одном месте.
Насколько я вижу, вы должны быть в состоянии использовать простой подход для решения этой ситуации, с фабрикой и интерфейсом,
class IStore
{
void Place(Order order);
....other methods
}
class AmazonStore : IStore
{
...implement methods
}
class EbayStore : IStore
{
...implement methods
}
Здесь объект Order должен быть переведен в конкретный API внутри фактической реализации, а также наоборот для любых методов, извлекающих данные.
и затем фабрика может использоваться для создания соответствующего хранилища на основе либо константы, либо на основе Enum.
В одной из моих предыдущих компаний мы работали над аналогичным проектом. Мы принимаем архитектуру труб и фильтров.
Используйте архитектурный стиль "Трубы и фильтры", чтобы разделить большую задачу обработки на последовательность меньших независимых шагов обработки ("Фильтры"), которые связаны каналами ("Трубы").
Каждый фильтр предоставляет очень простой интерфейс: он получает сообщения во входящем канале, обрабатывает сообщение и публикует результаты в исходящем канале. Канал соединяет один фильтр с другим, отправляя выходные сообщения от одного фильтра другому. Поскольку все компоненты используют один и тот же внешний интерфейс, их можно объединить в разные решения, подключив компоненты к разным каналам. Мы можем добавить новые фильтры, опустить существующие или переставить их в новую последовательность - и все это без необходимости менять сами фильтры. Соединение между фильтром и трубой иногда называют портом. В базовой форме каждый компонент фильтра имеет один входной порт и один выходной порт.
Думайте об этом как о своем Source
это насос, ваш Translator
это фильтр. Любая функциональность, добавленная в фильтры, будет основана на соответствующем бизнес-домене. Большая картина выглядит так: