Extending base List class with extra functionality

2019-08-11 23:53发布

问题:

This question is about Dart language. I want to have a class which is just a List but with some extra functionality.

For example I have a class named Model:

class Model{
  String name;
  int type;
  Model(this.name, this.type);
}

I know that Model's type could take only four values: from 0 to 3. And I want to have a method, which can give me a List of Models of specified type, e.g. List<Model> modelCollection.getByType(int type);. I plan to to have four 'hidden' Lists of the Models (grouped by type) in that class. Thus I need to override addition and removal of List elements to make that hidden lists being up to date.

How can I realize this as easy as possible?

P.S. I know this is quite simple, but I'm poorly familiar with Object inheritance and can't find proper examples. P.P.S. I've also checked this but don't know is it outdated or not and didn't catch the idea.

回答1:

To make a class implement List there are several ways :

  • Extending ListBase and implementing length, operator[], operator[]= and length= :
import 'dart:collection';

class MyCustomList<E> extends ListBase<E> {
  final List<E> l = [];
  MyCustomList();

  void set length(int newLength) { l.length = newLength; }
  int get length => l.length;
  E operator [](int index) => l[index];
  void operator []=(int index, E value) { l[index] = value; }

  // your custom methods
}
  • Mixin ListMixin and implementing length, operator[], operator[]= and length= :
import 'dart:collection';

class MyCustomList<E> extends Base with ListMixin<E> {
  final List<E> l = [];
  MyCustomList();

  void set length(int newLength) { l.length = newLength; }
  int get length => l.length;
  E operator [](int index) => l[index];
  void operator []=(int index, E value) { l[index] = value; }

  // your custom methods
}
  • Delegating to an other List with DelegatingList from the quiver package:
import 'package:quiver/collection.dart';

class MyCustomList<E> extends DelegatingList<E> {
  final List<E> _l = [];

  List<E> get delegate => _l;

  // your custom methods
}

Depending on your code each of those options have their advantages. If you wrap/delegate an existing list you should use the last option. Otherwise use one of the two first options depending on your type hierarchy (mixin allowing to extend an other Object).



回答2:

A basic approach is to extend an Object with IterableMixin. It also seems that you don't even need to override the "length" getter or let's say all methods that the IterableMixin already provides.

import 'dart:collection';    

class Model {
   String name;
   int type;

   Model(this.name, this.type) {
   }
}

class ModelCollection extends Object with IterableMixin {

   List<Model> _models;
   Iterator get iterator => _models.iterator;

   ModelCollection() {
      this._models = new List<Model>();
   }

   //get one or the first type
   Model elementByType(int type) {

     for (Model model in _models) {
       if (model.type == type) {
          return model;
       }
     }       
   }

   //get all of the same type
   List<Model> elementsByType(int type) {

      List<Model> newModel = new List<Model>();

      for (Model model in _models) {
         if (model.type == type) {
            newModel.add(model);
         }
      }
      return newModel;       
   }

   add(Model model) {
      this._models.add(model);
   }
}

Excuse my strong static typing.



回答3:

You might be interested in quiver.dart's Multimap. It behaves like a Map that allows multiple values per key.

Here's the code on github: https://github.com/google/quiver-dart/blob/master/lib/src/collection/multimap.dart#L20

It's on pub simply as quiver. We'll be hosting the dartdocs somewhere soon.