Свойства для инкапсуляции
Часть раздела Объектно-ориентированное программирование путешествия по C# на Coddy — урок 32 из 70.
Свойства — это основной инструмент для реализации инкапсуляции в C#. Вместо того чтобы открывать поля напрямую, вы оборачиваете их свойствами, которые управляют тем, как данные запрашиваются и изменяются.
Этот паттерн сочетает в себе закрытое поле с открытым свойством, которое включает валидацию или логику в своих аксессорах:
public class Temperature
{
private double celsius;
public double Celsius
{
get { return celsius; }
set
{
if (value < -273.15)
celsius = -273.15; // Минимум абсолютного нуля
else
celsius = value;
}
}
}Теперь внешний код не может установить невозможную температуру. Свойство выступает в роли привратника, гарантируя, что ваш объект всегда остается в валидном состоянии. Это инкапсуляция в действии — внутренние данные защищены, но при этом остаются доступными через контролируемый интерфейс.
Вы также можете использовать свойства для вычисления значений или вызова побочных эффектов:
public double Fahrenheit
{
get { return celsius * 9 / 5 + 32; }
set { celsius = (value - 32) * 5 / 9; }
}Внешний мир видит два свойства, но внутри существует только одно поле. Свойства позволяют изменять детали реализации, не нарушая работу кода, использующего ваш класс, — это ключевое преимущество правильной инкапсуляции.
Задание
ЛегкоДавайте создадим систему инвентаризации товаров, которая использует свойства для защиты целостности данных. Вы создадите класс, в котором цены никогда не могут быть отрицательными, а количество всегда остается в допустимых пределах — это продемонстрирует, как свойства действуют в качестве «стражей» для ваших данных.
Вы организуете свой код в двух файлах:
Product.cs: Создайте классProductв пространстве именInventory, который управляет информацией о товаре с валидацией через свойства. Вашему товару необходимы:- Закрытое поле
price(decimal) с открытым свойствомPrice, которое гарантирует, что цена никогда не опустится ниже0— если кто-то попытается установить отрицательную цену, она должна быть сохранена как0. - Закрытое поле
quantity(int) с открытым свойствомQuantity, которое удерживает значения в диапазоне от0до1000— значения ниже 0 становятся 0, значения выше 1000 становятся 1000. - Открытое автоматически реализуемое свойство
Name(string). - Вычисляемое свойство только для чтения
TotalValue, которое возвращаетPrice * Quantity.
- Закрытое поле
Program.cs: В основном файле создайте объектProduct, используя входные значения. Затем попытайтесь изменить цену и количество, используя дополнительные входные значения, которые могут быть некорректными. Выведите состояние товара после создания и после каждой модификации, чтобы увидеть, как свойства защищают данные.
Вы получите пять входных значений:
- Название товара
- Начальная цена (decimal)
- Начальное количество (integer)
- Новая цена для установки (decimal, может быть отрицательной)
- Новое количество для установки (integer, может быть вне диапазона)
Выведите результат в следующем формате:
After creation:
{Name}: Price={Price}, Qty={Quantity}, Total={TotalValue}
After modifications:
{Name}: Price={Price}, Qty={Quantity}, Total={TotalValue}Например, если входные данные: Laptop, 999.99, 50, -100 и 1500, вывод должен быть таким:
After creation:
Laptop: Price=999.99, Qty=50, Total=49999.50
After modifications:
Laptop: Price=0, Qty=1000, Total=0Обратите внимание, как отрицательная цена стала 0, а количество 1500 было ограничено до 1000. Ваши свойства защищают объект от недопустимых состояний — это и есть инкапсуляция в действии!
Шпаргалка
Свойства оборачивают закрытые поля с контролируемым доступом через аксессоры get и set, обеспечивая валидацию и инкапсуляцию:
public class Temperature
{
private double celsius;
public double Celsius
{
get { return celsius; }
set
{
if (value < -273.15)
celsius = -273.15;
else
celsius = value;
}
}
}Свойства могут вычислять значения на основе внутренних полей:
public double Fahrenheit
{
get { return celsius * 9 / 5 + 32; }
set { celsius = (value - 32) * 5 / 9; }
}Свойства только для чтения опускают аксессор set, позволяя только получение вычисленных или сохраненных значений.
Попробуйте сами
using System;
using Inventory;
class Program
{
public static void Main(string[] args)
{
// Чтение входных данных
string name = Console.ReadLine();
decimal initialPrice = Convert.ToDecimal(Console.ReadLine());
int initialQuantity = Convert.ToInt32(Console.ReadLine());
decimal newPrice = Convert.ToDecimal(Console.ReadLine());
int newQuantity = Convert.ToInt32(Console.ReadLine());
// TODO: Создайте Product, используя начальные значения
// TODO: Выведите состояние продукта после создания
Console.WriteLine("After creation:");
// Формат вывода: {Name}: Price={Price}, Qty={Quantity}, Total={TotalValue}
// TODO: Измените цену и количество, используя новые значения
// TODO: Выведите состояние продукта после изменений
Console.WriteLine("After modifications:");
// Формат вывода: {Name}: Price={Price}, Qty={Quantity}, Total={TotalValue}
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыПространства имен и директивыВведение в классы и объектыКлючевое слово 'this'Методы и параметрыПоля и свойстваКонструкторыИнициализаторы объектовИтоги — Простой калькулятор4Наследование
Основы синтаксиса наследования (:)Ключевое слово 'base'Ключевые слова Virtual и OverrideЗапечатанные классыБазовый класс 'object'Итоги — Иерархия сотрудников7Продвинутые возможности
Перегрузка операторовИндексаторы (this[])Переопределение ToString()Методы расширенияПовторение — Пользовательский список10Паттерны проектирования. Часть 1
Введение в паттерны проектированияПотокобезопасный SingletonПаттерн FactoryПаттерн Observer (События)Паттерн Strategy13Финальные испытания
Платформа для онлайн-обученияКомпонент игрового персонажаСервис аренды транспорта2Свойства и статические члены
Автоматически реализуемые свойстваСвойства только для чтения и записиСтатические поля и методыСтатические классыЧлены в виде выражений5Полиморфизм и интерфейсы
Полиморфизм: компиляция vs выполнениеИнтерфейс vs абстрактный классМножественные интерфейсыЯвные интерфейсыUpcasting и DowncastingИтоги: Калькулятор фигур8Продвинутые концепции ООП
Композиция вместо наследованияGenerics (классы и методы)Делегаты и событияАтрибуты и рефлексияIDisposable и оператор usingОсновы Dependency Injection11Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн Компоновщик3Архитектура классов
Экземплярные и статические данныеКлючевые слова 'readonly' и 'const'Опорные поляПовторение — Менеджер банковских счетов6Инкапсуляция
Модификаторы доступаСвойства для инкапсуляцииРеализация скрытия данныхПаттерны неизменяемостиИтоги — Записи студентов9Переменное количество аргументов
Ключевое слово 'params'Необязательные параметрыИменованные аргументыПерегрузка методов