👨‍💻
Flutter
  • 👨‍💻Flutter lessons
    • 🎨Flutter ui
      • 🚵‍♂️Travel app
        • 📱1. Lesson
        • 📱2.Lesson
      • 📚Books store
      • 🧑‍⚕️Doctor app
      • 🚖Taxi app
    • 🐦Основы Flutter
      • Page 1
      • Page 2
      • 🧑‍🏫Урок 1: Основные виджеты Flutter
        • Page
        • 🧩Container()
        • 🧩AppBar()
        • 🧩Text()
        • 🧩Icon()
        • 🧩Column()
        • 🧩Row()
        • 🧩TextButton()
        • 🧩ElevatedButton()
      • 🧑‍🏫Урок 2: Создаем UI
      • 🧑‍🏫Урок 3: Создаем UI
      • 🧑‍🏫Урок 4: Создаем UI
    • 🧩Основы dart
      • 🧑‍🏫01. Переменные часть 1
      • 🧑‍🏫01. Переменные часть 2
      • 🧑‍🏫02. Функции
      • 🧑‍🏫03. Условные операторы
      • 🧑‍🏫04. List
      • 🧑‍🏫05. Map
      • 🧑‍🏫06. Class
      • 🧑‍🏫07. Наследование
      • 🧑‍🏫08. Абстракция
      • 🧑‍🏫09. Интерфейсы
      • 🧑‍🏫10. Инкапсуляция
      • 🧑‍🏫11. Mixin
      • 🧑‍🏫12. Асинхронное программирование
      • 🧑‍🏫13. Streams
      • 🎯Final project
        • 🥦Grocery app
        • 🏠Home
    • ⚒️State management
      • ⬛Bloc
        • 1. Введение cubit
          • 1.1 Пример
          • 1.2 Пример
          • 1.3 Пример
          • 1.4 Пример
          • 1.5 Пример
        • 2. Введение в Bloc
      • 🌊Riverpod
    • 🏠Architechture
      • Clean Architechture
      • Bloc
    • 📲Locale storage
      • 🐝Hive
        • 🐝Ui
        • 🐝Hive - локальное хранилище: Введение
        • 🐝Hive - task app: часть 1
        • 🐝Hive - task app: часть 2
        • 🐝Hive - task app: часть 3
        • 🐝Hive - task app: часть 4
        • 🐝Hive - task app: часть 5
      • 🟩Sql
    • 📡Server
      • 📡Server - Lesson01 introduction
      • 📡Server - Lesson02 get data
      • 📡Server - Lesson03 News App get data
    • 🖥️Готовый backend
      • Firebase
      • Supabase
  • 🎯Dart practise
    • 🧑‍💻Переменные
      • 🧑‍💻String
      • 🧑‍💻int
      • 🧑‍💻double
      • 🧑‍💻bool
    • 🧑‍💻Функции
      • 🧑‍💻Обычные функции
      • 🧑‍💻Порядковые параметры
      • 🧑‍💻Обязательные параметры
      • 🧑‍💻Параметры по умолчанию
      • 🧑‍💻Функции-стрелки
      • 🧑‍💻Возвращаемые функции
    • 🧑‍💻Условные операторы
      • 🧑‍💻if/else
      • 🧑‍💻switch/case
      • 🧑‍💻тернарный оператор
    • 🧑‍💻Структура данных
      • 🧑‍💻List
      • 🧑‍💻Map
      • 🧑‍💻Set
    • 🧑‍💻ООП
  • 🧩Flutter Widgets
    • 💻Все виджеты
    • 🎞️Анимации
      • 🧩AnimatedContainer
      • 🧩AnimatedOpacity
      • 🧩AnimatedAlign
      • 🧩AnimatedCrossFade
      • 🧩Hero
      • 🧩AnimatedBuilder
      • 🧩AnimatedPositioned
      • 🧩AnimatedSwitcher
    • 🏗️Манипуляция пространством
      • 🧩Padding
      • 🧩SizedBox
      • 🧩Align
      • 🧩Center
      • 🧩Expanded
      • 🧩Flexible
      • 🧩Spacer
      • 🧩Column
      • 🧩Stack
      • 🧩Row
    • ✍️Отображение текста
      • 🧩RichText
      • 🧩FittedBox
      • 🧩SelectableText
      • 🧩Text
    • 📸Отображение изображений
      • 🧩Image()
      • 🧩Image.network
      • 🧩Image.asset
      • 🧩Image.file
      • 🧩Image.memory
      • 🧩FadeInImage
      • 🧩NetworkImage
      • 🧩AssetImage
    • 📃Списки и прокрутка
      • 🧩ListView()
      • 🧩ListView.builder()
      • 🧩GridView()
      • 🧩GridView.builder()
      • 🧩PageView()
      • 🧩SingleChildScrollView
      • 🧩CustomScrollView
      • 🧩ReorderableListView
      • 🧩NestedScrollView
    • ⌨️Кнопки
      • 🧩TextButton()
      • 🧩ElevatedButton()
      • 🧩IconButton()
      • 🧩DropDownButton()
      • 🧩FloatingActionButton
      • 🧩Checkbox
      • 🧩Radio
      • 🧩Switch
      • 🧩Slider
    • 📝Формы и ввод данных
      • 🧩TextField()
      • 🧩TextFormField
      • 🧩Form
      • 🧩FormField
      • 🧩DatePicker
      • 🧩TimePicker
    • 🧑‍🏫Диалоги и всплывающие окна
      • 🧩AlertDialog
      • 🧩SimpleDialog
      • 🧩BottomSheet
      • 🧩ExpansionPanel
      • 🧩SnackBar
      • 🧩PopupMenuButton
      • 🧩Tooltip
      • 🧩Dialog
    • 🛣️Навигация
      • 🧩BottomNavigationBar()
      • 🧩Navigator
      • 🧩Drawer
      • 🧩TabBar
    • 📱Отображение на экране
      • 🧩Scaffold
      • 🧩Container()
      • 🧩AppBar()
      • 🧩Icon()
      • 🧩Stepper()
  • 🎮Flutter Flame
    • Введение в разработку игр
  • 🔬Flutter projects
  • 🧑‍🎓Homeworks for everyday
    • 🧑‍🎓0. Переменные
    • 🧑‍🎓1. Функции - 1
    • 🧑‍🎓2. Функции - 2
    • 🧑‍🎓3. Условные операторы
    • 🧑‍🎓4. List
    • 🧑‍🎓5. Map
    • 🧑‍🎓6. class
    • 🐝Hive -
    • 🐝Hive clean architecture
    • 📡HTTP
    • 📡HTTP clean architecture
    • 💾Firebase
    • 💾Firebase clean architecture
Powered by GitBook
On this page
  1. Flutter lessons
  2. Основы dart

10. Инкапсуляция

Инкапсуляция — это принцип, который позволяет скрывать детали внутренней работы объектов и предоставлять только необходимый функционал другим частям программы. Это как коробка с кнопками на поверхности, где внешнему миру доступны лишь кнопки, но внутренние детали и механизмы коробки скрыты.

Зачем нужна инкапсуляция?

  1. Защищает данные: предотвращает случайные или неправильные изменения данных извне.

  2. Упрощает использование: делает объекты проще и понятнее для других частей программы.

  3. Сохраняет стабильность кода: позволяет менять внутреннюю реализацию без изменения внешнего интерфейса, что уменьшает риск поломок.

Как создавать инкапсуляцию в Dart

  1. Использование приватных переменных и методов — в Dart переменные и методы становятся приватными, если их имя начинается с _ (например, _balance).

  2. Методы для доступа к данным (геттеры и сеттеры): создаем публичные методы, чтобы безопасно читать и изменять приватные переменные.

Примеры с аналогиями

  1. Банковский счёт

    • Мы можем создать класс BankAccount, где баланс (_balance) скрыт от внешнего мира.

    • Для доступа есть методы deposit() и withdraw(), через которые можно добавлять или снимать деньги, проверяя корректность данных (например, не позволять снять больше, чем на счёте).

    class BankAccount {
      double _balance = 0; // приватная переменная
    
      void deposit(double amount) {
        if (amount > 0) {
          _balance += amount;
        }
      }
    
      void withdraw(double amount) {
        if (amount > 0 && amount <= _balance) {
          _balance -= amount;
        }
      }
    
      double get balance => _balance; // геттер для доступа к балансу
    }

    Аналогия: Представьте, что это сейф с дверью. Мы не видим, что находится внутри, но можем положить или забрать что-то, используя комбинацию.

  2. Телефон

    • В классе Phone можно скрыть сложные внутренние процессы, такие как проверка заряда батареи и соединение с сетью.

    • При этом мы оставляем доступ к публичным методам makeCall() или sendMessage(), которые работают независимо от внутреннего устройства телефона.

    class Phone {
      bool _isCharged = true; // приватная переменная
      
      void makeCall(String number) {
        if (_isCharged) {
          print('Звоним на $number');
        } else {
          print('Батарея разряжена');
        }
      }
    }
  3. Машина

    • В классе Car скрываем двигатель и топливную систему, которые не видны пользователю.

    • Публичный метод drive() позволяет пользователю ехать, но не требует знания о том, как работают двигатель или трансмиссия.

    class Car {
      bool _engineRunning = false; // приватное состояние двигателя
      
      void startEngine() {
        _engineRunning = true;
      }
    
      void drive() {
        if (_engineRunning) {
          print('Машина едет');
        } else {
          print('Сначала запустите двигатель');
        }
      }
    }

    Аналогия: Это как педали и руль, которые управляют машиной, не раскрывая детали того, как работает двигатель.

  4. Робот-пылесос

    • В классе RobotVacuum можно скрыть логику передвижения и сенсоры, чтобы пользователь мог просто использовать метод startCleaning().

    class RobotVacuum {
      bool _isBatteryCharged = true;
      
      void startCleaning() {
        if (_isBatteryCharged) {
          print('Начинаю уборку');
        } else {
          print('Нужно зарядить батарею');
        }
      }
    }

    Аналогия: Представьте, что робот-пылесос просто "убирается", и мы не видим, как он определяет, где грязь, а где чисто.

  5. Электронная книга

    • В классе EBookReader скрыты сложные процессы обработки и отображения текста.

    • У пользователя есть публичные методы openBook() и turnPage(), чтобы читать книгу без вмешательства в детали работы программы.

    class EBookReader {
      String _bookContent = "Содержание книги...";
    
      void openBook() {
        print("Книга открыта");
      }
    
      void turnPage() {
        print("Переворачиваем страницу");
      }
    }

    Аналогия: Электронная книга позволяет читать текст, не раскрывая, как устройство обрабатывает и отображает данные.

Резюме

Инкапсуляция помогает:

  • Скрывать внутренние данные и процессы, предоставляя только нужные методы.

  • Защищать данные и создавать единый интерфейс, которым легко пользоваться.

Инкапсуляция делает код более надежным и удобным для работы с ним в больших проектах, особенно при поддержке и изменениях.

Пример:

Создадим мини-приложение для управления профилем пользователя. В этом приложении будет инкапсулирована информация о пользователе, такая как имя, возраст и email. Мы будем использовать инкапсуляцию, чтобы скрыть эти данные от прямого доступа и предоставить методы для их безопасного изменения и получения.

Почему использовать инкапсуляцию?

Инкапсуляция позволяет:

  1. Защищать данные: Мы можем контролировать, как данные изменяются, например, проверять, чтобы возраст был положительным, а email соответствовал определённому формату.

  2. Упрощать использование: Публичные методы делают взаимодействие с данными понятным и безопасным, не позволяя другим частям программы неправильно изменять внутреннее состояние объекта.

  3. Сохранять целостность данных: Мы можем изменять внутреннюю реализацию без необходимости обновлять код, который использует эти объекты.

Структура приложения

  1. Класс UserProfile — инкапсулирует данные о пользователе.

  2. Публичные методы — позволяют безопасно изменять и получать данные.

  3. Экран профиля — демонстрирует использование класса UserProfile и взаимодействие с ним.

Код приложения

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: ProfileScreen(),
    );
  }
}

// Класс UserProfile, который инкапсулирует данные о пользователе
class UserProfile {
  String _name; // Приватное поле для имени
  int _age; // Приватное поле для возраста
  String _email; // Приватное поле для email

  UserProfile(this._name, this._age, this._email);

  // Геттеры
  String get name => _name;
  int get age => _age;
  String get email => _email;

  // Сеттеры
  void setName(String name) {
    _name = name;
  }

  void setAge(int age) {
    if (age > 0) { // Проверка на положительный возраст
      _age = age;
    } else {
      print("Возраст должен быть положительным");
    }
  }

  void setEmail(String email) {
    if (RegExp(r"^[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[a-zA-Z]+").hasMatch(email)) {
      _email = email;
    } else {
      print("Неверный формат email");
    }
  }
}

// Экран профиля пользователя
class ProfileScreen extends StatefulWidget {
  @override
  _ProfileScreenState createState() => _ProfileScreenState();
}

class _ProfileScreenState extends State<ProfileScreen> {
  UserProfile _userProfile = UserProfile("Иван", 30, "ivan@example.com");

  final TextEditingController _nameController = TextEditingController();
  final TextEditingController _ageController = TextEditingController();
  final TextEditingController _emailController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Профиль пользователя")),
      body: Padding(
        padding: EdgeInsets.all(16.0),
        child: Column(
          children: [
            Text("Имя: ${_userProfile.name}"),
            Text("Возраст: ${_userProfile.age}"),
            Text("Email: ${_userProfile.email}"),
            SizedBox(height: 20),
            TextField(
              controller: _nameController,
              decoration: InputDecoration(labelText: "Введите новое имя"),
            ),
            TextField(
              controller: _ageController,
              decoration: InputDecoration(labelText: "Введите новый возраст"),
              keyboardType: TextInputType.number,
            ),
            TextField(
              controller: _emailController,
              decoration: InputDecoration(labelText: "Введите новый email"),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                _userProfile.setName(_nameController.text);
                _userProfile.setAge(int.tryParse(_ageController.text) ?? 0);
                _userProfile.setEmail(_emailController.text);
                setState(() {}); // Обновляем состояние, чтобы показать изменения
              },
              child: Text("Обновить профиль"),
            ),
          ],
        ),
      ),
    );
  }
}

Объяснение кода

  1. Класс UserProfile:

    • Инкапсуляция данных: Приватные переменные _name, _age и _email скрывают внутренние данные пользователя. Это предотвращает случайное или неправильное изменение этих данных.

    • Геттеры и сеттеры: Публичные методы get name, get age и get email позволяют безопасно получать данные. Методы setName, setAge и setEmail предоставляют контролируемый доступ для изменения этих данных с проверкой правильности (например, положительный возраст и корректный email).

  2. Экран профиля (ProfileScreen):

    • Создаёт экземпляр UserProfile и предоставляет текстовые поля для ввода нового имени, возраста и email.

    • Кнопка "Обновить профиль" вызывает сеттеры, чтобы обновить данные пользователя. Если введенные данные некорректны, это обрабатывается в сеттерах, а пользователю не нужно беспокоиться о деталях проверки.

Аналогия

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

Заключение

Инкапсуляция позволяет защитить данные и контролировать их изменение, что делает код более безопасным и понятным. Мы можем менять внутренние детали класса, не нарушая взаимодействия с ним, что удобно для поддержки и расширения приложения в будущем.

Previous09. ИнтерфейсыNext11. Mixin

Last updated 6 months ago

👨‍💻
🧩
🧑‍🏫