记录Dart的一些特性
案例介绍
这里选择的是一段购物车程序,先不使用Dart独有的特性,然后逐步加入Dart语言特性。
首先在不使用任何Dart语法特性的情况下,一个有着基本功能的购物车程序如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| class Item { double price; String name; Item(name, price) { this.name = name; this.price = price; } }
class ShoppingCart { String name; DateTime date; String code; List<Item> bookings; price() { double sum = 0.0; for(var i in bookings) { sum += i.price; } return sum; } ShoppingCart(name, code) { this.name = name; this.code = code; this.date = DateTime.now(); } getInfo() { return '购物车信息:' + '\n-----------------------------' + '\n 用户名: ' + name+ '\n 优惠码: ' + code + '\n 总价: ' + price().toString() + '\n 日期: ' + date.toString() + '\n-----------------------------'; } } void main() { ShoppingCart sc = ShoppingCart('张三', '123456'); sc.bookings = [Item('苹果',10.0), Item('鸭梨',20.0)]; print(sc.getInfo()); }
|
这段代码看上去和Java或者JS都没有太大的差异,接下来从表达信息入手,优化这段代码
类抽象改造
在Item类和ShoppingCart类的构造函数中,他们都只是将main函数传入的参数进行属性赋值。
在Dart中使用语法糖和初始化列表进行简化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Item { double price; String name; Item(this.name, this.price); } class ShoppingCart { String name; DateTime date; String code; List<Item> bookings; price() {...} ShoppingCart(this.name, this.code) : date = DateTime.now(); ... }
|
然后我们发现:Item类和ShoppingCart类中都有一个name属性,都有一个price属性/方法,既然他们的类型和名称都一样,那么可以抽象出一个Meta基类,用于存放这两个属性。
因为在ShoppingCart中price只是用于计算购物车中商品的价格,那么继承Meta类后需要改写price属性的get方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Meta { double price; String name; Meta(this.name, this.price); } class Item extends Meta{ Item(name, price) : super(name, price); } class ShoppingCart extends Meta{ DateTime date; String code; List<Item> bookings; double get price {...} ShoppingCart(name, this.code) : date = DateTime.now(),super(name,0); getInfo() {...} }
|
不过ShoppingCart类中的price属性的get方法和打印购物车基本信息的getinfo方法都显得冗长,接下来改进一下这两个方法。
方法改造
我们需要重载Item类的“+”运算符,并通过对列表对象进行归纳合并操作即可
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Item extends Meta{ ... Item operator+(Item item) => Item(name + item.name, price + item.price); } class ShoppingCart extends Meta{ ... double get price => bookings.reduce((value, element) => value + element).price; ... getInfo() {...} }
|
顺便修改getInfo方法,因为字符串拼接实在是太不美观了。
1 2 3 4 5 6 7 8 9
| getInfo () => ''' 购物车信息: ----------------------------- 用户名: $name 优惠码: $code 总价: $price Date: $date ----------------------------- ''';
|
对象初始化方式的优化
因为有可能用户没有优惠券,所以我们需要对构造函数进行改进
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| class ShoppingCart extends Meta{ ... ShoppingCart({name}) : this.withCode(name:name, code:null); ShoppingCart.withCode({name, this.code}) : date = DateTime.now(), super(name,0); getInfo () => ''' 购物车信息: ----------------------------- 用户名: $name 优惠码: ${code??" 没有 "} 总价: $price Date: $date ----------------------------- '''; } void main() { ShoppingCart sc = ShoppingCart.withCode(name:'张三', code:'123456'); sc.bookings = [Item('苹果',10.0), Item('鸭梨',20.0)]; print(sc.getInfo()); ShoppingCart sc2 = ShoppingCart(name:'李四'); sc2.bookings = [Item('香蕉',15.0), Item('西瓜',40.0)]; print(sc2.getInfo()); }
|
因为打印这个行为非常通用,可能后面需要打印Item,所以我们需要把打印信息单独封装成一个类:PrintHelper。因为ShoppingCart 类本身已经继承自 Meta 类,考虑到 Dart 并不支持多继承,所以我们使用混合(Mixin)
1 2 3 4 5 6 7 8
| abstract class PrintHelper { printInfo() => print(getInfo()); getInfo(); } class ShoppingCart extends Meta with PrintHelper{ ... }
|
最后在main里面使用级联操作符,这样就不需要创建临时变量了,下面是完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| class Meta { double price; String name; Meta(this.name, this.price); } class Item extends Meta{ Item(name, price) : super(name, price); Item operator+(Item item) => Item(name + item.name, price + item.price); } abstract class PrintHelper { printInfo() => print(getInfo()); getInfo(); }
class ShoppingCart extends Meta with PrintHelper{ DateTime date; String code; List<Item> bookings; double get price => bookings.reduce((value, element) => value + element).price; ShoppingCart({name}) : this.withCode(name:name, code:null); ShoppingCart.withCode({name, this.code}) : date = DateTime.now(), super(name,0); @override getInfo() => ''' 购物车信息: ----------------------------- 用户名: $name 优惠码: ${code??" 没有 "} 总价: $price Date: $date ----------------------------- '''; } void main() { ShoppingCart.withCode(name:'张三', code:'123456') ..bookings = [Item('苹果',10.0), Item('鸭梨',20.0)] ..printInfo(); ShoppingCart(name:'李四') ..bookings = [Item('香蕉',15.0), Item('西瓜',40.0)] ..printInfo(); }
|