flutter - mixin

mixin

维基百科中这样定义 mixin:

In object-oriented programming languages, a Mixin is a class that contains methods for use by other classes without having to be the parent class of those other classes.(翻译:mixin 是一个普通类,可以让其他类在不继承这个类的情况下从这个类”借用”方法和变量。)

Support for the mixin keyword was introduced in Dart 2.1. Code in earlier releases usually used abstract class instead.(早期版本中的代码通常使用抽象类,也就是说 mixin 不过是一个 abstract class

Java tries to make up for this by using Interfaces, but that is not as useful or flexible as mixins.(从这个角度来讲,可以认为 mixin 是带具体实现的接口。)

Mixin 是对继承的一种功能扩展,它解决了继承带来的的基本问题,能够更优雅的重用不同类中的功能(这些类不太适合同一个类层次的结构)

小结

  • mixin 有点类似 abstract class
  • mixin 有点类似 interface
  • 不能继承 mixin
  • 可以使用 mixin, abstract class, class 来作为 mixin

定义方法

  • 用法: mixin [MixinClass] on [SuperClass]
  • 解释: [MixinClass]定义 mixin 类名, 例如:mixin Amixin {}
  • 解释: 可选关键字 on 用于限制 mixin 类的使用范围, 例如:Bmixin 类只能用于继承或者实现了 Bird那些类.

那些类到底是哪些类???

// 普通类,仅含有一个属性
class Bird{
  String name = "Bird";
}
// 1. 定义一个mixin类,含有属性和方法。
// !注意:在Amixin 内部有 String name=“A”,则表示,
// Amixin内部已经完全覆盖实现了上面得普通类Bird中所有属性和方法.所以 Amixin 属于 【那些类】
mixin Amixin {
  String name = "A";
  void say() {
    print(name);
  }
}

// 2.定义一个mixin类,并使用on 限定 Bmixin 只允许 那些类 使用
mixin Bmixin on Bird {
  String name = "B";
  void say() {
    print(name);
  }
}

// 3. 定义一个mixin类,只含有属性
// 同理,Cmixin 内部已经完全覆盖实现了上面得普通类Bird中所有属性和方法.所以 Cmixin 属于 【那些类】
mixin Cmixin {
  String name = "C";
}

使用方法 with 关键字后面跟上 mixin 的类名即可。

// 使用,普通类 OneBird 继承 Amixin
class OneBird with Amixin {}

// 使用,普通类 TwoBird 继承 Bird ,继承Bird之后就允许继承 Bmixin 
class TwoBird extends Bird with Bmixin {}

// 使用,普通类 ThirdBird 继承 Bird ,继承Bird之后就允许继承 Bmixin ,同时继承Amixin, Cmixin
class ThirdBird extends Bird with Amixin, Bmixin,Cmixin {}

Tips:继承层级顺序可以理解为压栈,后继承的位于栈顶,优先访问,优先调用

void main() async {
	OneBird myBird1 = OneBird();
	print(myBird1.name); // A

	TwoBird myBird2 = TwoBird();
	print(myBird2.name); // B

	// 多继承示例:
	// 创建的实例 myBird3 使用继承能力时,先在 Cmixin 上找,然后 Bmixin -> Amixin -> Bird
	// 先找到哪个就只用哪个
	ThirdBird myBird3 = ThirdBird();
	print(myBird3.name); // C
}

为什么使用 Mixin?

flutter 的吉祥物 Dash非常可爱,它和另一个虚拟吉祥物QuickBird一样都喜欢在全世界飘荡,有时鹦鹉(Parrot)也会与他们俩一起玩耍。那么在 flutter 中如何对面他们进行建模?

纯子类化

这 3 个都是鸟,他们都具有相同的能力: 震翅飞行(flutter)发出鸟鸣(chirp) 。因此让这 3 个类 QuickBird(快鸟), Dash(蜂鸟), Parrot(鹦鹉) 继承自同一个鸟类(Bird),其中 快鸟 是一个很聪明的鸟,它还能 写文章(write)。当他们到处飞行时,结识了新朋友 蚊子,但蚊子不是一直鸟,它更不能不鸟鸣,只是能飞而已。因此为它创建一个额外的超类飞行动物
在接下来的旅途中还会遇到其他各种像虫子一样的昆虫飞行动物类提供震翅飞行(flutter)功能,鸟类(Bird)提供了发出鸟鸣(chirp) 的能力。接下来他们飞行到了石家庄,发现了一个人,他没有飞的能力,但是他能敲键盘,能写文章。

在这里插入图片描述

  • 现在问题来了,在代码中我们如果想实现这些功能,希望通过继承重用震翅飞行(flutter)发出鸟鸣(chirp)写文章(write)功能。但是我们却不能为这些鸟, 昆虫, 和 人类创建一个通用的超类。

  • 如果添加一个写文章(write)的功能到共同的超类生物中。那么所有继承生物的子类鸟和昆虫都会拥有这个能力,但是只有 快鸟人类应该有这个能力

  • 如果我们创建一个新的超类 博客作者 并且只有 快鸟人类 从中继承, 快鸟 会失去它的 **震翅飞行(flutter)**和 发出鸟鸣(chirp) 的能力。

  • 如果我们根本不创建一个通用的超类,我们将不得不分别在快鸟人类实现 **写文章(write)**的功能,这就导致了代码重复,从而违反 DRY 原则(不要重复自己)。

并且随着生态系统越来越庞大,复杂,这将使得未来更加难以维护和理解。为了解决这个问题,所以需要一种能够在不同层次类结构中重用代码的方法。首先想到的就是允许类从多个超类继承,但是多重继承伴随着 Diamond 问题


abstract class Bird {
  void move() {
    print('Bird ▶︎ The bird is moving');
  }
}

mixin FlutterMixin on Bird {
  @override
  void move() {
    super.move();
    print('FlutterMixin ▶︎ The bird is fluttering through the air');
  }
}
mixin SailMixin on Bird {
  @override
  void move() {
    super.move();
    print('SailMixin ▶︎ The bird is sailing in the wind');
  }
}

class QuickBird extends Bird with FlutterMixin, SailMixin {}

void main(String[] args){
  QuickBird bird = QuickBird();
  bird.move();
}

结果:

> Bird ▶︎ The bird is moving
> FlutterMixin ▶︎ The bird is fluttering through the air
> SailMixin ▶︎ The bird is sailing in the wind

何时使用 Mixin

最常见的 mixin 类:TickerProviderStateMixinSingleTickerProviderStateMixin,这两个类常用于动画。
这两个类会告诉 flutter,这一个小部件是动画的,并且这个小部件希望收到帧更新通知,
以便于 AnimationController 生成一个新知值,然后为动画的下一帧重绘小部件

mixin SingleTickerProviderStateMixin<T extends StatefulWidget> on State<T>
    implements TickerProvider {

    Ticker? _ticker;
    @override
    Ticker createTicker(TickerCallback onTick) {
        // ...
        _ticker = Ticker(
            onTick,
            debugLabel:
                kDebugMode ? 'created by ${describeIdentity(this)}' : null
        );
        return _ticker!;
    }
    @override
    void didChangeDependencies() {
        if (_ticker != null)
            _ticker!.muted = !TickerMode.of(context);
        super.didChangeDependencies();
    }
    // ...
}

当然还有其它运用 mixin 的示例:

  • Service locators
  • i18n (Internationalization/Localization)
  • Logging
  • etc.

缺点和危险

一旦你体验到 mixin 的魅力,就一定会爱上并极有可能滥用它,比如
class Creature with FlutterMixin, SailMixin, ReadMixin, EatMixin,....

Mixins 使得在一个类可以包含各种各样的功能。但是当一个类可以做太多的事情时,就违反了单一职责原则,很难对这个类的作用保持直观的理解。此外,从哪个 mixin 继承哪个方法可能会变得非常混乱,难以理解,并且其他开发人员可能不清楚代码的执行顺序。

测试

这段代码输出结果是什么?

class A {
  String getMessage() => 'A';
}
class B {
  String getMessage() => 'B';
}
class P {
  String getMessage() => 'P';
}

class AB extends P with A, B {}
class BA extends P with B, A {}

void main() {
  String result = '';

  AB ab = AB();
  result += ab.getMessage();

  BA ba = BA();
  result += ba.getMessage();

  print(result);
}

答案解析:
从语义上讲以上这段代码等同于:

class PA = P with A;
class PAB = PA with B;

class AB extends PAB {}

class PB = P with B;
class PBA = PB with A;

class BA extends PBA {}

BA

------ 如果文章对你有用,感谢右上角 >>>点赞 | 收藏 <<<

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值