美文网首页
Dart语言基础(六)之面向对象扩展

Dart语言基础(六)之面向对象扩展

作者: 枫叶无处漂泊 | 来源:发表于2019-04-17 23:25 被阅读0次

简介

上一遍主要讲了面相对象的基础特性,这篇文章主要讲面向对象的扩展,分别以一下几个方面来讲

  • 继承,继承中的构造方法
  • 抽象类
  • 接口
  • Mixins,操作符的覆写

继承

  • 使用关键字extends继承一个类
  • 子类会继承父类可见的属性和方法,不会继承构造方法
  • 子类能够复写父类的方法、getter和setter
  • 单继承,多态性

在Person.dart文件中:

class Person {
  
  String name;
  int age;
  //私有属性
  String _favorite;
  //计算属性,判断是否成年
  bool get isAdult => age > 18; 
  void work() {
    print('person is working');
  }
  //私有方法
  void _run(){

    print('person is running');
  }
  //当继承person的子类要重写构造方法,不能继承
  Person(this.name,this.age);
}

在文件中import 'Person.dart'文件

import 'Person.dart';

void main() {

  var student = Student();
  student.study();
  student.name = '学生';
  student.age = 16; //可以访问可见属性
  // student._favorite = '打篮球'; //访问不了私有属性
  // student._run(); //访问不了私有方法
  //可以访问父类可见方法,可以重写父类的方法
  //子类work方法里面调用super的work方法
  /*
  打印结果:
  person is working
  student is working
  */
  student.work(); 

  //计算属性,通过age来计算是否成人
  //父类计算是大于18,子类重写大于15
  print(student.isAdult);  //YES

  //父类的引用,子类的实现
  Person person = new Student();
  // person.study();//提示找不到该方法
  if (person is Student) {
    //父类引动study方法,实际是子类去实现该方法
    person.study();
  }
}

class  Student extends Person {

  //stu自有的方法
  void study() {

    print('student is studying');
  }

  @override //表示复写父类的标识
  bool get isAudlt => age > 15;
  
  @override
  //学生可以重写父类的方法
  void work() {
    super.work();
    print('student is working');
  }
}

继承中的构造方法

  • 子类的构造方法默认会调用父类的无名无参构造方法
void main() {

  //默认会调用person的无名无参构造方法
  var student = new Student(); //Person的构造方法
}

class Person {
  
  String name;
  //无名无参的构造方法
  Person() {
    
    print('Person的构造方法');
  }
}

class Student extends Person {
  int age;
}

继承中的构造方法

  • 如果父类没有无名无参构造方法,则需要显示调用父类构造方法
  • 在构造方法参数后使用:显示调用父类构造方法

void main() {

  //Student('张三')相当于调用了Person.withName('张三')
  var student = new Student('张三');
  print(student.name); //张三
}

class Person {
  
  String name;
  //子类需要显示的父类构造方法,这两个其中之一
  Person(this.name);
  Person.withName(this.name);
}

class Student extends Person {
  
  int age;

  //Student(String name)就是显示调用super.withName(name)方法
  //下面两种方式都可以,但是都写的会报错,方法不能重载
  // Student(String name) : super(name);
  Student(String name) : super.withName(name);
}

构造方法执行顺序

  • 父类的构造方法在子类构造方法体开始执行的位置调用
  • 如果有初始化列表,初始化列表会在父类构造方法之前执行

void main() {

  //Student('张三')相当于调用了Person.withName('张三')
  var student = new Student('张三','男');
  print(student.name); 
  print(student.gender);
  /*
  打印结果:
    Person构造方法先执行
    Srudent构造方法后执行
    张三
    男
   */
}

class Person {
  
  String name;
  //子类需要显示的父类构造方法,这两个其中之一
  Person(this.name);
  Person.withName(this.name) {

    print('Person构造方法先执行');
  }
}

class Student extends Person {
  
  int age;
  final String gender ;


   //子类的初始化列表在父类构造方法之前,
  //父类构造方法执行在子类构造方法执行之前
  Student(String name, String gender):gender = gender ,super.withName(name) {

    print('Srudent构造方法后执行');
  }
  //初始化列表方法父类的构造方法之后编译会报错
  // Student(String name, String gender):super.withName(name),gender = gender;

}

抽象类

  • 抽象类使用abstract表示,不能直接被实例化
  • 抽象方法不能用abstract修饰,只声明方法,没有方法实现
  • 抽象类可以没有抽象方法
  • 有抽象方法的类一定得声明为抽象类

void main(List<String> args) {
  
  //抽象类不能被实例化
 var person = new Person(); //报错
  //抽象类只能通过子类继承来实现
  var student = new Student();
  student.run(); //run
}

abstract class Person {

  //抽象类中抽象方法不需要用abstract,不用实现。
  //子类继承去实现 
  void run();
}

//抽象类不能实例化,只能通过子类继承来实现实例化
class Teacher extends Person {

  @override
  void run() {

    print('teacher run');
  }
}

//抽象类不能实例化,只能通过子类继承来实现实例化
class Student extends Person {

  @override
  void run() {

    print('Student run');
  }
}

接口

  • 类和接口是统一的,类就是接口
  • 每个类都隐式的定义了一个包含所有实例成员的接口
  • 如果是复用已有类的实现,使用继承(extends)
  • 如果只是使用已有的外在行为,则使用接口(implements)
void main(List<String> args) {
  
  var student = new Student();
  student.run(); //student run
  print(student.age); //15

  var child = new Children();
  child.run(); //children run
}

 class Person {
   String name;
  int get age => 18;

  void run() {

    print('person run');
  }
    
}

//抽象类来作为接口
abstract class AbsPerson {

    void run();
}

//抽象类当成接口来调用,抽象类也是类的一种
//所以说类就是接口
//建议大家用抽象类来作为接口
class Children implements AbsPerson {
  @override
  void run() {
    // TODO: implement run
    print('children run');
  }
}

// 把Person作为接口来使用,类就是接口
//Person里面的所有属性方法都要重新实现
class Student implements Person {
  @override
  String name;

  @override
  // TODO: implement age
  int get age => 15;

  @override
  void run() {
    // TODO: implement run
    print('student run');
  } 
}

Mixins

  • Mixins类似于多继承,是在多类继承中重用一个类代码的方式
  • 作为Mixins类不能有显示声明构造方法
  • 使用关键字with连接一个或者多个Mixins类
void main(List<String> args) {
  
  //D多继承与A,B,C
  //D类的对象可以调用A,B,C的方法
  var d = new D();
  //A,B,C都有a()这个方法,会执行哪个类的a()方法
  //以为D extends A with B,C,按顺序执行
  //C在最后面,所以执行C的a()方法
  //b()方法同上原理
  d.a(); //C.a
  d.b();//C.b
  d.c();//C.c
}

class A {

  //D是继承A的,所以显示声明没有问题
  A() {

  }
  void a() {

    print('A.a');
  }
}

class B {

  //类B会报错,Mixins类不能显示创建构造方法
  // B() {

  // }
  void a() {

    print('B.a');
  }

  void b() {

    print('B.b');
  }
}

class C {

  //类B会报错,Mixins类不能显示创建构造方法
  // C() {

  // }
  void a() {

    print('C.a');
  }

  void b() {

    print('C.b');
  }
  
  void c() {

    print('C.c');
  }
}

//用 D extends A with B,C形式实现实现多继承
//先继承一个类 再在with后面跟的就是Mixins类
//在B,C类要是显示的创建构造方法,D在继承Mixins类的B,C就是有错误
class D extends A with B,C {
  
}

  • 作为Mixins的类只能继承自Object

void main(List<String> args) {
  
  var a = new A();
  a.work(); //b.work
}

//B是Mixins类,只能继承与Object
//C并不是Object
// class B extends C {

//mixins只能继承Object
class B extends Object {
  void work() {

    print('B.work');
  }
}

class C {

}

//B是Mixins类
class A with B {

}

下面我讲一个实例,通过用抽象类和接口来实现一个类,这样能更好理解抽象类和接口的作用

void main() {

  var car = Car();
  car.work(); //Using Electric
  car.run(); //tyre run

  var bus = Bus();
  bus.work(); //Using oil
  bus.run(); //tyre run
}

//发动机
abstract class Engine {

  void work();
}

//燃油发动力
class OilEngine implements Engine {
  @override
  void work() {
   
    print('Using oil');
  }
}

//电力发动机
class ElectricEngine implements Engine {
  @override
  void work() {
    
    print('Using Electric');
  }
}

//轮胎
class Tyre {
  String name;
  void run() {
    print('tyre run');
  }
}

//声明类,这种是简写的方法,下面我写全
//一个汽车有轮胎并且是电发动机
class Car = Tyre with ElectricEngine;
// //下面是写全的方式
// class Car extends Tyre with ElectricEngine{

// }

class Bus = Tyre with OilEngine;

操作符覆写

  • 覆写操作符需要在类中定义
返回类型 operator 操作符 (参数1,参数2,...) {
    实现体
    rturn 返回值
}

  • 如果覆写 == ,还需要覆写对象的hashCode getter方法
  • 可覆写的操作符:
    <,+,|,[],>,/,^,[]=,<=,/,&,,>=,*,<<,==,-,%,>>

void main() {

  var p1 = new Person(18);
  var p2 = new Person(22);

  //> 操作符无法比较两个对象的大小
  //要覆写操作符 > 才能比较
  //覆写的返回值是bool
  p1 > p2;
  print(p1 > p2); //false

  print(p1.age); //18
  //通过覆写操作符
  //p1通过p1['age']取值
  print(p1['age']); //18
  print(p1['aa']); //0
}

class Person {
  
  int age;
  Person(this.age);
  //覆写操作符 > 
  bool operator > (Person p) {

    return this.age > p.age;
  }
  //覆写操作符 = 
  int operator [](String name) {

    if(name == 'age') {
      return this.age;
    }
    return 0;
  }
}

覆写操作符你可以自己多尝试,多实践实践,慢慢就会深有体会。

结尾

通过本篇文章,解了面向对象的拓展功能,

下一篇会主要讲一下Dart语言基础(七)之枚举和泛型,到时候大家关注一下。

相关文章

网友评论

      本文标题:Dart语言基础(六)之面向对象扩展

      本文链接:https://www.haomeiwen.com/subject/jllawqtx.html