Приватные поля позволяют скрыть от внешнего кода состояние объекта. Однако нередко бывает необходимо иметь доступ к этим полям. Геттеры и сеттеры позволяют объединить приватность полей и возможность доступа к ним из внешнего кода, обеспечить контроллируемый доступ к приватным полям.
Например, возьмем следующий класс Person
class Person{ String _name; // приватное поле name int _age; // приватное поле age Person(this._name, this._age); }
Здесь приватность позволяет избежать установки полям _name и _age некорректных значений, например, пустой строки для имени или отрицательного возраста. Однако было бы неплохо, если бы могли установить корректные значения либо просто получить значения. И геттеры и сеттеры могут в этом помочь.
Геттеры (getters) предназначены для возвращения значения. Геттер представляет специальный метод, который использует ключевое слово get перед названием свойства и возвращает некоторое значение:
class Person{ String _name; // приватное поле name int _age; // приватное поле age String get name {return _name;} int get age {return _age;} Person(this._name, this._age); }
Здесь определено два геттера:
String get name {return _name;} int get age {return _age;}
Геттер начинается с возвращаемого типа, после которого следует ключевое слово get и имя свойства. А после имени свойства идет блок кода, где собственно возвращается значение. Причем никаких параметров подобный метод не принимает. В данном случае имя свойства соответствует имени поля (за исключением начального подчеркивания), значение которого возвращается, но это необязательно.
То есть у нас здесь два геттера: свойство name возвращает значение поля _name, а свойство age возвращает значение поля _age.
Далее в функции main мы можем обратиться к этим свойствам:
import 'person.dart'; // подключаем класс Person void main() { Person tom = Person("Tom", 38); print(tom.name); // Tom print(tom.age); // 38 }
Причем через геттер можно только получить значение, а установить нельзя.
Стоит отметить, что если геттер имеет одну строку кода, то, как и любой другой метод, его можно сократить:
String get name =>_name; int get age => _age;
Сеттеры позволяют установить значение поля. Сеттер представляет специальный метод, который начинается с ключевого слова set, за которым следует название свойства. Затем идет один параметр, который представляет устанавливаемое значение:
set имя_свойство(параметр) { тело сеттера}
Например, определим в классе Person сеттер для установки поля _age:
class Person{ String _name; // приватное поле name int _age; // приватное поле age String get name =>_name; int get age => _age; // сеттер set age(int value){ if(value > 0 && value < 111){ // если age в диапазоне от 1 до 110 _age = value; } } Person(this._name, this._age); }
Сеттер представляет свойство age. Поскольку нам надо установить значение значение поля _age, то параметр сеттера представляет тип int:
set age(int value){ if(value > 0 && value < 111){ _age = value; } }
В сеттере проверяем устанавливаемое значение. Если оно представляет действительный разумный возраст - от 1 до 110, то изменяем значение поля _age. Если же переданное значение некорректно, то оно никак не сказывается на поле _age. Таким образом, мы можем предоставить контролируемый доступ извне к полю _age.
Теперь мы сможем изменить значение свойства age (фактически поля _age):
import 'person.dart'; // подключаем класс Person void main() { Person tom = Person("Tom", 38); tom.age = 22; // вызываем сеттер print(tom.age); // 22 tom.age = 100500; // вызываем сеттер print(tom.age); // 22 }
При передаче свойству age значения, срабатывает сеттер. И если это значение корректное, то сеттер изменяет поле _age:
tom.age = 22; // вызываем сеттер print(tom.age); // 22
Если передается некорректное значение, то ничего не изменяется:
tom.age = 100500; // вызываем сеттер print(tom.age); // 22
свойства могут быть вычисляемыми - они не представляют значения какого-то конкретного поля, а динамически вычисляются. Например:
class Person{ String _name; // приватное поле name int _age; // приватное поле age String get name =>_name; int get age => _age; // вычисляемое свойства bool get isChild => _age < 18; Person(this._name, this._age); }
Здесь в класс Person добавлено вычисляемое свойство isChild
, которое возвращает true, если текущий объект Person условно является ребенком - если ему меньше 18 лет.
bool get isChild => _age < 18;
Далее это свойство можно использовать как и другие свойства-геттеры:
import 'person.dart'; // подключаем класс Person void main() { Person tom = Person("Tom", 38); bool tomIsChild = tom.isChild; // вызываем вычисляемое свойство isChild print("Tom is child? $tomIsChild"); // Tom is child? false Person sam = Person("Sam", 16); bool samIsChild = sam.isChild; print("Sam is child? $samIsChild"); // Sam is child? true }