Menu
Coddy logo textTech

Свойства для инкапсуляции

Часть раздела Объектно-ориентированное программирование путешествия по 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; }
}

Внешний мир видит два свойства, но внутри существует только одно поле. Свойства позволяют изменять детали реализации, не нарушая работу кода, использующего ваш класс, — это ключевое преимущество правильной инкапсуляции.

challenge icon

Задание

Легко

Давайте создадим систему инвентаризации товаров, которая использует свойства для защиты целостности данных. Вы создадите класс, в котором цены никогда не могут быть отрицательными, а количество всегда остается в допустимых пределах — это продемонстрирует, как свойства действуют в качестве «стражей» для ваших данных.

Вы организуете свой код в двух файлах:

  • 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}
    }
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование