Инкапсуляция в языке Dart

Определение из википедии:

Инкапсуляция (англ. encapsulation, от лат. in capsula) — в информатике, процесс разделения элементов абстракций, определяющих её структуру (данные) и поведение (методы); инкапсуляция предназначена для изоляции контрактных обязательств абстракции (протокол/интерфейс) от их реализации. На практике это означает, что класс должен состоять из двух частей: интерфейса и реализации. В реализации большинства языков программирования (C++,  C#,  Java и другие) обеспечивается механизм сокрытия, позволяющий разграничивать доступ к различным частям компонента.

В языке Dart есть возможность создать класс, который опишет данные (свойства) и поведение (методы), а так же для ограничения доступа существуют модификаторы доступа.

Для понимания выше сказанного давайте перейдём к примеру:

Мы создадим класс PersonCard c конструктором, который будет описывать карточку человека для какой нибудь картотеки. В классе будет 3 поля: имя (name) , возраст (age) и дата создания (createAt) карточки. Так же в классе будет 2 метода: toString — понадобится нам для удобства отображения полей (свойств) класса и метод addDateCreate — будет добавлять к карточке дату её создания (или автоматом текущую дату или с помощью переданной даты).

class PersonCard {
  String _createAt = DateFormat('yyyy-MM-dd').format(DateTime.now());
  final String name;
  final int age;

  PersonCard({
    required this.name,
    required this.age,
  });

  @override
  String toString() {
    return "$name, $age, $_createAt";
  }

  String addDateCreate() {
    return '$name, возраст $age, дата создания карточки $_createAt';
  }
}

Обратите внимание для поля createAt мы установили приватность (т.е. отсутствие доступа из вне) с помощью нижнего подчёркивания »_» перед названием поля. А так же сразу присвоили значение — это сегодняшняя (текущая) дата. Ограничили доступ мы специально, так как не хотим чтоб дату создания карточки можно было изменить каким то образом. То есть спрятали или другими словами инкапсулировали.

Теперь давайте в методе main создадим экземпляр нашего класса (инстанс) и с помощью нашего метода toString, который мы унаследовали от базового класса Object и переопределили (override) в нашем классе PersonCard, выведем хранящиеся значения в полях.

void main() {
  final PersonCard artem = PersonCard(name: 'Артём', age: 18);

  print(artem);
}

Смотрим вывод в консоль

Видим, что хранятся в классе наши данные которые мы создали через конструктор и в поле createAt хранится текущая дата.

Видим, что хранятся в классе наши данные которые мы создали через конструктор и в поле createAt хранится текущая дата.

Примечание! Если мы не переопределим метод toString то мы не сможем вывести в консоль значения в читаемом виде. В консоли мы просто увидем такую вот запись, которая мало что нам скажет!

d36f126adc168e833856f346e688fd52.png

А как же нам посмотреть, что находится в поле _createAt (не используя toString)? Как нам его вывести в консоль ведь оно приватное и доступа у нас к нему нет. Проверяем приватность:

Видим что у на есть доступ только к полям age и name, а до поля createAt мы достучаться не можем!

Видим что у на есть доступ только к полям age и name, а до поля createAt мы достучаться не можем!

На помощь нам спешат геттеры и сеттеры!

С помощью геттера мы можем прочитать содержимое поле createAt, давайте реализуем его.

String get createAt => _createAt;

Геттер этот тот же метод, у которого такое же имя и он просто возвращает нам то что в приватном поле.

Теперь наш класс PersonCard выглядит так.

class PersonCard {
  String _createAt = DateFormat('yyyy-MM-dd').format(DateTime.now());
  final String name;
  final int age;

  PersonCard({
    required this.name,
    required this.age,
  });

  String get createAt => _createAt;

  @override
  String toString() {
    return "$name, $age, $_createAt";
  }

  String addDateCreate() {
    return '$name, возраст $age, дата создания карточки $_createAt';
  }
}

Давайте теперь попробуем достучаться до него из main. Обратившись к свойству класса через точку мы видим, что теперь мы можем прочитать его содржимое

2040fc856ce9b835a99fb4116b2ba7a3.png

void main() {
  final PersonCard artem = PersonCard(name: 'Артём', age: 18);

  print(artem.createAt);
}

Вывод в консоли

Мы видим что мы с помощью геттера смогли достучаться до поля createAt

Мы видим что мы с помощью геттера смогли достучаться до поля createAt

А теперь давайте проверим можем ли мы записать другое значение в приватное поле _createAte, раз уж мы смогли до него достучаться, пробуем…

Видим что такой возможности у нас нет!

Видим что такой возможности у нас нет!

Но как же нам всё таки присвоить полю _createAt новое значение?

На помощь нам спешит сеттер! Давайте реализуем его!

set createAt(String value) {
    _createAt = DateFormat('yyyy-MM-dd').format(DateTime.parse(value));
  }

В сетторе мы принимаем value и приводим его в нужный формат даты и приравниваем его к приватному полю _createAt

Наш класс теперь полностью (включая сеттер и геттер) выглядит так:

class PersonCard {
  String _createAt = DateFormat('yyyy-MM-dd').format(DateTime.now());
  final String name;
  final int age;

  PersonCard({
    required this.name,
    required this.age,
  });

  String get createAt => _createAt;

  set createAt(String value) {
    _createAt = DateFormat('yyyy-MM-dd').format(DateTime.parse(value));
  }

  @override
  String toString() {
    return "$name, $age, $_createAt";
  }

  String addDateCreate() {
    return '$name, возраст $age, дата создания карточки $_createAt';
  }
}

Теперь мы можем записать в поле _createAte новое значение, давайте проверять.

void main() {
  final PersonCard artem = PersonCard(name: 'Артём', age: 18);
  artem.createAt = '2022-03-07';

  print(artem.createAt);

  print(artem.addDateCreate());

}

Ошибка связанная с невозможностью записать новые данные исчезла. Теперь мы можем распечатать поле и вызвать метод addDateCreate в принте, чтобы убедиться что и там применились новые данные в поле _createAt

ea4854942579e8ad49248b42cb5814ec.png

В итоге: Мы убедились, что язык Dart поддерживает принцип ООП — Инкапсуляция.

© Habrahabr.ru