2020-04-11 Flutter学习笔记——Dart构造函数介绍

Dart构造函数有4种格式:

ClassName(...)   //类名构造函数

Classname.identifier(...)   //命名构造函数

const ClassName(...)   //常量构造函数

factroy ClassName(...)   //工厂构造函数


1. 默认构造函数

如果你定义了一个类,而没有定义构造函数,那么它将有一个默认的构造函数,这个构造函数没有参数

如果这个类有父类,那么默认构造函数,还会调用父类的无参数构造函数。

2. 类名构造函数

构造函数就是一个与类同名的函数,构造函数是一个函数,因此可以参数化。但是与函数不同,构造函数不能具有返回类型。

class Point {

  num x, y;

  // 类名构造函数

Point(num x, num y) {

    // There's abetter way to do this, stay tuned.

    this.x = x;

    this.y = y;

  }

}

上例中只有两个成员变量,如果有10个,岂不是麻烦死?所以Dart有语法糖如下:

class Point {

  num x, y;

  // Syntacticsugar for setting x and y

  // before theconstructor body runs.

  Point(this.x,this.y);

}

它可以将x,y的赋值变得简单一些,就不用写构造函数的方法体了,记得括号后用分号哦。

3. 命名构造函数

在Dart中构造函数的名称可以是类名 ClassName 或者类名和标识符 ClassName.identifier 。 其中构造函数名称是“ClassName”的函数叫“类名构造函数”;构造函数名称是“ClassName.identifier”的函数叫“命名构造函数”。

class Point {

  num x, y;

  // 类名构造函数

Point(this.x, this.y);

  // 命名构造函数

  Point.origin() {

    x= 0;

    y= 0;

  }

// 命名构造函数

  Point.now(num x, num y)

  {

      print("这是命名构造函数");

      this.x = x;

      this.y = y;

   }

}

使用命名构造函数可以为类提供多个构造函数,以使类定义多个构造函数。

请记住,命名构造函数不可继承,如果子类想要有 和父类一样的命名构造函数,那就写个同名的(通常也会在子类的命名构造函数里,调用父类的同名命名构造函数)



再看一个实际例子,加深一下用命名构造函数的好处:横向扩展

RaisedButton 即"漂浮"按钮,它默认带有阴影和灰色背景。按下后,阴影会变大,如图3-10所示:


使用RaisedButton非常简单,如:

RaisedButton( //类名构造函数

  child: Text("normal"),

  onPressed: () {},

);

RaisedButton、FlatButton、OutlineButton都有一个icon 构造函数,通过它可以轻松创建带图标的按钮,如图3-14所示:


代码如下:

RaisedButton.icon( //命名构造函数

  icon:Icon(Icons.send),

  label:Text("发送"),

  onPressed: _onPressed,

),

OutlineButton.icon(

  icon:Icon(Icons.add),

  label:Text("添加"),

  onPressed:_onPressed,

),

FlatButton.icon(

  icon:Icon(Icons.info),

  label:Text("详情"),

  onPressed:_onPressed,

),

3.2重定向构造函数(构造函数传递)

有时构造函数的唯一目的是重定向到同一类中的另一个构造函数。定义构造函数的时候,除了一个普通构造函数,还可以有若干命名构造函数,这些构造函数之间,有时候会有一些相同的逻辑,如果分别书写在各个构造函数中,会有些多余,所以构造函数可以传递。重定向构造函数没有方法体,会在初始化列表中,构造函数调用出现在冒号( :)之后 。 就是在创建类时,定义一个命名构造函数,但是这个构造函式的主体不实现,直接通过另外一个构造函数实现对外界传入的参数接收并赋值给内部的变量。

class Point {

  num x, y;

  // The main constructor for this class.

  Point(this.x, this.y);

  // Delegates to the main constructor.

  Point.alongXAxis(Map<String, num> json)

    :x = json['x'],

      y= json['y'] {

  print('In Point.fromJson(): ($x, $y)');

}  //初始化列表就是构造函数名的冒号后面,打括号前面的部分。

}

初始化列表的执行顺序,在整个构造函数的最前面,它除了可以调用父类的构造函数,还可以在构造函数方法体之前,初始化一些成员变量。

import 'dart:math';

class Point {

  final num x;

  final num y;

  final num distanceFromOrigin;

  Point(x, y)

      :x = x,

        y= y,

        distanceFromOrigin= sqrt(x * x + y * y);

}

main() {

  var p = new Point(2, 3);

  print(p.distanceFromOrigin);

}


再看计数器示例的代码,是不是有感觉了:语法糖和初始化列表都出现了

class MyHomePage extends StatefulWidget {

  MyHomePage({Key key

, this.title}) : super(key: key);

// This widget is the home page of your application. It is stateful, meaning

  // that it has a State object (defined below) that contains fields that affect

  // how it looks.

  // This class is the configuration for the state. It holds the values (in this

  // case the title) provided by the parent (in this case the App widget) and

  // used by the build method of the State. Fields in a Widget subclass are

  // always marked "final".

final String title;


4. 常量构造函数

class ImmutablePoint {

  static final ImmutablePoint origin =

      const ImmutablePoint(0, 0);

  final num x, y;

  const ImmutablePoint(this.x, this.y);

}

如果你的类,创建的对象永远不会改变,你可以在编译期就创建这个常量实例,并且定义一个常量构造函数,并且确保所有的成员变量都是final的。


5. 工厂构造函数

有时候可能有一种需求,并不需要每次都创建新的类实例,而是每一种情况,只需要一个实例:

class Logger {

  final String name;

  bool mute= false;

  // _cache is library-private, thanks to the _ in front of its name.

  static final Map<String, Logger> _cache =

      <String, Logger>{};

  factory Logger(String name) {

    if (_cache.containsKey(name)) {

     return _cache[name];

    } else {

      final logger = Logger._internal(name);

      _cache[name] = logger;

      return logger;

    }

  }

  Logger._internal(this.name);

  void log(String msg) {

    if (!mute) print(msg);

  }

}

main() {

    var logger = Logger('UI');

    logger.log('Button clicked');

}

工厂构造函数,没有权利访问this

上例的意思是,类中又一个静态缓存_cache保存着一些Logger类实例,创建实例时,给工厂构造函数传递的name,如果在缓存中已经存在,就用缓存中现成的实例,如果没有,就新建一个实例,并且也放到缓存中。

如此这般,我们可以创建名字为UI / SYS / API 等的实例,然后在debug的时候,如果设置名字为UI的Logger实例的mute为true,就不会打印UI相关的log,而不影响其它两个名字的log。是不是很方便呢?

尾记:

学习Dart语法时建议结合实际例子中的用法去理解,语法特性也是为实际场景服务的,掌握背后的意义,才能真正掌握一门工具,用好一门语言。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339

推荐阅读更多精彩内容