Dart 中的构造函数

在 Dart 中,类的构造函数用于初始化类的对象。当你创建一个类的实例时,构造函数被自动调用。Dart 支持多种构造函数的写法,包括常规构造函数、命名构造函数、工厂构造函数等。

一、传统构造函数

默认构造函数是没有名字的构造函数,通常是通过 class 的成员变量来直接初始化对象。

  • 特点

    • 如果你没有显式定义构造函数,Dart 会自动生成一个默认的构造函数。
    • 默认构造函数直接初始化对象的字段。
    • 如果定义了其他构造函数,Dart 不再生成默认构造函数。
    • 不可以有多个
  • 示例

class Person {
    
    
  String? name;
  int? age;
  //传统构造函数
  Person(String name, int age) {
    
    
    this.name = name;
    this.age = age;
  }
  //上面的简写形式
  //Person(this.name, this.age);
  //Person();//报错
}

void main() {
    
    
  var person = Person("Alice", 25);
  print(person.name); // Alice
  print(person.age);  // 25
}

注意:传统构造函数只能有一个

二、命名构造函数

命名构造函数允许你定义多个构造函数,并通过不同的名字来区分它们。命名构造函数通常用于提供不同的初始化方式或逻辑。

  • 特点

    • 可以通过名字来区分不同的构造函数。
    • 适合需要不同初始化逻辑的场景。
    • 可以有多个
  • 示例

class Person {
    
    
  String? name;
  int? age;
  // 默认构造函数
  Person(this.name, this.age);

  // 命名构造函数
  Person.namedConstruction(this.name, this.age);
  Person.namedConstruction2(this.name) : age = 20;
}

void main() {
    
    
  var person1 = Person("Alice", 25);
  var person2 = Person.namedConstructor("Bob",18);

  print(person1.name); // Alice
  print(person1.age);  // 25
  print(person2.name); // Bob
  print(person2.age);  // 18
}

三、工厂构造函数

工厂构造函数通过 factory 关键字定义,主要用于控制实例化过程,可以根据条件返回一个现有实例或进行更复杂的初始化操作。工厂构造函数并不直接创建新的实例,甚至可能返回一个缓存的实例(例如,单例模式)。和其他构造函数相比他们最大的区别就是别的构造函数是没有返回值的,而factory构造函数需要一个返回值。

  • 特点

    • 可以返回已有的实例(比如实现单例模式)。
    • 可以通过返回不同的实例来控制对象的创建。
    • 适合于根据某些条件决定实例化过程的情况。
    • 可以有多个
  • 示例

class Person {
    
    
  String name;
  int age;

  // 默认构造函数
  Person(this.name, this.age);

  // 工厂构造函数
  factory Person.create(String name, [int age = 18]) {
    
    
    if (name.isEmpty) {
    
    
      throw ArgumentError("Name cannot be empty");
    }
    return Person(name, age);
  }
  factory Person.create2(String name) {
    
    
    return Person(name, 10);
  }
}

void main() {
    
    
  var person1 = Person.create("Alice", 25);
  var person2 = Person.create("Bob");

  print(person1.name); // Alice
  print(person1.age);  // 25
  print(person2.name); // Bob
  print(person2.age);  // 18
}

四、重定向构造函数

重定向构造函数使用 : 操作符将构造函数调用重定向到同一个类中的另一个构造函数。可以是默认构造函数、命名构造函数或者其他重定向构造函数。

  • 特点

    • 允许通过一种方式将构造函数的调用重定向到类中的其他构造函数。
    • 用于避免重复代码,简化类的构造逻辑。
  • 示例

class Person {
    
    
  String name;
  int age;

  // 传统构造函数
  Person(this.name, this.age);

  // 命名构造函数1
  Person.namedConstruction1(String name) : name = name, age = 18;

  // 命名构造函数2,重定向到 传统构造函数
  Person.namedConstruction3(String name) : this(name,10);
  // 重定向到 命名构造函数
  Person.namedConstruction4(String name) : this.namedConstruction1(name,10);
}

void main() {
    
    
  var person1 = Person.namedConstruction3("Alice");
  var person2 = Person.namedConstruction4("Bob");

  print(person1.name); // Alice
  print(person1.age);  // 10
  print(person2.name); // Bob
  print(person2.age);  // 10
}

五、初始化列表

在 Dart 中,构造函数的初始化列表部分允许你在构造函数体执行之前初始化对象的成员变量。它位于构造函数的 : 后面。

  • 特点

    • 用于在构造函数体内执行之前初始化字段。
    • 适合用于对字段进行条件初始化或其他复杂的赋值逻辑。
  • 示例

class Person {
    
    
  String name;
  int age;

  // 使用初始化列表
  Person(String name, [int age = 18])
      : name = name,
        age = age > 0 ? age : 18;

  void printDetails() {
    
    
    print("Name: $name, Age: $age");
  }
}

void main() {
    
    
  var person1 = Person("Alice", 25);
  var person2 = Person("Bob");

  person1.printDetails();  // Name: Alice, Age: 25
  person2.printDetails();  // Name: Bob, Age: 18
}

六、常量构造函数

常量构造函数用于创建常量对象。这些对象的字段值在编译时确定,且不能修改。你需要在构造函数前加上 const 关键字,初始化的所有属性都要以final来修饰。

  • 特点

    • 常量构造函数用于创建编译时已知的常量对象。
    • 常量对象在内存中只有一个实例,适用于单例模式。
  • 示例

class Person {
    
    
  final String name;
  final int age;

  // 常量构造函数
  const Person(this.name, this.age);
}

void main() {
    
    
  var person1 = const Person("Alice", 25);
  var person2 = const Person("Bob", 30);

  print(person1.name);  // Alice
  print(person2.name);  // Bob
}

总结

  • 传统构造函数:直接初始化成员变量,Dart 会自动生成,不写任何构造函数(包含其他种类构造函数)默认会有一个无参构造函数,一个类中只允许有一个。
  • 命名构造函数:可以定义多个构造函数,每个构造函数有不同的名字,用于提供不同的初始化逻辑。
  • 工厂构造函数:通过 factory 关键字定义,可以控制实例化过程,适合复杂的对象创建或返回缓存实例。
  • 重定向构造函数:将一个构造函数的调用重定向到另一个构造函数,减少代码重复。
  • 初始化列表:允许在构造函数体执行之前初始化字段,适用于复杂的初始化逻辑。
  • 常量构造函数:用于创建编译时常量对象,只有一个实例,字段不能修改。

通过这些构造函数的不同类型,你可以灵活地控制对象的创建和初始化方式,从而提高代码的可维护性和可读性。