Есть ли другой способ избежать дублирования кода в методах, помимо добавления прослойки базовым классом? (есть ли "миксины" для методов?)
Хотелось бы избежать дублирования кода в таких случаях (см. повторяемый паттерн кода в теле методов fetchFoo и fetchBar):
class MyUglyApiClient extends GetConnect {
Object? _lastError;
StackTrace? _lastErrorStacktrace;
Foo foo = Foo();
Bar bar = Bar();
/* ..всякие геттеры приватных свойств вида `lastError`, и прочие.. */
Future<bool> fetchFoo() async {
final res = await getRequest('/foo/', operation: 'Foo op');
if ((lastError != null) || (res == null)) return false;
try {
foo = Foo.fromJson(res);
return (Foo.items.length > 0);
} catch (err, st) {
_lastError = err;
_lastErrorStacktrace = st;
return false;
}
}
Future<bool> fetchBar() async {
final res = await getRequest('/bar/', operation: 'Bar op');
if ((lastError != null) || (res == null)) return false;
try {
/* ..тут всякие предварительные проверки `res`.. */
bar = Bar.fromJson(res);
/* ..тут доп. действия с `bar`.. */
return (bar.count > 0);
} catch (err, st) {
_lastError = err;
_lastErrorStacktrace = st;
return false;
}
}
/* ..вспомогательные методы, типа `getRequest`, `postRequest` и прочие..
}
Тут важно разделение "уровней" проверки ошибок, то есть реализация getRequest уже включает в себе обработку ошибок на уровне сети/доступа (проверки HTTP-кода и формата ответа, создание специфичных Error'ов), а вот эти два метода обрабатывают ошибки уже на уровне полученных данных (содержания серверного ответа) - такое разделение важно сохранить.
Поэтому, пока что вижу здесь только вариант объявления общего метода с коллбэками, типа
Future<bool> fetchGenericData(String url, { String operation, ResponseHandler onRes, DataParser? parser }) {
final res = await getRequest(url, operation: operation);
if ((lastError != null) || (res == null)) return false;
try {
bool isResDataOk = onRes(res);
return (isResDataOk && (parser == null) ? parser(res) : isResDataOk;
} catch (err, st) {
_lastError = err;
_lastErrorStacktrace = st;
return false;
}
, но в таком подходе не нравится то что точки взаимодействия с данными "прибиты гвоздями" к реализации... то есть, такой общий метод придется регулярно рефакторить по мере добавления новой бизнеслогики, и этого конечно желательно избежать.
Еще можно ввести базовый класс "обработчик данных", то есть спрятав try..catch логику в промежуточный слой абстракции, но создание такого класса воспринимается антипаттерном (имхо, много слоев и ветвистые классовые зависимости == переусложнение).
Идеальным решением был бы некий метод-"миксин" с общим try..catch, который я бы примешивал к методам (fetchFoo, fetchBar, и последующим), оставив в них только бизнеслогику работы с уже успешно сфетченными данными... но не получается сообразить, как при этом и работать с данными внутри "общего" try..catch присваивая данные значениям свойств экземпляра MyUglyApiClient, и при этом обойтись без прописывания множества коллбэков. Такое возможно как-то реализовать в Dart, без внесения дополнительных базовых классов?