В настоящее время я пытаюсь создать библиотеку для абстрагирования от различных веб-API CRUD наших бизнес-подразделений. Я не могу привести реальный пример, но вот основная проблема:
У нас есть N разных API, которые используют более или менее одни и те же ресурсы. Например, есть ресурс для создания пользователя. Для одного API X ресурс называется «пользователь», для другого API Y его «пользователи», и всем им требуются разные поля для запроса на создание. X требует только имя и адрес в виде строки, в то время как Y требует имя в виде строки, но адрес в виде объекта, состоящего из улицы, города и страны.
Мое первое намерение состояло в том, чтобы использовать шаблон адаптера и определить мой собственный класс User вместе со специфическими интерфейсами API.
interface XUser {
name: string;
address: string;
CREATE() : XUserWithId
}
interface YUser {
name: string;
address: {
street: string;
city: string;
country: string
};
CREATE() : YUserWithId
}
interface IUser {
name: string;
street: string;
city: string;
country: string;
}
class User implements IUser {}
Затем я хотел написать свои адаптеры, чтобы мой пользовательский класс вел себя как объекты, специфичные для API:
class XUserAdapter implements XUser {
constructor(user: IUser) {
this.name = user.name;
this.address = [user.street, user.city, user.country].join(", ");
}
}
class YUserAdapter implements YUser {
constructor(user: IUser){
this.name = user.name;
this.address = {
street: user.street;
city: user.city;
country: user.country;
}
}
}
СОЗДАНИЕ пользовательского ресурса в API X и Y теперь сводится к созданию одного пользовательского объекта, помещению его в адаптеры и вызову функций CREATE адаптеров:
users: User[] = [];
tom = new User(name = "Tom", street = "Foostreet", city = "Bartown", country = "USA");
xuser = new XUserAdapter(tom);
yuser = new YUserAdapter(tom);
xuser = xuser.CREATE();
yuser = yuser.CREATE();
Моя проблема в том, что, очевидно, вызов CREATE вернет мне пользовательские объекты платформы, которые я хочу иметь в форме моего собственного класса User. Для этого потребуется еще два адаптера для «перевода» в противоположном направлении:
class UserFromYUser implements IUser {
constructor(yUser: YUser) {
...
}
}
Вопрос: Я упускаю очевидное? Является ли создание одного адаптера для каждого ресурса конкретной платформы действительно правильным решением? Я читал о шаблоне двустороннего адаптера в GoF, но это был всего лишь короткий намек. Ребята, у вас есть какие-либо другие идеи о том, как можно решить эту проблему и как разделить код, но сохранить согласованность между интерфейсами API?
Заранее спасибо.


Похоже, шаблон репозитория — это путь. Как говорит martinfowler.com:
Концептуально репозиторий инкапсулирует набор сохраняемых объектов. в хранилище данных и операций, выполняемых над ними, обеспечивая более объектно-ориентированное представление слоя сохраняемости. Репозиторий также поддерживает цель достижения чистого разделения и одностороннего зависимость между доменом и слоями отображения данных.
Есть очень хорошая статья о том, что такое общий репозиторий. Если у ваших сущностей одинаковые методы, попробуйте использовать этот паттерн.
Это пример кода C#:
public interface IRepository<T>
{
void Insert(T entity);
void Delete(T entity);
void Update(T entity);
IQueryable<T> GetAll();
T GetById(int id);
}
Я отметил ваш ответ как принятый, поскольку, вероятно, нет «верного» ответа на такой вопрос. Если углубиться в проблему, шаблон репозитория предлагает хороший уровень абстракции, чтобы скрыть индивидуальную сложность API.
Благодарю за ваш ответ! Действительно, выглядит очень многообещающе. Я закодировал несколько тестов, и мне кажется, что репозиторий, по крайней мере, дает общее место для всех адаптеров. Отличный намек!