Инкапсуляция на основе свойств класса
Инкапсуляция на основе свойств класса
В отличие от традиционных методов чтения и модификации, языки .NET тяготеют к реализации принципа инкапсуляции на основе использования свойств, которые представляют доступные для внешнего пользователя элементы данных. Вместо того, чтобы вызывать два разных метода (get и set) для чтения и установки данных состояния объекта, пользователь получает возможность вызвать нечто, похожее на общедоступное поле. Предположим, что мы имеем свойство с именем ID (код), представляющее внутренний член-переменную empID типа Employee. Синтаксис вызова в данном случае должен выглядеть примерно так.
// Синтаксис установки/чтения значения ID работника.
static void Main(string[] args) {
Employee p = new Employee();
// Установка значения.
p.ID = 81;
// Чтение значения.
Console.WriteLine ("ID работника: {0} ", p.ID); Console.ReadLine();
}
Свойства типа "за кадром" всегда отображаются в "настоящие" методы чтения и модификации. Поэтому, как разработчик класса, вы имеете возможность реализовать любую внутреннюю логику, выполняемую перед присваиванием соответствующего значения (например, перевод символов в верхний регистр, очистку значения от недопустимых символов, проверку принадлежности числового значения диапазону допустимости и т.д.). Ниже демонстрируется синтаксис C#. использующий, кроме свойства ID, свойство Pay (оплата), которое инкапсулирует поле currPay, a также свойство Name (имя), которое инкапсулирует данные fullName.
// Инкапсуляция с помощью свойств.
public class Employee {
...
private int empID;
private float currPay;
private string fullName;
// Свойство для empID.
public int ID {
get {return empID;}
set {
// Вы можете проверить и, если требуется, модифицировать
// поступившее значение перед присваиванием.
empID = value;
}
}
// Свойство для fullName.
public string Name {
get { return fullName; }
set { fullName = value; }
}
// Свойство для currPay.
public float Pay {
get { return currPay; }
set { currPay = value; }
}
}
Свойство в C# компонуется из блока чтения и блока модификации (установки) значении. Ярлык value в C# представляет правую сторону оператора присваивания. Соответствующий ярлыку value тип данных зависит от того, какого сорта данные этот ярлык представляет. В данном примере свойство ID оперирует с типом данных int, который, как вы знаете, отображается в System.Int32.
// 81 принадлежит System.Int32,
// поэтому "значением" является System.Int32.
Employee e = new Employee();
e.ID = 81;
Чтобы это доказать, предположим, что вы добавили следующий программный код для установки свойства ID.
// Свойство для empID.
public int ID {
get {return empID;}
set {
Console.WriteLine("value является экземпляром {0} ", value.GetType());
Console.WriteLine("Значение value: {0} ", value); empID = value;
}
}
Выполнив приложение, вы должны увидеть вариант вывода, показанный на рис. 4.5.
Рис. 4.5. Значение value после установки для ID значения 81
Замечание. Строго говоря, ярлык value в C# является не ключевым оловом, а, скорее, контекстным ключевым словом, представляющим неявный параметр, который используется в операторе присваивания в контексте метода, используемого для установки значения свойства. Поэтому вполне допустимо иметь члены-переменные и локальные элементы данных с именем value.
Следует понимать, что свойства (в отличие от традиционных методов чтения и модификации) еще и упрощают работу с типами, поскольку свойства способны "реагировать" на внутренние операции в C#. Например, предположим, что тип класса Employee имеет внутренний приватный член, представляющий значение возраста работника. Вот соответствующая модификация класса.
public class Employee {
…
// Текущий возраст работника.
private int empAge;
public Employee(string fullName, int age, int empID, float currPay) {
…
this.empAge = age;
}
public int Age {
get { return empAge; }
set { empAge = value; }
}
public void DisplayStats() {
…
Console.WriteLine("Возраст: {0} ", empAge);
}
}
Теперь предположим, что вы создали объект Employee с именем joe. Вы хотите, чтобы в день рождения работника значение переменной возраста увеличивалось на единицу. Используя традиционные методы чтения и модификации, вы должны применить, например, следующий программный код.
Employee joe = new Employee();
joe.SetAge(joe.GetAge() + 1);
Но если инкапсулировать empAge, используя "правильный" синтаксис, вы сможете просто написать:
Employee joe = new Employee();
joe.Age++;