Дарт, переопределите многие геттеры и сеттеры DRY или syntheti c в Proxy Pattern - PullRequest
1 голос
/ 08 января 2020

Давайте возьмем этот класс дротиков:

class Subject {
  String a;
  String b;
  String c;
}

Теперь я хочу использовать его через прокси-сервер для управления отложенной загрузкой и синхронизацией.

Я также хочу иметь значения по умолчанию для использования в качестве заполнителей, пока я загружаю реальные данные из net. Чтобы держать бедра опрятными и изолированными, я добавил еще один класс:

class Fallback implements Subject {
  @override String a = 'a';
  @override String b = 'b';
  @override String c = 'c';
}

Теперь у меня есть все кирпичики, которые мне нужны, чтобы записать класс "прокси с резервным":

class Proxy implements Subject {
  Subject model;
  Subject fallback = Fallback();

  Future<void> slowlyPopulateModel() async => if (model == null) ... // do some async stuff that valorize model

  @override
  String get a {
    slowlyPopulateModel();
    return model?.a ?? fallback.a;
  }
  @override
  set a(String _a) {
    model?.a = a;
    notifyListener();
  }

  // same getters and setters for b and c
}

Переопределив get a Я могу при необходимости вызвать метод медленного ввода-вывода и вернуть значение заполнителя моего Fallback класса. Как только новое значение будет установлено, мое переопределенное значение set a(String _a) вызовет notifyListener(), что обновит мой интерфейс.
Это работает нормально, но я вручную переопределил getter и setter для каждого поля моего класса (а их много) ,

Есть ли у Дарта какой-нибудь трюк, чтобы сделать это более DRY способом?
Например, каким-то образом внедрить код, который будет выполняться до или после каждого метода получения или установки?

1 Ответ

1 голос
/ 08 января 2020

Я бы посоветовал взглянуть на Streams.

Этот пример кода вернет начальное значение, извлечет новое значение и уведомит слушателя об этом через поток.

import 'dart:async';

class Subject {
  // Current value, initially at "a"
  String _a = "a";

  StreamController<String> _aController = StreamController<String>();

  String get a {
    _updateA();
    return _a;
  }

  Stream<String> get aStream => _aController.stream;

  void _updateA() async {
    String newValue = await _fetchA();
    _a = newValue; // update the current value
    _aController.add(newValue); // push the new value onto the stream for listeners
  }

  // return a String after two seconds
  Future<String> _fetchA() async {
    return Future.delayed(
      Duration(seconds: 2),
      () => "New value for _a",
    );
  }

  // This closes the stream
  void dispose() {
    _aController.close();
  }

}

main(args) {
  final subject = Subject();

  // listen to changes
  subject.aStream.listen((value) {
    print("new value of a: $value");
  });

  // get current value
  final currentValue = subject.a;
  print("current value of a: $currentValue");

}

Вывод этого примера

текущее значение a: a

(через две секунды) новое значение a: Новое значение для _a

Используйте его во флаттере с StreamBuilder

StreamBuilder<String>(
  stream: subject.aStream,
  initialData: subject.a,
  builder: (context, snapshot) {
    final valueOfA = snapshot.data;
    return Text("value is $valueOfA");
  }
)

Некоторые из шаблонов кода можно заменить на BehaviorSubject в RxDart . Но для этого потребуется импортировать в проект еще одну зависимость.

...