Flutter学习——Dart篇 – 千根草的旅途

428 阅读5分钟
原文链接: euthl.top

创建一个Dart类

简单使用

class Bicycle {
  int cadence;
  int speed;
  int gear;

  //构造函数,在Dart里没有方法体是合法的
  Bicycle(this.cadence, this.speed, this.gear);

  //与第7行的写法等效
  /*Bicycle(int cadence, int speed, int gear) {
    this.cadence = cadence;
    this.speed = speed;
    this.gear = gear;
  }*/
}

main() {
  //实例化并打印
  var bike = new Bicycle(2, 0, 1);

  //与上一句等价,在Dart中new变为可选的
  // var bike = Bicycle(2, 0, 1);

  print(bike);
}

输出结果Instance of 'Bicycle'

说明:

  • main()主方法,如果你需要访问命令行传递过来的参数,可以使用 main(List args 方法。
  • 无变量访问控制的关键词,默认都为public。
  • 2个字符缩进,可使用 dartfmt 格式化,工具栏code下可以找到。
  • 实例化中,new变为可选的
  • 确信值不会发生改变可用final来代替var。

优化输出信息

在Bicycle类任意位置增加toString()方法

 //优化输出
  @override
  String toString() => 'Bicycle: $speed mph';

效果:Bicycle: 0 mph

增加一个只读的私有变量并增加getter方法

代码如下:

class Bicycle {
  int cadence;
  int _speed=0;
  //getter方法
  int get speed =>_speed;
  int gear;

  Bicycle(this.cadence,this.gear);

  void applyBrake(int decrement) {
    _speed -= decrement;
  }

  void speedUp(int increment) {
    _speed += increment;
  }

  @override
  String toString() => 'Bicycle: $speed mph';
}

main() {
  //实例化并打印
  var bike = Bicycle(2,1);
  print(bike);
}

说明:

  • 增加下划线 _ 来标记为私有的。
  • 未初始化的变量(即使是数字类型的变量)的值都为 null。
  • Dart 会为所有公开的变量提供存取方法,除非需要仅仅可读、可写,或者在某些情况下需要在 getter 方法中进行计算或是在 setter 方法中进行某些值得更新,否则都不需要再重新定义存取方法。
  • 实例变量可以直接通过 bike.gear 或者 bike.cadence 访问到,通过 bike.cadence 来进行实例变量的访问,然后再去通过定义存取方法来访问没有很大差距。

使用可选参数重载构造函数

Java使用重载构造函数,即重载的构造函数名同原构造函数名,但是在方法的参数个数或者参数类型上有些许不同。Dart不支持构造函数的重载,而是选择使用可选参数实现。
实现代码如下:

import 'dart:math';
class Rectangle {

  Point origin;
  int width;
  int height;

  //this.origin, this.width 和 this.height 使用了 Dart 提供的简便方法来直接对类中的实例变量进行赋值。
  //this.origin, this.width 和 this.height 嵌套在闭合的花括号中 ({}) ,用来表示它们是可选的命名参数。
  //this.origin = const Point(0, 0) 这样的代码表明给实例变量 origin 提供了默认的值 Point(0,0),默认值必须是在编译期就可以确定的常量。
  Rectangle({this.origin = const Point(0, 0), this.width = 0, this.height = 0});

  @override
  String toString() =>
      'Origin: (${origin.x}, ${origin.y}), width: $width, height: $height';
}

//验证传递不同数量的参数来实例化 Rectangle 是否成功
main() {
  print(Rectangle(origin: const Point(10, 20), width: 100, height: 200));
  print(Rectangle(origin: const Point(10, 10)));
  print(Rectangle(width: 200));
  print(Rectangle());
}

运行结果:

Origin: (10, 20), width: 100, height: 200
Origin: (10, 10), width: 0, height: 0
Origin: (0, 0), width: 200, height: 0
Origin: (0, 0), width: 0, height: 0

说明:因为Dart语言的特性,相对起Java节省代码量,书写更为简洁。

创建工厂方法

工厂类是一个广泛使用的设计模式,它相比较直接对类进行实例化来说,具有诸多优势,比如隐藏实例化的具体细节,提供可以配置为其他类的能力,直接返回一个已有的对象而不是直接返回一个新的对象。可以通过创建一个顶层的方法创建一个工厂模式的构造方法两种方式实现工厂类方法。

简单实现例子

代码如下:

import 'dart:math';

abstract class Shape {
  num get area;
}

class Circle implements Shape {
  final num radius;
  Circle(this.radius);
  num get area => pi * pow(radius, 2);
}

class Square implements Shape {
  final num side;
  Square(this.side);
  num get area => pow(side, 2);
}

main() {
  final circle = Circle(2);
  final square = Square(2);
  print(circle.area);
  print(square.area);
}

输出结果:

12.566370614359172
4

说明:

  • Dart支持抽象类
  • 一个文本中可定义多个类
  • 核心库math.dart

创建一个顶层的方法

在所有类外面创建

Shape shapeFactory(String type){
  if(type=='circle')return Circle(2);
  if(type=='square')return Square(2);
  throw 'Can't creat $type.';
}

修改main()中前两行代码

final circle = shapeFactory('circle');
final square = shapeFactory('square');

运行结果不变,但是返回的是一个已有对象而不是一个新对象。
其他说明:

  • 当出现异常后,DartPad 会直接抛出 Uncaught,你可以将代码封装在 try-catch 语句中来捕获异常。
  • 如果一个字符串中包含单引号,那么如果该字符串使用单引号声明的则需要在字符串内部的单引号之前增加转义符('Can't create $type.'),如果字符串是使用双引号进行生命的("Can't create $type."),则不需要。

创建工厂模式的构造方法

完整代码如下:

import 'dart:math';

abstract class Shape {
  factory Shape(String type) {
    if (type == 'circle') return Circle(2);
    if (type == 'square') return Square(2);
    throw 'Can't creat $type.';
  }
  num get area;
}

class Circle implements Shape {
  final num radius;
  Circle(this.radius);
  num get area => pi * pow(radius, 2);
}

class Square implements Shape {
  final num side;
  Square(this.side);
  num get area => pow(side, 2);
}

main() {
  final circle = Shape('circle');
  final square = Shape('square');
  print(circle.area);
  print(square.area);
}

在Shape类中增加工厂类的构造方法,以及修改main()前两行。
上述代码和之前创建的 shapeFactory()方法在效果上是一致的。

接口的实现

Dart 语言并没有提供 interface 关键字,但是每一个类都隐式地定义了一个接口

代码如下:

class Circle implements Shape {
  final num radius;
  Circle(this.radius);
  num get area => pi * pow(radius, 2);
}

class CircleMock implements Circle{
  num area;//实现Shape接口
  num radius;//实现Circle接口
}

Dart中的函数式编程

函数式有什么用?

  • 将函数当做参数进行传递
  • 将函数直接赋值给变量
  • 对函数进行解构,只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数
  • 创建一个可以被当作为常量的匿名函数(也被称为lambda表达式)

命令式编程:

String scream(int length) => "A${'a' * length}h!";
//'a' * length是指将a重复length次

main() {
  final values = [1, 2, 3, 5, 10, 50];
  for (var length in values) {
    print(scream(length));
  }
}

函数式编程:
将for循环内的换为values.map(scream).forEach(print);

运行结果:

Aah!
Aaah!
Aaaah!
Aaaaaah!
Aaaaaaaaaaah!
Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaah!

collection 库中的 List 和 Iterable 支持 fold, where, join, skip 等函数式方法,另外 Dart 还支持 Map 和 Set 类型。

同样将原来for循环那行替换为values.skip(1).take(3).map(scream).forEach(print);

  • skip(1)忽略第一个值,take(3)获取接下来的3个值

运行结果:

Aaah!
Aaaah!
Aaaaaah!