Dart/Flutter 的类似 Python 装饰器的设计模式?

问题描述 投票:0回答:2

我希望在类似装饰器的功能中拥有通用的 try/catch/finally 逻辑,可以“包装”函数或类方法。考虑一下场景:

Class MyClass {
  void someMethodA() {
    doSomeInitialWork();
    
    try {
      doSomething();
    } catch (err) {
      throw err;
    } finally {
      doSomeCleanUpWork();
    }
  }

  void someMethodB() {
    doSomeInitialWork();
    
    try {
      doSomethingElse();
    } catch (err) {
      throw err;
    } finally {
      doSomeCleanUpWork();
    }
  }
}

等等。每个方法的独特部分就是

try
主体。如果我有一堆方法,其中一些方法需要相同的逻辑,是否有一种“好的”方法来避免冗余代码?

理想情况下它可以是这样的语法:

@wrapper
void someMethodA() {
  doSomething();
}

@wrapper
void someMethodB() {
  doSomethingElse();
}

MyClassInstance.someMethodA(); // call it like this and the wrapper takes care of everything

但我知道这些是 Dart 中的注释,不适用于此处。

更新

按照 jamesdlin 的回答,我正在尝试将匿名函数解决方案合并到 futures/async/await 场景中:

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();
    });
  }
}

这似乎可行,但看起来有点混乱。我不确定我在 async/await 示例中所做的是否合适。

flutter dart design-patterns callback decorator
2个回答
8
投票

Dart 中的匿名函数相当常见(与 Python 不同,Python 中

lambda
受到很大限制)。

因此,您可以创建一个辅助函数,将唯一部分作为回调。

void trySomething(void Function() body) {
  doSomeInitialWork();

  try {
    body();
  } catch (err) {
    throw err;
  } finally {
    doSomeCleanUpWork();
  }
}

void someMethodA() {
  trySomething(() {
    doSomething();
  });
}

void someMethodB() {
  trySomething(() {
    doSomethingElse();
  });
}

这基本上就是

test()
中的
package:test
(或 Flutter 中的
testWidgets()
)所做的事情。


更新评论中描述的情况:如果方法返回

Future
s,则没有太大不同。 例如,如果您从以下内容开始:

Future<List<String>> someMethodA() async {
  return await blah();
}

那么你可以这样做:

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();
  });
}

0
投票

在 Python 中,它更加清晰,因为您可以读取参数并将函数标记在顶部。但在 Dart 中你可以使用 lambda 来实现。

注意它适用于同步和异步函数。 “H”适用于任何返回类型:

/// Fetch the web for something
Future<String> getTheWorld() async {
  return await withLog(() async {
    final resp = await http.get(someUri).timeout(_httpTimeout);
    if (resp.statusCode >= 300 || resp.statusCode < 200) {
      throw '${resp.statusCode} ${resp.reasonPhrase} - ${resp.body}';
    }

    return resp.body;
  });
}

/// Wrap your function in this one to have any error logged
R withLog<R>(R Function() func) {
  try {
    return func();
  } catch (e, l) {
    log('$e $l'); //Implement your log function
    rethrow;
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.