在Flutter应用程序中使用杂质



我在游戏开发公司工作,但作为家庭爱好,最近我对开发移动应用程序感兴趣。 因此,当一个朋友邀请我参加使用Flutter框架开发移动应用程序的会议时,我很高兴地同意了。 在那儿试用了Flutter之后,我决定肯定要研究这项技术。 由于开发所需的Dart对我来说并不陌生,因此强制性计划中还包括语言学习。 在仔细研究了代码示例之后,我发现Dart是我真正喜欢的一种易于理解和简洁的语言。 我喜欢的Dart的功能之一是杂质。

什么是杂质?


首先,我将摘录Wikipedia
Admixture (英语混入)是编程语言(通常是类或模块)的元素,可实现一些明确定义的行为。 用于阐明其他类的行为,并非旨在生成独立使用的对象。
在Dart中,此类构造由名称前的单词mixin定义。

上面的定义意味着我们获得了可以添加到其他类的逻辑隔离行为的功能。

它是否使您想起了多重继承的可能性? 是的,但是在我看来,杂质方法更好。 为什么,让我们看一个例子。

假设我们有一个抽象类Animal。

abstract class Animal { void voice(); } 

还有实现Animal类的Cat和Dog类。

 class Cat extends Animal { void voice() { print(“Meow”); } } class Dog extends Animal { void voice() { print(“Woof”); } } 

然后我们突然需要...
猫狗

是的,是的,我个人在开发过程中没有这些东西。

在多重继承的情况下,我们会做同样的事情。

 class CatDog extends Cat, Dog { } 

但是,一旦我们向宠物发出语音命令,我们就会遇到非常不愉快的情况-不清楚他应该确切回答什么,因为这两种方法都实现了语音方法。 这种情况众所周知,被称为钻石问题致命钻石死亡

致命的死亡钻石

在通过杂质进行销售的情况下,我们将不会遇到这种情况。

 lass Animal { void voice() { print(“Hakuna Matata!”); } } mixin Cat { void voice() { print(“Meow”); } } mixin Dog { void voice() { print(“Woof”); } } class CatDog extends Animal with Cat, Dog { } 

如果现在发出语音命令,我们会听到什么? 在这种情况下-织物就像您已经了解的那样,取决于杂质的添加顺序。 发生这种情况是因为它们的添加不是并行的,而是顺序的。

我专门实现了Animal类来标记Dart 2.1中引入的功能。 在此之前,只能将杂质添加到从Object继承的类中。 从2.1版开始,实现了向继承人添加任何类的功能。

这种机制使制作和使用该功能的公共部分变得非常方便,从而解决了代码重复的问题。 让我们来看一个例子。

 abstract class Sportsman { void readySteadyGo(); } mixin SkiRunner { void run() { print(“Ski, ski, ski”); } } mixin RifleShooter { void shot() { print(“Pew, pew, pew”); } } class Shooter() extends Sportsman with RifleShooter { void readySteadyGo() { shot(); } } class Skier() extends Sportsman with SkiRunner { void readySteadyGo() { run(); } } class Biathlete() extends Sportsman with SkiRunner, RifleShooter { void readySteadyGo() { run(); shot(); } } 

如您所见,我们按杂质分布了所有重复的代码,并且在每个实现中仅使用了必要的代码。

在开发过程中,可能会出现一种情况,即任何杂质的功能都不应公开提供给所有类别。 也可以使用一种机制来强加这些限制。 这是admixture声明中的on关键字以及类名。 因此,我们仅将杂质的使用限制为实现指定的或从其继承的类。

例如:

 class A { } abstract class B { } mixin M1 on A { } mixin M2 on B { } 

然后我们可以声明类似的类:

 class C extends A with M1 { } class D implements B with M2 { } 

但是我们在尝试声明如下内容时遇到错误:
 class E with M1, M2 { } 

在Flutter应用程序中的用法


正如我上面提到的那样,杂质使您摆脱了重复代码,并使单独的逻辑部分可以重复使用。 但是,这对于Flutter一般适用吗?Flutter中的所有事物都是原子的,因此分为负责某种功能的小部件? 作为示例,我立即想到了一个情况,该项目使用许多小部件,其显示取决于特定的内部状态。 我将在BLoC体系结构中考虑此示例,并使用rxDart库中的实体。

我们需要一个接口来关闭流量控制器。

 /// Interface for disposable objects abstract class Disposable { void dispose(); } 

我们用于实现状态支持的混合物。

 /// Mixin for object which support state mixin StateProvider implements Disposable { static const NONE_STATE = "None"; final _stateController = BehaviorSubject<String>(seedValue: NONE_STATE); Observable<String> get stateOut => _stateController.stream; String get currentState => _stateController.value; void setState(String state) { _stateController.sink.add(state); } @override void dispose() { _stateController.close(); } } 

控制小部件状态的逻辑部分。 让她通过调用方法设置状态,并在3秒钟后将其更改为另一个状态。

 /// Example BLoC class ExampleBloc implements Disposable with StateProvider { static const EXAMPLE_STATE_1 = "EX1"; static const EXAMPLE_STATE_2 = "EX2"; Timer _timer; void init() { setState(EXAMPLE_STATE_1); _timer = new Timer(const Duration(seconds: 3), () { _timer = null; setState(EXAMPLE_STATE_2); }); } @override void dispose() { if (_timer != null) { _timer.cancel(); _timer = null; } } } 

而小部件本身将响应状态更改。 想象一下使用依赖注入获得所需的逻辑组件。

 class ExampleWidget extends StatelessWidget { final bloc = di<HomePageBloc>(); @override Widget build(BuildContext context) { return StreamBuilder( stream: bloc.stateOut, builder: (BuildContext context, AsyncSnapshot<String> snapshot) { // build widget by state }, ); } } 

如果需要的话,我们甚至可以将编写的内容添加到混合中,只需要使用接口来实现builder方法,但是在我看来这已经是不必要的了,因为在项目中不太可能会有很多这样的简单小部件,因为这只是一个例子。 尽管如此,使用这种混合物,状态支持功能的逻辑部分将很容易添加到任何BLoC中。

结论


在我看来,使用杂质的机制似乎是一种非常有趣且灵活的开发工具,它使构建简单,易于理解和方便的体系结构成为可能。 对于我自己,我认为我的工具包中的这个工具显然不是多余的,我希望它也对您有用。

资源:
飞镖语言之旅
维基百科

Source: https://habr.com/ru/post/zh-CN467143/


All Articles