更新:对于 Equitable package >= v 0.6.0的新版本,请阅读我在 Medium 上的文章,对于旧版本或深入了解,请阅读此答案。
当你父亲给你和你兄弟两件礼物时,两件礼物都是笔记本电脑,但它们不是同一类型的笔记本电脑;你想知道两个礼物是否相等!因此,您将比较对您的RAM、SSD、CPU重要的所有方面。
在纸上:myLaptop: 16G/256G/i5 | myBrotherLaptop: 8G/512G/i5
假设您的大脑正在使用 Dart 语言,并且您将每个礼物视为此类的对象:
class LaptopGiftClass {
int ram;
int ssd;
String cpu;
// Default constructor
LaptopGiftClass(this.ram, this.ssd, this.cpu);
}
然后比较使用上述类创建的两种礼物的相等性,Dart 和其他面向对象的语言,例如 Java、C# 期望您创建(覆盖)这些函数,以使这些语言理解对象并能够比较任何两个同一类的对象:
@override
bool operator ==(Object myBrotherLaptop) =>
identical(myLaptop, myBrotherLaptop) ||
myBrotherLaptop is LaptopGiftClass &&
runtimeType == myBrotherLaptop.runtimeType &&
name == myBrotherLaptop.name;
@override
int get hashCode => name.hashCode;
如果这些台词把你吓跑了,没有人会责怪你,这就是为什么好人为我们创造了平等的包裹!
Equatable 包告诉你“把这个可怕的工作留给我”但是如何将可怕的代码委托给equatable 包??!通过做两件事:
- 让你的类扩展相等:
dart class LaptopGiftClass extends Equatable {...}
- 从一开始就将您需要在数组中比较的所有属性传递给 Equatable(超/父类),因此在构造函数中:
LaptopGiftClass(this.ram, this.ssd, this.cpu) : super([ram, ssd, cpu]);
你的最后一堂课是:
class LaptopGiftClass extends Equatable {
int ram;
int ssd;
String cpu;
// Default constructor
LaptopGiftClass(this.ram, this.ssd, this.cpu) : super([ram, ssd, cpu]);
}
你完成了!您现在可以检查两个礼物的相等性,只需创建对象然后比较:
LaptopGiftClass myLaptop = LaptopGiftClass(16,256,'i5');
LaptopGiftClass myBrotherLaptop = LaptopGiftClass(8, 512,'i5');
在开始比较之前,您的兄弟看到了您,因为他是一名游戏玩家,他希望您在此相等性检查中添加更多属性:GPU 和 Screen_Resolution!你妈听了还让你加价!
现在你有一个新的道具列表来比较:[GPU,Screen_Resolution,Price]。
因此,因为您遵循干净的代码原则,所以您期望这样做,并且您使构造函数能够获得更多属性以进行比较:
// This only mean combine both lists
[ram, ssd, cpu]..addAll(myBrotherAndMotherProps)
所以你的最后一课是:
class LaptopGiftClass extends Equatable {
int ram;
int ssd;
String cpu;
// Default constructor
LaptopGiftClass(
this.ram,
this.ssd,
this.cpu,
// List of list => because we think "clean code"
// and maybe in the future we will send other data; NOT
// only an array(list)..
// so we here sent the extra props we need to
// compare 'myBrotherAndMotherProps', and
// as sometime brother and mother will not ask you
// to add props to compare, you give it a default value
// as empty "const []", why const here??! just for better
// performance as we are so soooo Professional!!
[ List myBrotherAndMotherProps = const [] ],
) : super([ram, ssd, cpu]..addAll(myBrotherAndMotherProps));
// WHY TO PASS FROM INSIDE THE CONSTRUCTOR?
// because Equatable needs them (required)
// and not at anytime but immediately inside the
// constructor of itself, so we made this
// chaining(constructor pass to another constructor)..
}
所以很明显,基本属性是 [RAM、SSD、CPU],但任何额外的东西也会被考虑在内,因为我们使实现变得干净、灵活和可扩展。
在添加这个灵活的代码之前,List<Object> get props => [RAM, SSD, CPU]..addAll(myBrotherAndMotherProps);
这些代码曾经是 EQUAL !!:
// Note first 3 are equal [ram, ssd, cpu]:
LaptopGiftClass myLaptop = LaptopGiftClass(16,256,'i5', ['Nvidia', 1080, '1200$']);
LaptopGiftClass myBrotherLaptop = LaptopGiftClass(16, 256,'i5', ['Intel HD', 720, '900$']);
myLaptop == myBrotherLaptop; // True without ..addAll(myBrotherAndMotherProps);
myLaptop == myBrotherLaptop; // False with ..addAll(myBrotherAndMotherProps);
TimerState 也一样:
@immutable
abstract class TimerState extends Equatable {
final int duration;
TimerState(this.duration, [List props = const []])
: super([duration]..addAll(props));
}
TimerState
就像LaptopGiftClass
上面一样实现(最后一个实现)。您可以props
使用构造函数发送给它:
TimerState(this.duration, [List props = const []])
: super([duration]..addAll(props));
所以TimerState
将在这一行中将道具的列表传递给它的父级(超级/ Equatable/扩展的..),如下所示:
: super([duration]..addAll(props));
在这个计时器示例中;duration
是基本的道具,就像[RAM, SSD, CPU]
LaptopGiftClass。
层次结构将是这样的:
// Inside class Paused extends TimerState {...}
Paused(int duration) : super(duration); // super is TimerState
// then Inside abstract class TimerState extends Equatable {..}
TimerState(this.duration, [List props = const []])
: super([duration]..addAll(props)); // super is Equatable
// Then Equatable will get props and deal with it for you...