Проблема с открытыми данными заключается в том, что сами по себе они неспособны "понять", является ли присваиваемое значение допустимым с точки зрения текущих бизнес-правил системы. Как известно, верхний предел значений для типа int
// Хм... Ничего себе мини-новелла!
Book miniNovel = new Book();
miniNovel.numberOfPages = 30_000_000;
Хотя границы типа данных int
На заметку!
Говоря точнее, члены класса, которые представляют состояние объекта, не должны помечаться какpublic
. В то же время позже в главе вы увидите, что вполне нормально иметь открытые константы и открытые поля, допускающие только чтение.Инкапсуляция предлагает способ предохранения целостности данных состояния для объекта. Вместо определения открытых полей (которые могут легко привести к повреждению данных) необходимо выработать у себя привычку определять
• определение пары открытых методов доступа и изменения;
• определение открытого свойства.
Независимо от выбранного приема идея заключается в том, что хорошо инкапсулированный класс должен защищать свои данные и скрывать подробности своего функционирования от любопытных глаз из внешнего мира. Это часто называют
Инкапсуляция с использованием традиционных методов доступа и изменения
В оставшейся части главы будет построен довольно полный класс, моделирующий обычного сотрудника. Для начала создайте новый проект консольного приложения под названием EmployeeApp
Employee.cs
. Обновите класс Employee
с применением следующего пространства имен, полей, методов и конструкторов:using System;
namespace EmployeeApp
{
class Employee
{
// Поля данных.
private string _empName;
private int _empId;
private float _currPay;
// Конструкторы.
public Employee() {}
public Employee(string name, int id, float pay)
{
_empName = name;
_empId = id;
_currPay = pay;
}
// Методы.
public void GiveBonus(float amount) => _currPay += amount;
public void DisplayStats()
{
Console.WriteLine("Name: {0}", _empName); // имя сотрудника
Console.WriteLine("ID: {0}", _empId); // идентификационный
// номер сотрудника
Console.WriteLine("Pay: {0}", _currPay); // текущая выплата
}
}
}
Обратите внимание, что поля класса Employee
private
. Учитывая это, поля empName
, empID
и currPay
не будут доступными напрямую через объектную переменную. Таким образом, показанная ниже логика в коде приведет к ошибкам на этапе компиляции:Employee emp = new Employee();
// Ошибка! Невозможно напрямую обращаться к закрытым полям объекта!
emp._empName = "Marv";
Если нужно, чтобы внешний мир взаимодействовал с полным именем сотрудника, то традиционный подход предусматривает определение методов доступа (метод get
set
). Роль метода get
заключается в возвращении вызывающему коду текущего значения лежащих в основе данных состояния. Метод set
позволяет вызывающему коду изменять текущее значение лежащих в основе данных состояния при условии удовлетворения бизнес-правил.