Dart(四)—面向对象、类操作、抽象、多态、接口以及mixins特性

858 阅读8分钟

Dart(三)—方法定义、箭头函数、函数相互调用、匿名、自执行方法及闭包

Dart(二)—循环表达式、List、Set及Map的常用属性和方法

Dart(一)—变量、常量、基本类型、运算符、条件判断以及类型转换

Dart的面向对象

基本概念

DartKotlinJava都是面向对象编程语言,那面向对象编程(OOP)的三个基本特征是:封装、继承、多态。

  • 封装:封装是对象和类概念的主要特性。封装,把客观事物封装成抽象的类,并且把自己的部分属性和方法提供给其他对象调用, 而一部分属性和方法则隐藏。
  • 继承:面向对象编程语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
  • 多态:允许将子类类型的指针赋值给父类类型的指针, 同一个函数调用会有不同的执行效果 。

这里要注意的是Dart里面所有的都是对象,而对象都继承自Object类。Dart是一门使用类和单继承的面向对象语言,所有的对象都是类的实例。

下面我们看一下如何用 Object来定义一个属性:

Object str = "Dart面向对象";

Object flag = true;

print(str);
print(flag);

类定义及使用

创建一个类并并定义属性和方法:

class UserInfo {

  String name = "Jack";

  int age = 26;

  void getUserInfo(){

    print("${this.name}----${this.age}");
  }

  void setAge(){

    this.age = age;
  }

}

调用:

void main() {

    var userInfo = UserInfo();
    // UserInfo userInfo = UserInfo();也可这样写
    userInfo.getUserInfo();
}

这里我们看到Dart中的类也是默认带有一个没有参数的构造函数,如果我们需要自定义构造函数也是Kotlin或者Java一样的:

class UserInfo {

  String name = "Jack";

  int age = 26;

  UserInfo(String name,int age){
    this.name=name;
    this.age=age;
  }
}

当然,Dart也是可以有多个构造函数的,这里就不展开赘述了。

Dart的私有方法和私有属性

Dart和其他面向对象语言不一样,在修饰属性和方法时没有publicprivateprotected这些修饰符。

Dart的私有方法通过下划线_来定义:

//这是一个私有方法
void _getUserInfo(){

  print("${this.name}----${this.age}");
}

私有属性通过_关键字来声明:

//通过late关键字声明为私有属性
String _name = "Jack";
int age = 26;

私有属性和方法无法通过类的实例直接访问,只能通过非私有的方法来访问。

类中getter和setter修饰符用法

Dart中有getset两个关键字来修饰方法,它们的写法和传统JavaBean还是听不同的,下面我们看看顶一个一个私有属性变量,并添加settergetter方法:

String _name = "Jack";

String get name => _name;

set name(String value) {
  _name = value;
}

调用:

//get 方法的调用
userInfo.name;

//代表set方法,不用括号调用传值
userInfo.name = "Max";

这里要注意的是getset修饰符并不只针对私有属性,我们可以完全自由定义一个方法:

String get strBuild{

  return "$_name$age";
}

也可以不使用 String 类型修饰,调用的时候也是直接通过属性类型访问调用。

在构造函数运行之前初始化实例变量

这种用法个人觉得应该会用的比较少,例如:

String _name;
int age;

UserInfo(): _name = "Max", age = 26{
  
}

这样就是再构造这个对象时会初始化赋值。

Dart的类操作

静态成员和方法

Dart中的静态成员使用static关键字来修饰变量和函数,我们要知道的是静态方法中不能访问非静态变量,非静态方法可以访问静态成员。

static String name = 'Max';
int age = 28;

//静态方法引用静态变量
static void getName() {
  print(name);

  //print(this.age); 静态方法引用非静态变量报错
}

//非静态方法可以访问静态成员以及非静态成员
void printInfo(){
  // print(name);  //访问静态属性
  // print(this.age);  //访问非静态属性
  getName();   //调用静态方法
}

Dart对象操作符

Dart中的对象操作符主要有:

  • as 类型转换
  • is 类型判断
  • .. 级联操作 (连缀)

as类型强转:

var userInfo;

userInfo = UserInfo('Max', 26);

(userInfo as UserInfo).getUserInfo();

is判断一个对象是否为某一类型:

if(userInfo is UserInfo){
  userInfo.name = "Jack";
}

.. 级联操作可以把多个属性和方法写成链式调用的样式:

var userInfo = UserInfo('Max', 26);
userInfo
 ..name = "Jeremy"
 ..age = 23
 ..getUserInfo();

Dart类的继承

Dart中的类的继承:

  • 子类使用extends关键词来继承父类;
  • 子类会继承父类里面可见的属性和方法 但是不会继承构造函数;
  • 子类能复写父类的方法gettersetter

简单继承:

class UserInfo {
  String name = "Max";
  int age = 26;

  void getUserInfo() {
    print("${this.name}---${this.age}");
  }
}

//使用extends来实现继承
class Student extends UserInfo{

}

super 关键字在继承中的使用

我们再UserInfo 中添加一个构造函数:

class UserInfo {
  String name = "Max";
  int age = 26;

  UserInfo(this.name,this.age);

  void getUserInfo() {
    print("${this.name} -> ${this.age}");
  }
}

这样子我们可以在实现Student类的时候通过super关键字给父类构造方法传参:

class Student extends UserInfo{
  Student(String name, int age) : super(name, age){

  }
}

这样我们通过Student实例调用getUserInfo()方法也可以得到具体的值。

在继承中覆写父类的方法:

如上述例子中,覆写它的getUserInfo()方法:

@override
void getUserInfo() {
  super.getUserInfo();

  
}

子类调用父类方法:

我们先在UserInfo方法中增加一个方法:

void run(){
  
  print("run方法");
}

在子类里面调用直接通过super来实现:

extc(){

  super.run();
}

Dart中抽象类、多态以及接口

抽象类

Dart抽象类主要用于定义标准,子类可以继承抽象类,也可以实现抽象类接口:

  • 抽象类通过abstract关键字来定义;
  • Dart中的抽象方法不能用abstract声明,Dart中没有方法体的方法我们称为抽象方法;
  • 如果子类继承抽象类必须得实现里面的抽象方法;
  • 如果把抽象类当做接口实现的话必须得实现抽象类里面定义的所有属性和方法;
  • 抽象类不能被实例化,只有继承它的子类可以。

Dart中对于抽象类的使用可以extendsimplements,这两者的区别是:

  • 如果要复用抽象类里面的方法,并且要用抽象方法约束自类的话我们就用extends继承抽象类;
  • 如果只是把抽象类当做标准的话我们就用implements实现抽象类。

我们可以一个Person的抽象类,那作为Person的一些公共行为可以是eat、sleep以及run:

abstract class Person {

  eat();
  sleep();
  run(){
    print('人就需要动的');
  }
}

那这时要是实现一个Student类,那他也是需要eat、sleep、run的,可以继承Person

class Student extends Person{

  @override
  eat() {
    print("这个学生正在吃饭");
  }

  @override
  sleep() {
    print("这个学生正在睡觉");
  }
  
  @override
  run() {
    
  }
}

多态

Datr中的多态:

  • 允许将子类类型的指针赋值给父类类型的指针, 同一个函数调用会有不同的执行效果;
  • 子类的实例赋值给父类的引用;
  • 多态就是父类定义一个方法不去实现,让继承他的子类去实现,每个子类有不同的表现。

其实这里的多态就是父类的一个抽象方法可以给不同的子类实现,并且执行不同的逻辑。就如上述继承的例子,我们也可以定义一个Worker去实现:

class Worker extends Person{

  @override
  eat() {
    print("工人正在吃工作餐");
  }

  @override
  sleep() {
    print("工人需要上班9个小时候才能睡觉");
  }

  @override
  run() {

  }
}

接口

Dart的接口没有interface关键字定义接口,而是普通类或抽象类都可以作为接口被实现。 同样使用implements关键字进行实现。但是Dart的接口有点奇怪,如果实现的类是普通类,会将普通类和抽象中的属性的方法全部需要覆写一遍。而因为抽象类可以定义抽象方法,普通类不可以,所以一般如果要实现像Java接口那样的方式,一般会使用抽象类。所以建议使用抽象类定义接口。

abstract class ItemCallback{   //抽象类当接口用   接口:就是约定 、规范

  setData();

  callbackItem(String str);
}

实现:

class ItemSample implements ItemCallback{
  @override
  callbackItem(String str) {

  }

  @override
  setData() {

  }
}

这里要注意的是Dart中是可以实现多接口实现的,只需要在implements后面使用逗号分隔开就可以了。

Dart中的mixins

mixins的意思就是混入,在类中使用mixins实现类似多继承的功能。

  • 作为mixins的类只能继承自Object,不能继承其他类;
  • 作为mixins的类不能有构造函数;
  • 一个类可以mixins多个mixins类;
  • mixins绝不是继承,也不是接口,而是一种全新的特性。

要知道,Dart是只能单继承的,mixins实现的是介于继承功能的是多继承,通过with关键字来实现。看下面代码:

定义两个类:

class A {
  String info="this is A";
  void printA(){
    print("A");
  }
}

class B {
  void printB(){
    print("B");
  }
}

定义一个类去获取到两个类的属性和方法:

class C with A,B{
  
}

通过实例类调用其中的属性和方法:

var c = C();  
c.printA();
c.printB();
print(c.info);