Flutter学习6 - Dart 类与对象

时间:2024-02-24 07:33:50

1、面向对象编程(Object-Oriented Programming, OOP)三大特征

(1)封装

  • 封装是指将对象的状态(属性)和行为(方法)封装在一起,对外部隐藏对象的内部细节,只提供公共的访问方式。
  • 通过封装,可以保护对象的状态不被外部直接访问和修改,只能通过对象提供的接口进行操作,提高了安全性和可维护性。

(2)继承

  • 继承是指一个类(子类)可以从另一个类(父类)中继承属性和方法的机制。
  • 子类可以继承父类的公共成员,并且可以通过重写(Override)或扩展(Extend)父类的方法来实现特定的行为。
  • 继承可以减少代码的重复性,提高代码的可重用性和可扩展性。

(3)多态

  • 多态是指同一个方法调用可以根据对象的不同类型而具有不同的行为。
  • 多态可以通过继承和接口实现,其中包括重载(Overloading)和重写(Overriding)两种形式。
  • 多态可以提高代码的灵活性和扩展性,使得程序能够更好地应对不同的需求和情况。

重载(Overloading)

// 相同方法名,不同参数
fun foo() {}
fun foo(str: String?) {}

重写(Overriding)

// 子类重新定义(覆盖)了父类中已有的方法
open class Animal{
    open fun makeSound(){
        System.out.println("Animal makes a sound");
    }
}

class Cat : Animal(){
    override fun makeSound() {
        System.out.println("Cat makes a sound");
    }
}

2、Dart 中的类与对象

(1)类与对象

void main() {
  Person person = Person("leon", 18);
  print(person.toString()); //name: leon  age: 18
}

//所有的类均继承自 Object
class Person {
  String? name;
  int? age;

  Person(this.name, this.age);

  //重写父类的方法
  
  String toString() {
    return "name: $name  age: $age";
  }
}

(2)初始化列表

void main() {
  Student student1 = Student("艾伦", 19, '清华大学');
  print(student1.toString()); //name: 艾伦  age: 19  school: 清华大学  city: null  country: 中国
  Student student2 = Student("三笠", 20, '复旦大学', city: '上海');
  print(student2.toString()); //name: 三笠  age: 20  school: 复旦大学  city: 上海  country: 中国
  Student student3 = Student("莱纳", 21, '哈佛大学', city: '剑桥', country: '美国');
  print(student3.toString()); //name: 莱纳  age: 21  school: 哈佛大学  city: 剑桥  country: 美国
}

class Student extends Person {
  //通过查下划线标识私有字段,作用域是当前文件
  String? _school;
  String? city;
  String? country;
  String? funName;

  /**
   * 初始化列表  funName = '$country.$city'
   * 必填项  name. age, _school
   * 选填项 city, country
   * 带默认值 country
   */
  Student(name, age, this._school, {this.city, this.country = "中国"})
      : funName = '$country.$city', super(name, age) {
    //构造函数体不是必须的
  }

  
  String toString() {
    return "name: $name  age: $age  school: $_school  city: $city  country: $country";
  }
}

(3)命名构造方法

  • 命名构造方法,在类的里面,通过 “类名.方法名” 的方式构造
  • 使用命名构造方法可以实现多个构造方法
void main() {
  Student s1 = Student.create1("炭治郎");
  print(s1.toString()); //name: 炭治郎  age: 0  school: null  city: null  country: null
  Student s2 = Student.create2('祢豆子', 4);
  print(s2.toString()); //name: 祢豆子  age: 4  school: null  city: null  country: null
  Student s3 = Student.create3('利威尔', 24, '巨人学院');
  print(s3.toString()); //name: 利威尔  age: 24  school: 巨人学院  city: null  country: null
}

class Student extends Person {
  //通过查下划线标识私有字段,作用域是当前文件
  String? _school;
  String? city;
  String? country;
  String? funName;

  Student(name, age) : super(name, age) {
    //构造函数体不是必须的
  }

  /**
   * 命名构造方法:类名.方法名
   */
  Student.create1(name) : super(name, 0) {}

  Student.create2(name, age) : super(name, age) {}

  Student.create3(name, age, school) : super(name, age) {
    _school = school;
  }

  
  String toString() {
    return "name: $name  age: $age  school: $_school  city: $city  country: $country";
  }
}

注:当有 final 变量时,命名构造方法必须初始化它
注:构造函数中也必须初始化 final 变量

void main() {
  Student s1 = Student.create1("炭治郎", '鬼灭学院');
  print(s1.toString()); //name: 炭治郎  age: 0  school: 鬼灭学院  city: null  country: null
  Student s2 = Student.create2('祢豆子', 4, '鬼灭学院');
  print(s2.toString()); //name: 祢豆子  age: 4  school: 鬼灭学院  city: null  country: null
  Student s3 = Student.create3('利威尔', 24, '巨人学院', '玛利亚', '日本');
  print(s3.toString()); //name: 利威尔  age: 24  school: 巨人学院  city: 玛利亚  country: 日本
}

class Student extends Person {
  //通过查下划线标识私有字段,作用域是当前文件
  final String? _school;
  String? city;
  String? country;
  String? funName;

  //构造函数中也必须初始化 final 变量
  Student(name, age, this._school) : super(name, age) {
    //构造函数体不是必须的
  }

  /**
   * 命名构造方法中必须 初始化 final 变量
   */
  Student.create1(name, this._school) : super(name, 0) {}

  Student.create2(name, age, this._school) : super(name, age) {}

  Student.create3(name, age, this._school, this.city, country) : super(name, age) {
    this.country = country;
  }

  
  String toString() {
    return "name: $name  age: $age  school: $_school  city: $city  country: $country";
  }
}

(4)命名工厂构造方法

  • 命名工厂构造方法,在类的里面,通过 " factory 类名.方法名" 方式构造
  • 会返回一个实例对象
void main() {
  Student s1 = Student.generate1('冯宝宝', 200);
  print(s1.toString()); //name: 冯宝宝  age: 200  school: null  city: null  country: null
  Student s2 = Student.generate2('张楚岚', 18, '野鸡大学');
  print(s2.toString()); //name: 张楚岚  age: 18  school: 野鸡大学  city: null  country: null
}

class Student extends Person {
  //通过查下划线标识私有字段,作用域是当前文件
  String? _school;
  String? city;
  String? country;
  String? funName;

  Student(name, age) : super(name, age) {
    //构造函数体不是必须的
  }

  /**
   * 命名工厂构造方法:factory  类名.方法名
   * 它会返回一个实例对象
   */
  factory Student.generate1(name, age) {
    return Student(name, age);
  }

  factory Student.generate2(name, age, school) {
    Student s = Student(name, age);
    s._school = school;
    return s;
  }

  
  String toString() {
    return "name: $name  age: $age  school: $_school  city: $city  country: $country";
  }
}

注:命名工厂构造方法无需初始化 final 变量

void main() {
  Student s1 = Student.generate1('冯宝宝', 200);
  print(s1.toString()); //name: 冯宝宝  age: 200  school: 未知  city: null  country: null
  Student s2 = Student.generate2('张楚岚', 18, '野鸡大学');
  print(s2.toString()); //name: 张楚岚  age: 18  school: 野鸡大学  city: null  country: null
}

class Student extends Person {
  //通过查下划线标识私有字段,作用域是当前文件
  final String? _school;
  String? city;
  String? country;
  String? funName;

  //构造函数中也必须初始化 final 变量
  Student(name, age, this._school) : super(name, age) {
    //构造函数体不是必须的
  }

  /**
   * 命名工厂构造方法:factory  类名.方法名
   * 它会返回一个实例对象
   */
  factory Student.generate1(name, age) {
    return Student(name, age, '未知');
  }

  factory Student.generate2(name, age, school) {
    return Student(name, age, school);
  }

  
  String toString() {
    return "name: $name  age: $age  school: $_school  city: $city  country: $country";
  }
}

(5)工厂构造方法

  • 通常是通过它实现单例
void main() {
  LogUtils log1 = LogUtils();
  LogUtils log2 = LogUtils();
  //若是单例,则 log1 == log2
  print("log1 与 log2 是否为同一个单例: ${log1 == log2}"); //log1 与 log2 是否为同一个单例: true

  //调用单例内的方法
  log1.log("输出日志 test"); //输出日志 test
}

/**
 * 工厂构造方法  实现单例
 */
class LogUtils {
  //静态私有成员
  static LogUtils? _instance;

  //命名构造方法,私有方法
  LogUtils._getInstance();

  //工厂构造方法
  factory LogUtils() {
    // ??=:表示若 _instance 为空,则取等号后面的值
    //若 _instance 不空,则继续执行下面代码,返回 _instance
    _instance ??= LogUtils._getInstance();
    return _instance!;
  }

  log(String msg) => print(msg);
}