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

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

相关推荐
程序员Ctrl喵12 小时前
异步编程:Event Loop 与 Isolate 的深层博弈
开发语言·flutter
前端不太难14 小时前
Flutter 如何设计可长期维护的模块边界?
flutter
小蜜蜂嗡嗡15 小时前
flutter列表中实现置顶动画
flutter
始持15 小时前
第十二讲 风格与主题统一
前端·flutter
始持15 小时前
第十一讲 界面导航与路由管理
flutter·vibecoding
始持15 小时前
第十三讲 异步操作与异步构建
前端·flutter
新镜16 小时前
【Flutter】 视频视频源横向、竖向问题
flutter
黄林晴16 小时前
Compose Multiplatform 1.10 发布:统一 Preview、Navigation 3、Hot Reload 三箭齐发
android·flutter
Swift社区17 小时前
Flutter 应该按功能拆,还是按技术层拆?
flutter
肠胃炎17 小时前
树形选择器组件封装
前端·flutter