美文网首页Dart
Dart系列-面向对象(一)

Dart系列-面向对象(一)

作者: h2coder | 来源:发表于2020-10-23 10:01 被阅读0次

    周末学习了一下Dart语言,按照慕课网Flutter开发第一步-Dart编程语言入门教程进行学习,所以记录一下,感觉慕课网的老师辛苦做的视频教程,说得很清楚,有基础学起来很轻松也很快,本篇来学习dart的面向对象(一)。

    类和对象

    dart也是一门面向对象的语言,所以也有类和对象的概念。

    • 类的声明,使用class关键字定义类。
    class Person {
        //类成员
        String name;
        int age;
        //final修饰的属性,不能被外部重新赋值,只可读,不可写
        final String address = null;
        
        void work() {
        print('Name is $name, Age is $age, He is working');
      }
    }
    
    • 类的私有方法

    不同Java有丰富的权限操作符。dart默认都是公开的,在变量名或方法名前加入_前缀即为私有。

    class Person {
      //_前缀可以标识属性,代表属性是私有的
      String _name;
      
      //_前缀也可以标识方法,表示方法是私有的
        void _work() {
        print('Name is $_name, Age is $age, He is working');
      }
    }
    
    • dart的方法不支持重载。
    class Person {
      void work() {
        print('Name is $name, Age is $age, He is working');
      }
      
      //不支持重载,这样写是编译不通过的
      void work(int a) {
    
      }
    }
    
    • 创建对象,使用new关键字或不写new关键字
    void main() {
      //var person = new Person();
      var person = Person();
      person.name = 'Tom';
      person.age = 20;
      print(person.name);
      person.work();
    
      //final属性不能重新赋值
      //person.address = 'china';
    }
    

    计算属性

    例如我们有个矩形类,有宽和高属性,需要计算它的面积时,我们通常会建立一个方法去计算再返回。而dart则提供了计算属性,dart允许申明一个计算属性来通过计算得出的结果做为属性的值。

    • 传统创建方法进行计算的方式
    class Rectangle {
      num width;
      num height;
      
      //自定义方法来实现求面积
      num area() {
        return width * height;
      }
    }
    
    • 使用dart提供的计算属性

    和申明变量的格式一样,加上get关键字,表示为计算属性,右边是箭头函数,写成一对花括号也是一样的。

    class Rectangle {
      num width;
      num height;
      
      //计算属性,使用get关键字标识,生成一个area属性,他是width和height计算而得来的
      num get area => width * height;
    }
    
    • 计算属性的设置

    计算属性除了内部定义后,进行get操作外,还可以进行赋值操作。例如面积的反算,根据一个高度值,计算出宽度。再将计算出来的值赋值给宽度属性。

    class Rectangle {
      num width;
      num height;
      
      //计算属性,使用get关键字标识,生成一个area属性,他是width和height计算而得来的
      num get area => width * height;
      
      //给计算属性进行赋值,使用set关键字
      set area(value) {
        //结果赋值给另外一个属性
        width = value / 20;
      }
    }
    
    

    构造方法

    既然有类的声明,就有类的构造方法。

    • 默认编译器会给类添加一个无参构造方法。手动声明也可以,效果是一样的。
    class Person {
      String name;
      int age;
    
        //默认无参构造方法
      Person() {
      }
      
      void work() {
        print('Name is $name, Age is $age, Gender is $gender, He is working');
      }
    }
    
    void main() {
        Person person = new Person();
        person.name = 'Tom';
        person.age = 20;
        person.work();
    }
    
    • 有参构造方法。还可以使用dart提供的语法糖进行声明。
    class Person {
      //定义一个有参构造,就不会默认生成一个无参构造方法了
      Person(String name, int age) {
        this.name = name;
        this.age = age;
      }
      
      //dart提供的语法糖
      //直接赋值的方式,this直接指定,它是在构造方法执行之前进行赋值的!
      //Person(this.name, this.age);
    }
    
    • 命名构造方法。但如果类已经声明了一个有参构造方法了,编译器就不会给类添加一个无参构造了。那如果我需要一个无参构造方法,还需要一个有参构造方法,像Java那样声明是不可以的,dart没有方法重载,而构造方法也一样,这时候就需要用到命名构造方法,格式:类型.命名(参数)。
    class Person {
      //...
      
      //如果我想有一个有参构造方法,也有一个无参构造方法,dart是不能重载的,所以不能添加
      //这时候就需要用到命名构造方法,格式为:类名.方法名
      Person.withName(String name) {
        this.name = name;
      }
    
      //命名构造方法也可以使用直接设置属性的语法糖
      Person.withAge(this.age);
    
      //...
    }
    

    常量构造方法

    当类的属性设置一次之后,就不会再设置了,那么这个类就可以声明为常量类,常量类的属性使用final修饰,而构造方法使用const修饰。

    class Person {
      final String name;
      final int age;
      final String gender;
    
      const Person(this.name, this.age, this.gender);
    
      void work() {
        print('Name is $name, Age is $age, Gender is $gender, He is working');
      }
    }
    
    void main() {
      //如果需要将对象作为常量,就需要将构造方法声明为常量构造方法
      //使用常量构造方法的对象,属性和构造方法都为常量,属性使用final修饰,构造方法使用const修饰
      //常量型对象运行时更快,如果对象的值设置一次后就不会改变,可以使用这种方式
      const person = const Person('Tom', 18, 'Male');
      person.work();
    }
    

    工厂构造方法

    在Java中,我们会使用工厂设计模式,生产不同类型的实例,而dart则提供了工厂构造方法的语法糖,方便我们实现工厂模式生产实例。

    • 工厂构造方法,使用factory关键字声明,这个工厂以一个String类型的key作为缓存key,类的实例作为缓存value。当没有缓存时构造实例,并缓存起来,如果有缓存则取出并返回。
    class Logger {
      final String name;
    
      static final Map<String, Logger> _cache = Map();
    
      //工厂构造方法使用factory关键字,和构造方法的区别是,工厂构造方法能有返回值,而构造方法不行
      factory Logger(String name) {
        //如果有缓存,直接返回
        if (_cache.containsKey(name)) {
          return _cache[name];
        } else {
          //否则使用命名构造方法生成对象,再放到缓存中
          final logger = Logger._internal(name);
          _cache[name] = logger;
          //再返回出去
          return logger;
        }
      }
    
      //_前缀也可以修饰命名构造方法,标识为私有的
      Logger._internal(this.name);
    
      void log(String msg) {
        print(msg);
      }
    }
    

    初始化列表

    声明为final的成员属性,需要在构造方法时就赋值,除了使用dart提供的语法糖进行中直接赋值外,还可以使用初始化列表。

    • 初始化列表的格式,在构造方法名后:final属性=值,多个用逗号分隔。
    class Person {
      String name;
      int age;
      final String gender;
    
      Person(this.name, this.age, this.gender);
    
      //命名构造方法+初始化列表,:号后进行final属性的赋值,多个属性中间用,号分隔
      Person.withMap(Map map) : gender = map["gender"] {
        this.name = map["name"];
        this.age = map['age'];
      }
    
      printPerson() {
        print('name=$name, age=$age, gender=$gender');
      }
    }
    
    void main() {
      //初始化列表
      var map = Map();
      map['name'] = 'wally';
      map['age'] = 18;
      map['gender'] = 'Male';
      var person = Person.withMap(map);
      person.printPerson();
    }
    

    静态成员

    类的成员,为静态成员。dart和java的静态成员基本一致。

    • 静态方法,只能访问静态成员。
    • 实例方法,既能访问静态成员,也可以访问实例成员。
    class Page {
      //静态常量
      static const int maxPage = 10;
      static int currentPage;
      int firstPage = 1;
    
      //静态方法能访问静态成员
      static void scrollDown() {
        currentPage = 1;
        //静态方法不能访问实例变量
        //firstPage++;
        print("scroll down -> currentPage: $currentPage");
      }
    
      //实例也能访问静态成员
      void scrollUp() {
        currentPage++;
        firstPage++;
        firstPage;
        print("scroll up -> currentPage:$currentPage");
      }
    }
    
    void main() {
      Page page = Page();
      Page.scrollDown();
      page.scrollUp();
    }
    

    对象操作符

    • 空安全对象操作符。如果调用一个值为null的对象的属性或方法,会抛出异常。传统方式需要判空,而dart提供了空安全的操作符,在调用处加上?即可。
    Person person;
    //?.对象操作符,在对象为null时,不会进行调用
    person?.work();
    //属性也可以使用?.
    person?.name;
    
    • as操作符。将对象强转为某个类型。如果类型强转出错则会抛出异常。
    //没有推断出Person,类型为dynamic
    var person2;
    //因为类型为dynamic,可以赋值任意类型
    person2 = "";
    //as操作符,强转类型,这里是String类型,强转为Person类型会抛出异常。
    (person2 as Person).work();
    
    • is操作符,判断对象是否为某个类型的实例。是返回true,不是则返回false。一般is会配合as使用,但是通过is后,类型会自动转换,所以as操作符就不用了。而Java判断类型后还需要强转类型。
    if (person2 is Person) {
        print('object is Person');
    }
    
    if (person2 is Person) {
        //经过了is操作符判断,就不用as操作符再转换再操作
        person2.work();
    }
    
    • 级联操作符

    当一个类有多个set方法时,一般我们会让set方法后return返回当前对象,来做到链式操作,或者使用builder设计模式进行链式操作,而dart提供了级联操作符。格式为:对象...setXxx()...setYyy();

    //级联操作符,每次操作后都返回自身,方便链式调用
    var person3 = new Person();
    person3
    ..name = 'wally'
    ..age = 19
    ..work();
    

    对象的call方法

    dart中,默认一个规定,对象中存在call方法,那么输出对象时,调用的不是对象的toString()方法,而是声明的call方法。toString()方法不能传入参数,而call方法则不是,输入参数和返回值都可以自定义,只要名字为call即可。

    void main() {
      var person = new Person();
      //call方法,输出对象默认调用对象的默认方法
      //可以带参数,有返回值,只要名称是call就可以
      String result = person('wally', 19);
      print(result);
    }
    
    class Person {
      String name;
      int age;
    
      String call(String name, int age) {
        return "name=$name,age=$age";
      }
    }
    

    相关文章

      网友评论

        本文标题:Dart系列-面向对象(一)

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