美文网首页Flutter
第七节: Dart中抽象类abstract/接口implemen

第七节: Dart中抽象类abstract/接口implemen

作者: 时光如剑 | 来源:发表于2020-05-12 12:02 被阅读0次

    Dart 语法学习目录

    第一节: Dart 语法了解,认识变量,常量,数据类型
    第二节: Dart 操作符(运算符)
    第三节: Dart 中流程控制,条件判断以及循环语句
    第四节: Dart 中常用集合 List/Map
    第五节: Dart 函数使用,声明函数/匿名函数/可选参数/作用域/闭包
    第六节: Dart 面向对象/构造函数/静态属性
    第七节: Dart中抽象类abstract/接口implements/混入Mixin
    第八节: Dart中泛型/泛型定义与使用
    第九节: Dart 中的库/自定义库/内置库/第三方库

    1. Dart中的抽象类和抽象方法

    1.1 定义抽象类

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

    定义抽象类

    1. 抽象类通过abstract关键字类定义
    2. 抽象类不能被实例化
    // 定义抽象类
    abstract class Animate{
    
    }
    
    // 入口函数
    void main(){
        //  实例化抽象类就报错
        var cat = new Animate();
    
    }
    
    1.2 抽象方法

    抽象方法的定义

    1. Dart中没有方法体的方法我们称为抽象方法:
    2. Dart中的抽象方法不能用abstract声明,

    示例

    抽象类中的抽象方法

    // 定义抽象方法
    abstract class Animate{
    
        // 抽象方法
        // 抽象方法不能使用abstract声明
        // 如果使用就会报错
        void eat();
    }
    

    非抽象类中定义抽象方法就会报错,

    class Dog{
      // 属性
      String name = "哈士奇";
      
      // 方法
      void getInfo(){
        print("我是${name}");
      }
      
      // 抽象方法
      void sayHello();  // 报错
    
    }
    

    所以不要在非抽象类中定义抽象方法

    1.3 抽象类的说明
    1. 如果子类继承抽象类必须的实现里面的抽象方法
    2. 如果抽象类被当做接口实现的话, 子类必须得实现抽象类里面定义的所有属性和方法
    3. 抽象类不能被实例化,只有继承它的子类可以
    4. 抽象类通常用来定义接口,
    5. 抽象类通常具有 抽象方法
    6. 有抽象方法的类一定要声明为抽象类。

    使用示例

    // 定义一个抽象类
    abstract class Animal{
    
        // 抽象方法
        eat();
    }
    
    // 子类继承抽象类
    class Dog extends Animal{
        String name;
        Dog(this.name){}
    
        // 子类必须实现抽象类的方法
        @override
        eat() {
            print("${this.name}喜欢吃骨头");
        }
    }
    
    // 子类继承抽象类
    class Cat extends Animal{
        String name;
        Cat(this.name){}
    
        // 子类必须实现抽象类的方法
        @override
        eat() {
            print("${this.name}喜欢吃千层饼");
        }
    }
    
    void main(){
        Dog dog = new Dog("哈士奇");
        dog.eat();  // 哈士奇喜欢吃骨头
    
        Cat cat = new Cat("加菲猫");
        cat.eat();  // 加菲猫喜欢吃千层饼
    }
    
    1.4 抽象类也可以有非抽象方法

    抽象类里也可以定义非抽象方法, 这些方法都可以被子类多调用

    // 定义一个抽象类
    abstract class Animal{
    
        // 抽象方法
        eat();
    
        // 非抽象方法
        printInfo(){
            print("我就是抽象类里的一个非抽象方法");
        }
    }
    
    // 子类继承抽象类
    class Dog extends Animal{
        String name;
        Dog(this.name){}
    
        // 子类必须实现抽象类的方法
        @override
        eat() {
            print("${this.name}喜欢吃骨头");
        }
    }
    
    // 子类继承抽象类
    class Cat extends Animal{
        String name;
        Cat(this.name){}
    
        // 子类必须实现抽象类的方法
        @override
        eat() {
            print("${this.name}喜欢吃千层饼");
        }
    }
    
    void main(){
        Dog dog = new Dog("哈士奇");
        dog.eat();  // 哈士奇喜欢吃骨头
    
        // 子类调用继承的抽象类中的非抽象方法
        dog.printInfo();  // 我就是抽象类里的一个非抽象方法
    
        Cat cat = new Cat("加菲猫");
        cat.eat();  // 加菲猫喜欢吃千层饼
        dog.printInfo();  // 我就是抽象类里的一个非抽象方法
    }
    

    2. 多态

    2.1 正常使用的多态

    多态就是父类定义一个方法不去实现,让继承他的子类去实现, 每个子类有不同的表现

    其实刚刚讲的抽象类的示例就是一个多态, 父类定义eat方法, 但是没有实现他, 不同的子类实现了eat方法的不同功能,这就是多态

    2.2 子类的实例赋值给父类的引用

    Dart 中的多态 讲子类类型的指针赋值给父类类型的指针,同一个函数调用会有不同的执行效果

    // 定义一个抽象类
    abstract class Animal{
        // 抽象方法
        eat();
    }
    
    // 子类继承抽象类
    class Dog extends Animal{
        String name;
        Dog(this.name){}
    
        // 子类必须实现抽象类的方法
        @override
        eat() {
            print("${this.name}喜欢吃骨头");
        }
        
        // 子类自己的方法
        run(){
            print("${this.name}在愉快的奔跑");
        }
    }
    
    
    void main(){
        // 通过子类 定义实例
        //  Dog dog = new Dog("哈士奇");
        //  dog.eat();  // 哈士奇喜欢吃骨头
        //  dog.run();  // 哈士奇在愉快的奔跑
    
        // 将子类的实例赋值给了父类的引用
        Animal dog = new Dog("哈士奇");
        dog.eat();  // 哈士奇喜欢吃骨头
        //  dog.run();  // 这个时候就报错
    
    }
    

    我们会发现如果将子类的实例赋值给了父类的引用, 那么将只能使用父类限定的方法, 子类自己实现的自定义的方法将不能调用

    3. Dart中的接口

    3.1 dart 接口了解

    官网的定义

    一个类通过使用关键字implements 来实现一个或者多个接口。

    接口说明:

    1. 通类和抽象类都可以作为接口,类就是接口
    2. 一个普通类要实现某个接口,覆写接口接口类(普通或抽象类)的每个成员。
    3. 如果是复用已有类的接口,使用继承(extends)。
    4. 如果只是使用已有类的外在行为,使用接口(implements)。
    5. 每个类都隐式的定义了一个包含所有实例成员的接口
    3.2 普通类接口
    3.2.1 定义普通类

    通过class关键字定义普通类

    class Person{
        // 属性
        String name;
    
        // 构造函数
        Person(this.name);
    
        // 方法
        void sayHello(){
            print("大家好,我叫${name}");
        }
    }
    
    void main(){
        Person xm = new Person("小明");
        xm.sayHello();  //大家好,我叫小明
    }
    
    3.2.2 extends关键字实现类的继承

    定义子类继承这个父类

    // 父类
    class Person{
        // 属性
        String name;
    
        // 构造函数
        Person(this.name);
    
        // 方法
        void sayHello(){
            print("大家好,我叫${name}");
        }
    }
    
    // 子类通过extends 继承父类的方法
    class Student extends Person{
        String name;
        Student(this.name):super(name);
    
        // 子类自己的方法
        void getInfo(){
            print("他叫做${name}");
        }
    }
    
    
    void main(){
    
    
        Student xm = new Student("小明");
        xm.sayHello();  //大家好,我叫小明
        xm.getInfo();   // 他叫做小明
    }
    
    3.2.3 implements关键字实现接口

    现在将父类作为接口,让子类来实现这个接口

    // 接口类
    class Person{
        // 属性
        String name;
    
        // 构造函数
        Person(this.name);
    
        // 方法
        void sayHello(){
            print("大家好,我叫${name}");
        }
    }
    
    // 实现接口类
    class Student implements Person{
        // 覆写接口的属性
        @override
        String name;
        Student(this.name);
    
        // 覆写接口的方法
        @override
        void sayHello(){
            print("大家好,我叫${name}");
        }
    
        // 子类自己的方法
        void getInfo(){
            print("他叫做${name}");
        }
    }
    
    
    void main(){
        Student xm = new Student("小刚");
        xm.sayHello();  //大家好,我叫小刚
        xm.getInfo();   // 他叫做小刚
    } 
    

    这个时候我们就会发现, 这是不是子类继承父类的关系,而是父类就是定义接口,实现接口的子类要覆写接口中的所有属性和方法.

    3.3 抽象类接口

    建议:

    将抽象类作为接口使用(类就是接口),让子类来实现(关键字implements来实现)

    因为抽象类的所有的方法不用定义方法体, 而普通类定义的方法需要实现方法体, 反正这些方法在作为接口的时候都是需要被实现接口的子类覆写的,那么有没有方法体已经不重要了,所以推荐使用抽象类作为接口

    // 定义一个抽象类接口
    abstract class Db{
        String uri;
        // 抽象方法
        add(String data);
        save();
        delete();
    }
    
    // Mysql 实现接口
    class Mysql extends Db{
        @override
        String uri;
        Mysql(this.uri);
    
        // 子类必须实现抽象类的方法
        @override
        add(data){
            print("这是Mysql的${data}");
        }
        @override
        save(){
            print("这是Mysql的save方法");
        }
        @override
        delete(){
            print("这是Mysql的delete方法");
        }
    }
    
    
    void main(){
        Mysql mysql = new Mysql("mysql");
        mysql.add("123456");  // 这是Mysql的123456
        mysql.save();   // 这是Mysql的save方法
        mysql.delete();  // 这是Mysql的delete方法
    }
    

    4. Dart中一个类实现多个接口

    extends 关键字的继承没发做到多继承,如果需要继承多个类, extends是不能实现的,

    那么我们就可以把需要继承的类作为接口,使用关键字implements来实现多个接口

    还是要注意区分

    1. extends 是继承 就算有些父类的方法不覆写,子类的实例也能使用父类的方法
    2. implements 是实现接口,不管实现多少父类接口, 父类里的所有方法都需要覆写的,

    实现多接口的示例:

    // 抽象类A接口
    abstract class A{
        String name;
    
        // 抽象方法
        printA();
    }
    
    // 抽象类B接口
    abstract class B{
        int age;
    
        // 抽象方法
        printB();
    }
    
    
    // Student 类实现 A和B 两个接口
    class Student implements A,B{
        // 覆写接口的属性
        @override
        String name;
        int age;
        Student(this.name,this.age);
    
        // 实现A接口的方法
        @override
        void printA(){
            print("实现A接口的方法");
        }
        // 实现B接口的方法
        @override
        void printB(){
            print("实现B接口的方法");
        }
    
        // 子类自己的方法
        void sayHello(){
            print("大家好, 我叫${name},今年${age}岁了");
        }
    }
    
    // 入口函数
    void main(){
        // 实例化子类
    
        Student xm = new Student("小刚",8);
        xm.printA();   // 实现A接口的方法
        xm.printB();   // 实现B接口的方法
        xm.sayHello();  //大家好, 我叫小刚,今年8岁了
    
    } 
    

    5. 枚举类型

    枚举类型也称为 enumerationsenums , 是一种特殊的类,用于表示数量固定的常量值。

    说明:

    1. 使用 enum 关键字定义一个枚举类型.
    2. 枚举是一种有穷序列集的数据类型。
    3. 常用于代替常量,控制语句等
    4. 枚举中的每个值都有index,返回索引,索引从0开始.
    5. 枚举中的每个值可以使用values 属性列举出来

    枚举的限制:

    1. 枚举不能被子类化,混合或实现。
    2. 枚举不能被显式实例化。
    // 定义枚举
    enum Color {
        red,
        green,
        blue,
        // 不能指定值,会报错的
        //    whie = "#fff"
    
    }
    
    // 入口函数
    void main(){
        // index 获取索引
        print(Color.red.index);  
        print(Color.green.index);
        print(Color.blue.index);
    
        // value
        print(Color.red);
    
        // 枚举值
        List list = Color.values;
        print(list); //[Color.red, Color.green, Color.blue]
    
    
        // 流程控制
        var color = Color.red;
    
        switch(color){
            case Color.red:
                print("红色");
                break;
            case Color.green:
                print("绿色");
                break;
            case Color.blue:
                print("蓝色");
                break;
        }
    } 
    
    

    6. Mixin 混入

    官方定义:

    Mixin 是复用类代码的一种途径, 复用的类可以在不同层级,之间可以不存在继承关系。

    简单说就是在类中混入其他的功能,实现类似多继承的功能

    说明:

    1. 使用mixin关键字替换class定义混入类
    2. 作为Mixin的类只能继承Object,不能继承其他的类
    3. Mixin 类似于多继承,实在多类继承中重用一个类代码的方式。
    4. 作为mixins的类不能声明构造函数,不能调用 super
    5. 一个类可以混入多个Mixin
    6. 使用with 方法实现类似于多继承
    7. mixins绝不是继承 也不是接口, 而是一种全新的特性
    6.1 混入普通的类

    使用关键字with混入普通的类

    // 定义普通混入类
    class A{
        String name = "AA";
    printA(){
        print("这是普通类A");
    }
    }
    
    class B{
        String name = "BB";
    printB(){
        print("这是普通类B");
    }
    }
    
    // 混入两个类A,B
    class Student with A,B{
    
    }
    
    // 入口函数
    void main(){
        // 实例化子类
        Student student = new Student();
        print(student.name);  // BB
        student.printA();     // 这是普通类A
        student.printB();    // 这是普通类B
    
    } 
    

    在混入多个类是,类中有相同 的属性或方法,后混入的会将先混入的覆盖掉

    6.2 使用mixin定义混入类
    // 使用mixin关键字定义混入类
    mixin A{
        String name = "AA";
        printA(){
            print("这是普通类A");
        }
    }
    
    mixin B{
        String name = "BB";
        printB(){
            print("这是普通类B");
        }
    }
    
    class Student with A,B{
    
    }
    
    // 入口函数
    void main(){
        // 实例化子类
        Student student = new Student();
        print(student.name);  // BB
        student.printA();     // 这是普通类A
        student.printB();    // 这是普通类B
    
    } 
    
    6.3 注意混入的类不能有构造函数

    无论是class定义的混入类,还是mixin定义的混入类, 有构造函数就不错

    但是如果class定义的类不作为混入类使用,就不会报错

    // 混入类不能有构造函数会报错
    
    // mixin 定义的混入类
    mixin A{
        String name = "AA";
        //   A(this.name);  // 报错
        printA(){
            print("这是普通类A");
        }
    }
    
    
    // class定义的混入类
    class B{
        String name = "BB";
        // B(this.name);   // 报错
        printB(){
            print("这是普通类B");
        }
    }
    
    // 混入类
    class Student  with A,B{
    }
    
    6.4 混入类不能继承其他类
    // 被继承的类
    class Person{
        int age ;
        Person(this.age);
    
        printInfo(){
            print("被继承的类Person, 年纪${this.age}");
        }
    }
    
    // B 是混入类,不能继承其他类, 报错
    class B extends Person{
        printB(){
            print("混入类B");
        }
    }
    
    
    // 混入
    class Student with B{
    
    }
    
    6.5 混入不影响继承
    // 第一个类
    mixin A{
        String name = "AA";
        printA(){
            print("这是普通类A");
        }
    }
    
    class B{
        String name = "BB";
        printB(){
            print("这是普通类B");
        }
    }
    
    // 被继承的类
    class Person{
        int age ;
        Person(this.age);
    
        printInfo(){
            print("被继承的类Person, 年纪${this.age}");
        }
    }
    
    
    // 继承一个类混入两个类
    class Student extends Person with A,B{
        Student(int age):super(age);
    }
    
    
    void main(){
        // 实例化类
        Student student = new Student(18);
        // 继承类
        student.printInfo(); // 被继承的类Person, 年纪18
    
        // 混入类的方法
        print(student.name);  // AA
        student.printA(); // 这是普通类A
        student.printB(); // 这是普通类B
    }
    

    相关文章

      网友评论

        本文标题:第七节: Dart中抽象类abstract/接口implemen

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