Dart 2ベース(8)-クラスと列挙

10765 ワード

目次
クラスの定義と使用
オブジェクトの種類を取得
インスタンス変数
構造関数
サブ構造関数
リダイレクトコンストラクタ
静的コンストラクタ
工場構造関数
実例的な方法
抽象類と方法
隠蔽インターフェース
クラスの継承
演算子をリロード
列挙
mixins
クラス変数と方法
Dart 2のクラスはすべてObjectに引き継がれます.Dart 2の各クラスにはスーパークラス(Objectを除く)がありますが、一つのクラスの主体は複数のクラスで使えます.
  • 類の定義と使用
    Dart 2でキーワードclassを使ってクラスを定義します.クラスのメンバーを呼び出します.?は、オブジェクトが空でない場合は、メンバーを呼び出し、空の場合はスキップします.
    class Animal{
    
      String name;
    
      //     
      Animal(String name){
        this.name = name;
      }
    
      run(){
        print("${this.name} is running");
      }
    }
    
    main(List args) {
      //           
      var cat = Animal("cat"); 
      //     new     ,new Dart2      
      var dog = new Animal("dog");
      cat.run();
      dog.run();
      // cat  null ,name    
      cat?.name = "small cat";
      cat.run(); // small cat is running;
      Animal nullAnimal;
      // nullAnimal null,      nullAnimall.name,        
      nullAnimal?.name = "null";
    }
  • オブジェクトタイプ
  • を取得する.
    各オブジェクトにはruntimeTypeの属性があり、この属性によりそのオブジェクトのタイプ(Typeのオブジェクト)が取得できます.
    class Animal(){}
    
    main(){
        //       Type   
        print(Animal().runtimeType); // Animal
    }
  • インスタンス変数
  • 各インスタンス変数には暗黙的なGet方法があり、変数がfinalタイプでない場合、インスタンス変数には暗黙的なSet方法があります.
    インスタンス変数に初期値がある場合、その値は構造方法が有効になる前に与えられています.
    GetとSet方法を書き換えるなら、キーワードgetとsetで実現できます.
    Dart 2中は_で最初の変数と方法は、すべてプライベートです.
    //       
    class Rectangle {
      num left = 10;
      num _left_width = 12; //     
      
      //       
      num top, width, height;
    
      Rectangle(this.left, this.top, this.width, this.height);
    
      //         : right and bottom.
      //       ,get set      
      //   get
      num get right => left + width;
      //   set
      set right(num value) => left = value - width;
      num get bottom => top + height;
      set bottom(num value) => top = value - height;
    }
    
    void main() {
      var rect = Rectangle(3, 4, 20, 15);
      assert(rect.left == 3);
      rect.right = 12;
      assert(rect.left == -8);
    }
  • 構築関数
  • コンストラクタの定義は、関数名をClass NameとClass Name.identiferとして定義することができます.
    名前付きのコンストラクタによって,複数の異なるコンストラクタが簡単に実現できる.
    クラスにコンストラクタがない場合、デフォルトではパラメータなしのコンストラクタがあります.
    class Animal{
    
      String name;
    
      String color = "yellow";
      
      Animal(String name){
        this.name = name;
      }
      //        ,     
      Animal(this.name);
    
      Animal.createInstance(Map values){
        name = values["name"];
      }
    
      run(){
        print("${this.name} is running");
      }
    }
    main(List args) {
      var animal = Animal.createInstance({"name": "dog"});
      print(animal.name);
    }
  • サブクラス構成関数
  • 父の名前の構造関数は布団類の継承ができません.サブクラスも父親のような名前のコンストラクタを持つには、サブクラスでこのコンストラクタを実現する必要があります.デフォルトでは、サブクラスは親の名前なし、パラメータなしのコンストラクタしか呼び出しられません.親の名前のない構造関数は、サブクラスの構造関数の前で呼び出されます.initializer listも同時に定義されたら、initializer listの内容を先に実行して、父類の名前のないパラメーター構造関数を実行して、最後にサブクラス自身の名前のないパラメーター構造関数を呼び出します.以下の順序です.
  • initializer list(初期化リスト)
  • superclass's no-arg constructor
  • main class’s no-arg constructor
  • 親が無パラメータ構造関数を提供する構造関数を表示しない場合、サブクラスでは父親クラスの構造関数を明示的に呼び出す必要があります.この場合、親のようなコンストラクタを呼び出すコードは、サブコンストラクタ名の後に、サブコンストラクタの前に置かれ、中間は:(colon)で分割される.開発状態では、初期化リストは、クラスリスト表現を使用することができます.
    class Animal{
    
      String name;
    
      String color = "yellow";
    
      Animal.createInstance(Map values){
        print("in animal");
        name = values["name"];
      }
    
      run(){
        print("${this.name} is running");
      }
    }
    
    // extends       
    class Bird extends Animal{
      String name = "blue bird";
      String desc;
    
      Bird.createInstance(Map values):
        desc = name, //      ,      this 
        super.createInstance(values){ //         super
          print("in bird");
        }
    
    }
    
    main(List args) {
     var bird = Bird.createInstance({
       "name": "bird"
        });
     print(bird.name); // bird
     print(bird.desc); // blue bird
    }
     
  • リダイレクト構造関数
  • リダイレクトコンストラクタとは、あるコンストラクタの中で別のコンストラクタを指すが、リダイレクトコンストラクタの関数は空である.公式サイトのコードを例にします.
    class Point {
      num x, y;
    
      //      
      Point(this.x, this.y);
    
      //        
      Point.alongXAxis(num x) : this(x, 0);
    }
  • 静的構造関数
  • クラスのオブジェクトが変更されない場合は、これらのオブジェクトはコンパイル時定数となります.静的コンストラクタを作成し,全メンバ属性がfinalであることにより実現した.
    静的コンストラクタは、コンパイル時定数を返します.
    class Animal{
      final String name;
      final String color;
    
      //       
      const Animal(this.name, this.color);
    }
    
    main(List args) {
      var cat = const Animal("cat", "yellow");  //   
      var cat2 = const Animal("cat", "yellow");
      var cat3 = Animal("cat", "yellow"); //    
        
      //             ,        
      print(identical(cat, cat2)); // true
      print(identical(cat, cat3)); // false
      //        ,                
      const cats = const {
        'bluscat': const [const Animal("cat", "blue")],
        'yellowcat': const [const Aminal("cat", "yellow")],
      };
      //              ,  Dart2    
      const cats2 = {
        'bluscat': [Animal("cat", "blue")],
        'yellowcat': [Aminal("cat", "yellow")],
      };
    }
  • 工場構造関数
  • キーワードfinalを使って工場の構造関数を実現します.工場構造関数は毎回新しいオブジェクトを作成する必要がないようにできます.キャッシュがあるように、古いオブジェクトをキャッシュしました.
    工場の構造関数ではthisは使えません.
    以下は公式サイトの例です.
    class Logger {
      final String name;
      bool mute = false;
    
      //     
      static final Map _cache =
      {};
    
      factory Logger(String name) {
        if (_cache.containsKey(name)) {
          return _cache[name];
        } else {
          final logger = new Logger._internal(name);
          _cache[name] = logger;
          return logger;
        }
      }
    
      Logger._internal(this.name);
    
      void log(String msg) {
        if (!mute) {
          print(msg);
        }
      }
    }
    void main() {
      var p1 = Logger("Part1");
      p1.log("this is part1");
    
      var p2 = Logger("Part2");
      p2.log("this is part2");
    
    }
    
  • 例示的な方法
  • 実例的な方法はオブジェクトの関数です.例示的な方法では、インスタンス変数とthisを使用することができる.
    class Animal(){
        String name;
        Animal(this.name);
        //     
        void run(){
            print("${this.name} is running");
        }
    }
  • 抽象類と方法
  • キーワードを使ったabstract声明の種類は、抽象的なものです.抽象的な方法は体を実現する方法がないので、抽象的な方法は抽象的な種類の中に存在するしかないです.
    実例的な方法、Setter、およびGetter方法は、いずれも抽象的な方法であってもよい.
    抽象類は実用化されない.抽象類を実用化したいなら、工場の構造関数で実現できます.
    抽象類は一般にインターフェースを定義するために用いられる.
    abstract class Animal{
      String color = "blue";
    
      //     
      run();
    
    }
    
    class Bird extends Animal{
      
      String name;
    
      Bird(this.name);
      //        
      run(){
        print("A ${this.color} ${this.name} is flying");
      }
    }
    
    main(List args) {
      var bird = Bird("tom");
      bird.run();
    }
  • 暗黙インターフェース
  • Dart 2の各クラスには暗黙的なインターフェースがあり、この暗黙的なインターフェースはすべてのインスタンスメンバーと実装されたインターフェースのインスタンスメンバーを含む.
    クラスAサポートクラスBのAPI関数を作成したいが、Bの実装を引き継ぎたくない場合、クラスAはクラスBのインターフェースを引き継ぐ必要があります.
    インターフェースを継承するキーワードはimplemensで、一つのクラスは複数のインターフェースを継承することができます.
    class Animal{
      String _name; //     ,      ,          
    
      Animal(this._name); //          
    
      run(){
        print("${this._name} is running");
      }
    
    }
    
    //   Animal   ,         ,   ,   implements Animal, ...
    class Bird implements Animal{
      String _name;
      Bird(this._name);
      run(){
        print("${this._name} can not run");
      }
    }
    
    runningAnimal(Animal animal){
      animal.run();
    }
    
    main(List args) {
      runningAnimal(Animal("dog")); // dog is running
      runningAnimal(Bird("bird"));  // bird can not run
    }
  • 類の継承
  • extensを使用して親クラスを継承し、superを指定します.
    サブクラスは、親タイプの実例的な方法、Setter、Getterを再ロードし、@override注釈を使って、新しい方法を再構築することができます.
    noSuchMethod()を再ロードする方法は、オブジェクトビューで存在しない方法または変数を呼び出したときに呼び出すことができます.ただし、存在しない方法を呼び出すことはできません.次の場合を除き、
    1.静的なタイプのdynamicの変数.
    2. 受信者は、実装されていない方法を定義する静的なタイプ(抽象的でもよい)があり、受信者はdynamicであり、noSuchMethod()の実装は、クラスObjectにおける実装とは異なる.
    class Animal{
    
      String name;
    
      String color = "yellow";
    
      Animal.createInstance(Map values){
        print("in animal");
        name = values["name"];
      }
    
      run(){
        print("${this.name} is running");
      }
    }
    
    // extends       
    class Bird extends Animal{
      String name = "blue bird";
      String desc;
    
      Bird.createInstance(Map values):
        desc = name, //      ,      this 
        super.createInstance(values){ //         super
          print("in bird");
        }
        
       @override
       run(){
         pirnt("${this.name} can not run");
      }
      @override
      void noSuchMethod(Invocation invocation) {
        print('You tried to use a non-existent member: ' +
            '${invocation.memberName}');
      }
    }
    
  • リロード演算子
  • 再読み込み可能な演算子はありますか?<+|[]>/^[]=<=~/&~>=*<<==%>> 
    class Person{
    
        String name;
        
        Person(this.name);
        //    + 
        Person operator + (Person p){
          return Person(this.name + " *** " + p.name);
        }
    }
    
    main(List args) {
      var man = Person("man");
      var woman = Person("woman");
      var person = man + woman;
      print(person.name); // man *** woman
    }
  • エニュメレーション
  • 列挙の種類は特殊な種類で、通常は同じタイプの定数のセットを表すために用いられます.キーワードenumを使って列挙を定義します.
    列挙の各値にはindex属性があり、indexは0から数え始めます.
    列挙は引き継がれず、インスタンスは作成できません.
    enum Animal {
      cat,
      dog,
      bird
    }
    
    main(List args) {
      print(Animal.dog.index); // 1
      //        
      List animals = Animal.values;
      Animal dog = Animal.dog;
      switch (dog) {
        case Animal.cat:
          print("animal is cat");
          break;
        case Animal.dog:
          print("animal is dog");
          break;
        default:
          print("which animal?");
      }
      // animal is dog
    }
  • mixins
  • mixinsはクラスに新しい特性を追加する方法であり、クラスコードを再利用する方法でもある.
    mixinsのキーワードはwithです.詳細な使用は、ドキュメントを見ることができます.
    withは単独では使えません.extensに従って使用しなければなりません.
    class Fly{
      fly(){
        print("flying");
      }
    }
    class Animal{}
    
    class Bird extends Animal with Fly{
    
    }
    
    main(List args) {
      var bird = Bird();
      bird.fly(); // flying
    }
  • クラスの変数と方法
  • キーワードstaticを使って、クラス変数とクラス方法を宣言します.
    class Animal{
    
      static var name; //    
      static const color = "yellow"; //     
    
      //    
      static run(){
        print("running");
      }
    
    }
    
    main(List args) {
      Animal.name = "dog";
      print(Animal.name); // dog
      Animal.run(); // running
    }