Dart中的类和单例模式

本文详细介绍了Dart中的类和单例模式。从类的定义、构造函数、命名构造方法、初始化列表,到类的继承、抽象类、多继承和扩展,深入探讨了Dart的面向对象特性。接着,文章讨论了Flutter中的单例模式实现,包括普通单例、getter操作符、工厂构造函数以及利用Dart空安全和箭头函数的多种方式。最后,通过InheritedWidget展示了Flutter中的单例应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Dart中的类和单例模式

先了解Dart中的类:

Dart也是一门面向对象的开发语言,面向对象中非常重要的概念就是类,通过类的初始化创建一个对象

Dart 是支持基于 mixin 继承机制的面向对象语言,所有对象都是一个类的实例,而除了 Null 以外的所有的类都继承自 Object 类。 基于 mixin 的继承 意味着尽管每个类(top class Object? 除外)都只有一个超类,一个类的代码可以在其它多个类继承中重复使用。 扩展方法 是一种在不更改类或创建子类的情况下向类添加功能的方式。

类的定义

  • Dart中,定义类用class关键字
  • 类通常有两部分组成:成员(member)和方法(method)。
  • 当未指明其父类的时候, 默认是继承自Object的, 定义类的伪代码如下:
class 类名 {
   
  类型 成员名;
  返回值类型 方法名(参数列表) {
   
    方法体
  }
}
  • Dart语言中, 在类中使用属性(成员/实例变量)时, 有必要时是通过this获取的
  • 但是下面在getsize方法中并没有加this
  • 这里需要注意的是: Dart的开发风格中,在方法中通常使用属性时,会省略this,但是有命名冲突时,this不能省略
// 创建类
class Point {
   
  // 定义变量
  int x;

  void getsize() {
   
    print('x = $x');
  }
}

// 类的初始化
main(List<String> args) {
   
    // 从Dart2开始,new关键字可以省略
    var point = new Point();
    point.x = 1;
    point.getsize();
}

使用类的成员

对象的 成员 由函数和数据(即 方法实例变量)组成。方法的 调用 要通过对象来完成,这种方式可以访问对象的函数和数据。

使用(.)来访问对象的实例变量或方法:

var p = Point(2, 2);

// Get the value of y.
assert(p.y == 2);

// Invoke distanceTo() on p.
double distance = p.distanceTo(Point(4, 4));

使用 ?. 代替 . 可以避免因为左边表达式为 null 而导致的问题:

// If p is non-null, set a variable equal to its y value.
var a = p?.y;

构造函数

  • 当通过类创建一个对象时,会调用这个类的构造方法
    • Dart语言中,如果类中没有明确指定构造方法时,将默认拥有一个无参的构造方法()
    • 上面得到的point对象调用的就是默认的无参构造方法
  • 也可以根据自己的需求自定义构造方法
    • 当我们创建了自己的构造方法时,默认的无参的构造方法将会失效,不能使用,否则会报错
    • 因为Dart本身不支持函数的重载, 所以如果我们明确的写一个默认的构造方法,就会和我们自定义的构造方法冲突
class Student {
   
  String name;
  int age;

  Student(String name, int age) {
   
    this.name = name;
    this.age = age;
  }
}
  • 在上面构造方法中主要实现的就是通过构造函数的参数给类的户型赋值
  • 为了简化这一过程, Dart提供了一种更加简洁的语法糖形式
class Student1 {
   
  String name;
  int age;

  // 这里和上面的Studeng的构造方法等价
  Student1(this.name, this.age);
}

命名构造方法

  • 在实际开发中, 很明显一个构造方法的确是不够我们使用的
  • 而且Dart又不支持函数的重载, 不能创建爱你相同名称不同参数的构造方法
  • 这就衍生出了另外一中构造方法:命名构造方法
class Model {
   
  String name;
  int age;

  Model(this.name, this.age);

  // 命名构造方法
  Model.withNameAndAge(String name, int age) {
   
    this.name = name;
    this.age = age;
  }
  // 命名构造方法
  Model.initJson(Map<String, Object> map) {
   
    this.name = map['name'];
    this.age = map['age'];
  }
}


// 初始化对象
main() {
   
  // 普通构造方法
  var model0 = Model('name', 12);
  // 命名构造方法
  var model1 = Model.withNameAndAge('titan', 12);
  var model2 = Model.initJson({
   'name': 'jun', 'age': 18});
}

初始化列表

几种方式定义的属性都是可变的, 如果定义的属性是final不可重新赋值的又该如何实现

class Teacher {
   
  final String name;
  final int age;

  // 1. 这里会有一个错误提示: All final variables must be initialized, but 'age' and 'name' are not
  Teacher(String name, int age) {
   
    //2. 这里也会有一个错误提示: 'name' can't be used as a setter because it's final
    this.name = name;
    this.age = age;
  }
}
  • 上面第一处错误主要是因为: 在Dart中在执行下面{ }中的代码的时候, 表示Teacher对象已经初始化完毕了
  • 所以在执行{ }之前, 必须保证nameage被初始化了
  • 而且final修饰的属性是不可被重新赋值的, 所以才会报错
  • 或者也可以使用函数中的命名可选参数处理
class Size {
   
  final double width;
  final double height;
  final double area;

  // 命名可选参数
  Size(this.width, this.height, {
    this.area = 10 }); 
}
  • 上面通过命名可选参数的形式, 给参数设置默认值也是可以的, 但是不同的是area只能设置具体的数值, 不能设置表达式
  • 初始化列表的形式不但可以设置具体的数值, 也可以设置默认值为表达式的形式

                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值