Python decorator-like design pattern for Dart/Flutter?
Anonymous functions in Dart are rather common (unlike Python, where lambda
is very restricted).
You therefore could make a helper function that takes the unique part as a callback.
void trySomething(void Function() body) {
doSomeInitialWork();
try {
body();
} catch (err) {
throw err;
} finally {
doSomeCleanUpWork();
}
}
void someMethodA() {
trySomething(() {
doSomething();
});
}
void someMethodB() {
trySomething(() {
doSomethingElse();
});
}
That's basically what test()
from package:test
(or testWidgets()
from Flutter) do.
Update for the case described in the comment: It's not much different if the methods return Future
s. For example, if you start with:
Future<List<String>> someMethodA() async {
return await blah();
}
then you could do:
Future<R> trySomethingAsync<R>(Future<R> Function() body) async {
doSomeInitialWork();
try {
return await body();
} catch (err) {
throw err;
} finally {
doSomeCleanUpWork();
}
}
Future<List<String>> someMethodA() {
return trySomethingAsync(() async {
return await blah();
});
}
user1087973
Updated on December 27, 2022Comments
-
user1087973 over 1 year
I'd like to have common try/catch/finally logic in a decorator-like feature that can "wrap" a function or class method. Consider the scenario:
Class MyClass { void someMethodA() { doSomeInitialWork(); try { doSomething(); } catch (err) { throw err; } finally { doSomeCleanUpWork(); } } void someMethodB() { doSomeInitialWork(); try { doSomethingElse(); } catch (err) { throw err; } finally { doSomeCleanUpWork(); } } }
So on and so forth. The unique parts of each method are just the
try
body. If I have a bunch of methods, some which require the same logic, is there a "nice" way to avoid redundant code?Ideally it could be syntax like:
@wrapper void someMethodA() { doSomething(); } @wrapper void someMethodB() { doSomethingElse(); } MyClassInstance.someMethodA(); // call it like this and the wrapper takes care of everything
but I know those are annotations in Dart and not applicable here.
UPDATE
Following jamesdlin answer, I am trying to incorporate the anonymous function solution to a futures/async/await scenario:
Future<dynamic> trySomething(Future<dynamic> Function() callback) async { doSomeInitialWork(); try { return await callback(); } catch (err) { throw err; } finally { doSomeCleanUpWork(); } } class MyClass { Future<List<String>> someMethodA() async { return await trySomething(() async { return await someApiCall(); }); } }
That seems to work, but it looks kind of messy. I'm not sure if what I'm doing in the async/await example is appropriate.
-
user1087973 about 3 yearsTo make things a bit more complicated, what if the methods return futures? So instead of
void someMethodA() {}
it isFuture<List<String>> someMethodA() async {return await blah();}
. I'm not sure what the anonymous function looks like now and how to wrap the body. -
jamesdlin about 3 years@user1087973 Sorry, I didn't see your comment before. If you haven't figured it out on your own yet, I've updated my answer for your case.