在向新技术过渡时,我们失去了通常的开发工具。 在某些情况下,由于某些技术限制,我们不得不忍受他们的缺席,但如果可能,我们会随身携带这些工具。 在开发android应用程序时,我以Fernando Cejas提出的干净架构为例 。 了解Flutter中使用的设计模式后,我决定放弃此架构,转而使用BLoC。 我很快就习惯了这个模板,它与我之前使用的MVVM非常相似,但是我不想忍受一个细节。 调用存储库方法时,我必须捕获异常,将其转换为某种类型,并根据类型创建必要的状态。 在我看来,这非常混乱,我移植了先前在基于Fernando的android项目中使用的Either类型。
两者都来自函数式编程语言。 它提供以下一种可能类型的值:
该实现非常基础,不如其他语言的解决方案,但可以应付其任务。 我将这种类型用作存储库的所有方法的结果,并将异常处理转移到数据层。 这消除了对try / catch构造的需要,这使代码更具可读性。
尝试/捕获示例 class ContactBloc { final ContactRepository contactRepository; ContactBloc(this.contactRepository); @override Stream<ContactState> mapEventToState(ContactEvent event) async* { if (event is GetContactEvent) { yield LoadContactState(); try { var contact = contactRepository.getById(event.id); yield ContactIsShowingState(contact); } on NetworkConnectionException catch (e) { yield NetworkExceptionState(e); } catch (e) { yield UnknownExceptionState(e); } } } } abstract class ContactRepository { Future<Contact>getById(int id); }
任一示例 class ContactBloc { final ContactRepository contactRepository; ContactBloc(this.contactRepository); @override Stream<ContactState> mapEventToState(ContactEvent event) async* { if (event is GetContactEvent) { yield LoadContactState(); final either = contactRepository.getById(event.id); if (either.isRight) { final contact = either.right; yield ContactIsShowingState(contact); } else { final failure = either.left; if (failure is NetworkFailure) yield NetworkFailureState(failure); if (failure is UnknownFailure) yield UnknownFailureState(failure); } } } } abstract class ContactRepository { Future<Either<Failure, Contact>>getById(int id); }
关于可读性,可能有人会争论。 也许有人习惯尝试/捕捉并以他自己的方式正确,在大多数情况下,这就是调味。 另一个好处是,我们自己可以定义“失败”层次结构并在左侧返回。 让我们做一个抽象的故障,将其与所有继承继承的ServerFailure,NetworkFailure功能以及当前功能的某些ContactFailure特定功能通用。 在该区块中,我们将确切知道预期会发生哪种故障。
在Dart上执行Failure的缺点是缺乏象kotlin中那样的密封类 ,否则就不会使用强制转换。 该语言还很年轻,正在积极发展,我希望时间到了,我们将拥有可以更简洁地编写处理程序的工具。
有人可能不喜欢这种实现,可能会觉得毫无意义,但我只是想向您介绍Dart中采用功能性方法进行错误处理的可能性,尽管使用起来并没有其他语言那么优雅。
资源:
源代码