Dart语言之面向对象

目录

前言

1、初始化列表和标准构造方法

2、命名构造方法

3、工厂构造方法

4、命名工厂构造方法

5、set&get&静态方法

6、抽象类

7、mixins

8、方法

9、泛型


前言

本篇继续来学习Dart语言的内容,今天接上一篇《Dart语言之常用数据类型》来介绍Dart里面的面向对象。面向对象的核心特性包括封装、继承和多态

1、初始化列表和标准构造方法

类是面向对象编程的核心概念,包含对象、变量和方法。在Dart中定义类时,所有类默认继承自Object。

定义类变量的语法为:在类的大括号内直接声明变量类型和变量名,构造方法用于初始化类的对象。多态的表现形式包括方法重载,例如重写父类的toString方法,举个栗子如下:

Dart 复制代码
/// 定义一个类,所有的类都继承自Object
class Person {
  String name;
  int age;

  /// 标准的构造方法
  Person(this.name, this.age);

  /// 重写父类方法
  @override
  String toString() {
    return '$name,$age';
  }
}

初始化列表位于构造方法冒号后的表达式,用于初始化类的变量。

私有变量通过下划线标识,仅在当前文件内可访问:String _school;

可选参数通过大括号声明:Student({String city});

默认参数在可选参数后通过等号设置默认值,例如:Student({String country = 'China'});

可选参数和默认参数不仅适用于构造方法,也适用于其他类型的方法。

初始化列表可在子类构造方法体之前设置,用于初始化实例变量。若父类没有无参构造方法,则需在初始化列表中调用父类的构造方法。构造方法的方法体可通过大括号设置,但非必须。示例:

Dart 复制代码
class Student extends Person {
  // 定义类的变量
  String? _school; // 私有变量通过下划线标识,仅在当前文件内可访问
  String? city;
  String? country;
  late String name;

  /// 构造方法:
  /// 通过this._school初始化自有参数
  /// name,age交给父类进行初始化
  /// city为可选参数
  /// country为默认参数
  Student(
    this._school,
    String name,
    int age, {
    this.city,
    this.country = '中国',
  }) : // 初始化列表可在子类构造方法体之前设置,用于初始化实例变量。例如:
       name = '$country-$city',
       // 若父类没有无参构造方法,则需要在初始化列表中调用父类的构造方法
       super(name, age) {
    // 构造方法体不是必须的
    print('构造方法的方法体不是必须的');
  }
}

2、命名构造方法

命名构造方法是开发过程中常见的一种构造方法形式。命名构造方法以类名开头,通过点符号连接自定义方法名,用于实现类的多构造方法功能。

Dart 复制代码
// 命名构造方法【类名+.+方法名】
Student.convert(Student stu) : super(stu.name, stu.age);

3、工厂构造方法

在 Dart 中,使用 factory 关键字在构造方法前定义一个工厂构造方法。它允许你在构造函数中执行自定义逻辑,比如返回一个已存在的实例(实现单例模式)、返回子类实例,或者根据条件返回不同类型的实例。与普通构造函数不同,工厂构造方法需要显式使用 return 关键字来返回一个对象,并且不一定要返回新的实例。

定义工厂构造方法:

  • 使用 factory 关键字:在类定义中,在构造方法的声明前加上 factory 关键字。
  • 实现逻辑:在方法体内部编写创建和返回对象的逻辑。
  • 使用 return 关键字:工厂构造方法必须使用 return 关键字返回一个对象。
Dart 复制代码
class Singleton {
  static Singleton? _instance; // 静态变量,缓存实例
  // 私有命名构造函数
  Singleton._internal();

  // 工厂构造方法
  factory Singleton() {
    if (_instance == null) {
      // 如果实例不存在,就创建一个新的实例
      _instance = Singleton._internal();
    }
    // 返回缓存的实例
    return _instance!;
  }
}

void main(){
  var s1 = Singleton();
  var s2 = Singleton();
  print(s1 == s2); // 输出:true
}

4、命名工厂构造方法

命名工厂构造方法的主要形式如下:

  • 通过factory关键字标识
  • 类名加点加自定义方法名构成
  • 参数可根据需要设置
  • 可返回构造方法并根据需要进行初始化
  • 无需将类final变量作为参数,是一种灵活的获取类对象的方式
Dart 复制代码
// 命名工厂构造方法:factory [类名+.+方法名]
  // 它可以有返回值,而且不需要将类的final变量作为参数,是一种灵活获取类对象的方式
  factory Student.stu(Student stu){
    return Student(stu._school, stu.name, stu.age);
  }

5、set&get&静态方法

set方法用于修改私有字段值,需使用set关键字声明:

Dart 复制代码
// 可以为私有字段设置setter来控制外界对私有字段的修改
  set school(String value) {
    _school = value;
  }

get方法用于为私有字段设置访问接口,允许外部代码获取私有字段值:

Dart 复制代码
// 可以为私有字段设置getter来让外界获取到私有字段
  String? get school => _school;

静态方法使用static关键字标识,属于类而非实例,调用方式为类名.方法名(),无需创建类实例:

Dart 复制代码
// 静态方法
  static doXXX(String str) {
    print('doXXX:$str');
  }

6、抽象类

抽象类的定义需使用abstract关键字修饰。例如,定义Study抽象类时需标注为abstract class Study。抽象类的作用主要体现在接口定义场景。

Dart 复制代码
/// 使用abstract来定义抽象类,该类不能被实例化,在定义接口时非常有用
abstract class Study{
  void study(); // 抽象方法

  @override
  String toString() {
    return '抽象类中的普通方法';
  }
}
/// 继承抽象类要实现它的抽象方法,否则也需要将自身定义成抽象类
class StudySon extends Study{
  @override
  void study() {
    // TODO: implement study
  }
}

7、mixins

mixin的特征包括:

  • 必须创建继承自object的子类
  • 不能继承其他类
  • 不能声明构造方法
  • 不能调用super
Dart 复制代码
mixin class OldMan{
  void workOld(){
    print('OldMan');
  }
}
mixin class YoungMan{
  void workYoung(){
    print('YoungMan');
  }
}
class Worker with OldMan,YoungMan{

 @override
  void workOld() {
    // TODO: implement workOld
    super.workOld();
  }

  @override
  void workYoung() {
    // TODO: implement workYoung
    super.workYoung();
  }
}

class Worker extends OldMan with YoungMan{
 @override
  void workOld() {
    // TODO: implement workOld
    super.workOld();
  }

  @override
  void workYoung() {
    // TODO: implement workYoung
    super.workYoung();
  }
}

8、方法

①、方法的完整结构包含以下要素:

  • 返回值:定义方法执行后的输出类型,可为void或具体数据类型
  • 参数:接收外部输入的变量集合
  • 方法名:方法的唯一标识符(匿名方法除外)

其中,返回值特性包括:

  • 类型可缺省,默认返回void类型
  • 需显式声明返回具体数据类型时,必须包含return语句
  • 匿名方法作为特例可不声明方法名

以及,方法参数具有以下特征:

  • 参数类型与参数名共同构成参数声明
  • 参数分类:
    • 可选参数
    • 默认参数
  • 构造方法的参数规则完全适用于普通方法

②、私有方法的核心特征:

  • 命名规范:以下划线开头
  • 作用域限制:仅在定义文件中可访问

应用范围:同样适用于私有字段和私有类

③、匿名方法的定义:

  • 无方法名的即时函数定义

常见应用场景:作为回调函数参数

Dart 复制代码
class FunctionLearn {
  int sum(int value1, int value2) {
    return value1 + value2;
  }

  _learn() {
    print('私有方法');
  }

  anonymousFunction() {
    const list = ['func1', 'func2'];
    list.forEach((item) {
      print('item: $item');
    });
  }
}

关于其它类型的方法在上面基本上都已经介绍了,这里不再赘述。

9、泛型

最后来看一下泛型的使用,泛型的核心价值在于提升代码复用性,支持对非特定数据类型的通用操作。在 Dart 中,通过在类名后添加一对尖括号 <T> 来定义泛型类,其中 T 是一个泛型占位符,表示一个不确定的类型。如果需要多个泛型参数,可以使用逗号分隔,例如 <T, E>。泛型类可以在实例化时指定具体的类型,以提高代码的复用性和类型安全。

示例代码如下:

Dart 复制代码
class Cache<T> {
  final Map<String, T> _cached = <String, T>{};

  void setItem(String key, T value) {
    _cached[key] = value;
  }

  T? getItem(String key) {
    return _cached[key];
  }
}

void main() {
  var ca = Cache<String>();
  ca.setItem('key', '123');
  print(ca.getItem('key'));
}

关键点:

  • 定义泛型类 :在类名后面使用尖括号 <T> 来声明泛型参数。
  • 使用泛型参数 :在类的方法、属性等中使用泛型参数 T 来表示一个不确定的类型。
  • 实例化 :在创建类的实例时,通过 <具体类型> 指定泛型参数的类型,例如 Cache<int>()
  • 多个泛型参数 :可以使用逗号分隔多个泛型参数,例如 class MyMap<K, V>
  • 类型约束 :可以使用 extends 关键字来限定泛型参数的类型,例如 class NumericCache<T extends num> 表示 T 必须是 num 或其子类。

OK,到这里今天的内容就介绍完了,更多详情请参考文档:https://dart.dev/docs

下期再会,祝:工作顺利!

相关推荐
汤面不加鱼丸2 小时前
flutter实践:DropdownButton2使用示例
flutter
心随雨下2 小时前
Flutter Material 3设计语言详解
javascript·flutter·设计语言
猫林老师3 小时前
Flutter for HarmonyOS开发指南(六):测试、调试与质量保障体系
flutter·华为·harmonyos
stringwu8 小时前
Flutter DevTools 全景介绍
flutter
GISer_Jing11 小时前
跨平台Hybrid App开发实战指南
android·flutter·react native
猫林老师1 天前
Flutter for HarmonyOS开发指南(八):国际化与本地化深度实践
flutter·华为·harmonyos
dragon7251 天前
FutureProvider会刷新两次的问题研究
前端·flutter
2501_915909061 天前
Flutter 应用怎么加固,多工具组合的工程化实战(Flutter 加固/Dart 混淆/IPA 成品加固/Ipa Guard + CI)
android·flutter·ios·ci/cd·小程序·uni-app·iphone