По умолчанию поля класса являются публичными. А это значит, что они доступны в любой точке программы. И мы можем свободно получить или изменить значения этих полей. Однако подобное поведение не всегда может быть желательным. Нередко бывает необходимо скрыть внутреннюю реализацию от внешнего кода, что позволит избежать некорректного использования полей, передачи им некорректных значений.
Dart позволяет сделать поля класса приватными - к таким полям можно обратиться только внутри класса. Вне класса обратиться к приватным полям нельзя. Чтобы сделать поля приватными, необходимо добавить перед их именем символ подчеркивания (_). Однако тут есть нюансы. Например, пусть весь код программы размещен в одном файле main.dart, и в этом коде определен класс Person:
class Person{ String _name =""; // приватное поле name int _age =0; // приватное поле age Person(String name, int age) { this._name = name; this._age = age; } void display(){ print("Name: $_name \tAge: $_age"); } } void main() { Person tom = Person("Tom", 38); tom.display(); // Name: Tom Age: 38 tom._age = 100500; tom._name = "toidi"; tom.display(); // Name: toidi Age: 100500 }
Здесь в классе Person поля name и age, которые представляют соответственно имя и возраст, определены как приватные:
String _name =""; // приватное поле name int _age =0; // приватное поле age
Однако в функции main мы по прежнему можем обратиться к этим полям и изменить их значения:
tom._age = 100500; tom._name = "toidi";
И консольный вывод покажет, что значения полей действителено изменились:
Name: Tom Age: 38 Name: toidi Age: 100500
В чем же тогда приватность? И тут надо учитывать, что приватность применяется, если класс определен в отдельной библиотеке/файле. Поэтому определим в одной папке с главным файлом новый файл person.dart:
class Person{ String _name =""; // приватное поле name int _age =0; // приватное поле age Person(String name, int age) { this._name = name; this._age = age; } void display() => print("Name: $_name \tAge: $_age"); }
Здесь определен тот же класс Person. А в главном файле main.dart подключим этот файл и используем класс Person:
import 'person.dart'; // подключаем файл с классом Person void main() { Person tom = Person("Tom", 38); tom.display(); // Name: Tom Age: 38 // tom._age = 100500; // Ошибка // tom._name = "toidi"; // Ошибка }
С помощью директивы import подключаем файл "person.dart" и в функции main создаем объект Person. Но теперь мы уже не сможем обратиться к полям name и age (поэтому в примере выше соответствующие строки закомментированы). А если мы и попробуем это сделать, то столкнемся с ошибкой.
Стоит отметить, что то же самое обстоятельно касается определения приватных методов - если их имя начинается с подчеркивания, то они тоже являются приватными, и их нельзя вызвать вне класса:
class Person{ String _name =""; // приватное поле name int _age =0; // приватное поле age Person(String name, int age) { this._name = name; this._age = age; } void _printPerson() => print("Name: $_name \tAge: $_age"); void display() =>_printPerson(); }
В данном случае метод _printPerson является приватным, и вне текущего файла к нему обратиться нельзя.
Также могут быть приватными именованные конструкторы. Например:
class Person{ String _name; // приватное поле name int _age; // приватное поле age Person(String name, int age): this._create(name, age); // вызываем приватный конструктор Person._create(this._name, this._age); // приватный конструктор void display() => print("Name: $_name \tAge: $_age"); }
Здесь конструктор Person._create()
определен как приватный - для этого перед именем конструктора также ставится символ подчеркивания. Этот консструктор устанавливает
значения приватных переменных:
Person._create(this._name, this._age);
Внутри класса мы можем вызвать этот конструктор
Person(String name, int age): this._create(name, age);
Вне файла данного класса приватный конструктор не доступен.