几次问同事一个问题,就是不清楚为什么通常需要Dart语言的mixins(杂质)。 我决定查看互联网上有关此问题的内容。 可能引起很多文章困扰的是,他们主要谈论如何使用杂质,但没有解释为什么需要使用杂质,在这种情况下,使用杂质比使用普通继承或接口实现更可取。 本文试图填补这一空白。
尽管Internet上有足够的文章讨论Dart和Flutter中的杂质,但在我看来,它们并没有使您澄清,因为给出的示例显示了构造带有杂质的类的纯机制,这远非合理的,因此不能证明其实际应用范围。 。 我特别遇到了这样一个例子 。 我们有:
class Animal {} class Dog {} class Cat {}
由于某种原因,我们希望获得一种同时具有猫和狗特性的动物。 在这种情况下,我们可以这样做:
class CatDog extends Animal with Cat, Dog {}
此示例至少有两个问题:
- 为什么我们需要猫和狗之间的十字架?
- 猫和狗为什么不继承
Animal
? 他们不是动物吗?
同时,为什么仍然需要杂质呢?这仍然是一个谜。
以我的拙见,为了理解杂质的含义,需要开始考虑继承关系的问题。 OOP中继承的要点是,一个实体是另一实体的变体 。 例如,
是人物的变体
或者
是
的变体。 而这正是构建类层次结构的决定因素。
如果从不同的角度看待继承,我们将看到
继承了
的属性,而
继承了
的属性。 如果您不关注逻辑,那么纯粹从技术上讲,您可能希望继承几个不同实体的属性。 为此,某些编程语言支持多重继承 。
多重继承由于存在许多缺点而受到批评(请参阅Wikipedia ),因此许多编程语言根本不使用多重继承,而是使用一种用于实现接口和/或杂质的机制。 并且,从逻辑的角度来看,由多重继承产生的结构不容易理解。
为了理解以下内容,有必要从基本逻辑中回顾一些概念。 特别是本质和非本质属性的概念。 对象的基本属性是由于存在而导致的,它指的是特定类别的对象。 对象的非必需属性是指那些属性的存在,不存在或特定值不会影响属于某一类对象的对象。 例如,矩形的形状是该图形的基本属性,因为如果我们更改此形状(删除或添加侧面或更改角度),则该矩形将不再是矩形。 但是,如果您调整矩形的大小,则它仍将是矩形。 因此,尺寸是微不足道的属性。
建立类层次结构通常是基于将任何基本属性添加到父类。 举个例子
abstract class Shape { void draw(); } class Rectangle extends Shape { @override void draw() { print('Draw rectangle'); } } class Circle extends Shape { @override void draw() { print('Draw circle'); } }
该层次结构的基础是图形形状的基本属性。
另一个例子:
abstract class Widget { void render(); } class Container extends Widget { @override void render() { print('Renders container'); } } class Text extends Widget { @override void render('Render text'); }
小部件的用途是这里的基本属性。
现在假设我们需要向我们的实体添加一些非必要的属性。 这样的属性例如是颜色。 现在让我们为某些形状和小部件着色。
为此,您当然可以使用继承并首先实现PaintableShape
和PaintableWidget
。 但这并不方便,因为首先,我们必须在两个层次结构中都复制着色功能的实现,其次,对于我们要着色的每个图形和小部件,我们都必须实现新的类,例如PaintableRect
和PaintableContainer
。
您可以使用该机制来实现接口。 然后我们得到这样的东西:
enum Color {red, yellow, green} abstract class Paintable { void paint(Color color); Color get color; } class PaintableRect extends Rectangle implements Paintable { Color _color; @override void paint(Color color) {_color = color;} @override Color get color => _color; } class PaintableContainer extends Container implements Paintable { Color _color; @override void paint(Color color) {_color = color;} @override Color get color => _color; }
如您所见,这也不是最佳解决方案,因为我们必须为每个可解析实体复制相同的代码。
但是,如果将与无关紧要的属性相关的功能作为单独的混合物(mixin)除去,则可以解决所有这些问题:
enum Color {red, yellow, green} mixin PaintableMixin { Color _color; void paint(Color color) {_color = color;} Color get color => _color; } class PaintableRect extends Rectangle with PaintableMixin { @override void draw() { print('Draw rectangle with color $color'); } } class PaintableContainer extends Container with PaintableMixin { @override void render() { print('Render container with color $color'); } }
现在您可以使用它:
main() { PaintableRect() ..paint(Color.red) ..draw(); PaintableContainer() ..paint(Color.yellow) ..render(); }
综上所述,可以通过以下方式确定何时方便使用杂质:是否有几个不同的层次结构需要添加相同的功能,这些功能定义了这些层次结构的实体的一些非必要属性。 或者它可以是一个层次结构,但是我们要处理其不同的分支。 例如,考虑Flutter框架的小部件。
假设我们需要向一些小部件添加与同一属性相关的功能。 Flutter中的小部件构造如下:
class MyStatelessWidget extends StatelessWidget {}
或
class MyStatefulWidget extends StatefulWidget {}
要通过继承添加属性,您将必须实现至少两个类:
class StatelessWidgetWithProperty extends StatelessWidget {} class StatefulWidgetWithPropery extends StatefulWidget {}
同时,正如您再次看到的,您必须复制与添加的属性关联的功能。
使用杂质时,问题得以解决:
mixin Property {} class MyStatelessWidget extends StatelessWidget with Propery {} class MyStatefulWidget extends StatefulWidget with Property {}
对于那些熟悉设计模式的人来说,在某些情况下使用杂质可以代替使用Bridge模式。
总之,应该指出的是,通过这种方式,可以任意组合一次混合几种不同特性的功能。
本文并不旨在详尽地定义杂质的使用。 开发人员的好奇心可能会为他们找到更多美丽的用途。 如果这些使用杂质的选项出现在本文的评论中,我将感到高兴。