Dart

Dart系列-面向对象(一)

2020-10-23  本文已影响0人  h2coder

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

类和对象

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

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');
  }
}
class Person {
  void work() {
    print('Name is $name, Age is $age, He is working');
  }
  
  //不支持重载,这样写是编译不通过的
  void work(int a) {

  }
}
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;
  }
}

和申明变量的格式一样,加上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();
}
class Person {
  //定义一个有参构造,就不会默认生成一个无参构造方法了
  Person(String name, int age) {
    this.name = name;
    this.age = age;
  }
  
  //dart提供的语法糖
  //直接赋值的方式,this直接指定,它是在构造方法执行之前进行赋值的!
  //Person(this.name, this.age);
}
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则提供了工厂构造方法的语法糖,方便我们实现工厂模式生产实例。

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提供的语法糖进行中直接赋值外,还可以使用初始化列表。

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();
}

对象操作符

Person person;
//?.对象操作符,在对象为null时,不会进行调用
person?.work();
//属性也可以使用?.
person?.name;
//没有推断出Person,类型为dynamic
var person2;
//因为类型为dynamic,可以赋值任意类型
person2 = "";
//as操作符,强转类型,这里是String类型,强转为Person类型会抛出异常。
(person2 as Person).work();
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";
  }
}
上一篇下一篇

猜你喜欢

热点阅读