🧑🏫07. Наследование
Наследование в программировании — это способ, с помощью которого один класс может "унаследовать" свойства и методы другого класса. Представь себе это как передачу знаний и навыков от одного человека к другому, например, от учителя к ученику или от родителя к ребенку. Благодаря наследованию, можно не дублировать код, а использовать уже готовый, добавляя или изменяя нужные части.
Зачем нужно наследование?
Экономия времени и ресурсов: Можно создать один базовый класс с общими характеристиками и использовать его для других классов.
Упрощение кода: Если несколько классов имеют похожие свойства и методы, их можно унаследовать от одного общего класса, чтобы избежать дублирования кода.
Логическая организация: Наследование помогает структурировать код так, чтобы общие черты группировались в одном месте, а уникальные — добавлялись там, где это нужно.
Пример из жизни
Представь, что у нас есть класс "Транспортное средство". Все транспортные средства имеют общие характеристики: у них есть колеса, скорость, способность перемещаться. Однако есть разные виды транспортных средств: автомобили, велосипеды, поезда и т.д. Вместо того чтобы для каждого из них снова прописывать колеса и скорость, мы создаем класс "Транспортное средство" и наследуем его для создания специфичных классов, таких как "Автомобиль" и "Велосипед".
Как создать наследование?
В Dart (языке, используемом в Flutter) для создания наследования используется ключевое слово extends
. Давай сначала создадим базовый класс Transport
(Транспортное средство), а потом унаследуем его для создания других классов.
// Базовый класс Transport
class Transport {
int wheels;
int speed;
Transport(this.wheels, this.speed);
void move() {
print('Транспортное средство движется со скоростью $speed км/ч');
}
}
Теперь у нас есть базовый класс Transport
. Он описывает общее транспортное средство с колесами и скоростью, а также метод move()
.
Пример 1: Автомобиль
Унаследуем Transport
для создания класса Car
(Автомобиль).
class Car extends Transport {
String brand;
Car(this.brand, int wheels, int speed) : super(wheels, speed);
void honk() {
print('Автомобиль $brand сигналит');
}
}
Здесь:
Класс
Car
наследуетTransport
, поэтому он получаетwheels
,speed
, и методmove()
.Мы добавили свойство
brand
и методhonk()
, уникальные для автомобиля.
Пример 2: Велосипед
Теперь создадим класс Bicycle
(Велосипед).
class Bicycle extends Transport {
bool hasBasket;
Bicycle(this.hasBasket, int wheels, int speed) : super(wheels, speed);
void ringBell() {
print('Велосипед звонит');
}
}
Класс Bicycle
также наследует Transport
, получает все его свойства и методы и добавляет свои, такие как hasBasket
и метод ringBell()
.
Пример 3: Самолет
Создадим класс Airplane
(Самолет).
class Airplane extends Transport {
int wings;
Airplane(this.wings, int speed) : super(0, speed); // Самолет не имеет колес, поэтому указываем 0
void fly() {
print('Самолет летит со скоростью $speed км/ч');
}
}
Здесь:
Самолет наследует
Transport
, но устанавливает количество колес равным нулю.Добавляет уникальное свойство
wings
и методfly()
.
Пример 4: Поезд
Создадим класс Train
(Поезд).
class Train extends Transport {
int carriages;
Train(this.carriages, int speed) : super(0, speed); // У поезда могут быть колеса, но в данном примере установим 0
void chooChoo() {
print('Поезд сигналит: Чух-чух');
}
}
Поезд наследует Transport
, но добавляет уникальное свойство carriages
и метод chooChoo()
.
Пример 5: Корабль
Создадим класс Ship
(Корабль).
class Ship extends Transport {
int sails;
Ship(this.sails, int speed) : super(0, speed); // Корабль не имеет колес
void sail() {
print('Корабль плывет');
}
}
Корабль также наследует Transport
, но добавляет свое уникальное свойство sails
и метод sail()
.
Полный пример
Теперь мы можем создать объекты разных классов и вызывать их методы:
void main() {
Car myCar = Car('Toyota', 4, 180);
myCar.move(); // Из класса Transport
myCar.honk(); // Уникальный метод класса Car
Bicycle myBike = Bicycle(true, 2, 20);
myBike.move(); // Из класса Transport
myBike.ringBell(); // Уникальный метод класса Bicycle
Airplane myPlane = Airplane(2, 900);
myPlane.move(); // Из класса Transport
myPlane.fly(); // Уникальный метод класса Airplane
Train myTrain = Train(10, 80);
myTrain.move(); // Из класса Transport
myTrain.chooChoo();// Уникальный метод класса Train
Ship myShip = Ship(3, 30);
myShip.move(); // Из класса Transport
myShip.sail(); // Уникальный метод класса Ship
}
В результате:
Мы создали один базовый класс
Transport
и унаследовали его для создания конкретных классов.Каждый унаследованный класс получил свойства и методы базового класса и добавил свои уникальные.
Это позволяет не дублировать общие части кода и поддерживать его в порядке.
Пример:
Давай создадим мини-приложение для магазина, где будут разные типы товаров. У нас будут базовые свойства и функции для товара (например, цена, название), а также уникальные для каждого типа товара — например, книги и электроника. Используем наследование, чтобы сделать код проще и избежать повторения.
Структура приложения
Главный экран с товаром, где мы показываем список продуктов.
Детальный экран для просмотра конкретного товара, где видим подробности.
Почему используем наследование?
Мы можем создать базовый класс "Товар" и наследовать его для других классов, таких как Книга и Электроника. Это позволяет нам описать общие свойства и методы (например, price
, name
, showDetails()
), которые будут у всех товаров, и добавить уникальные свойства только для каждого конкретного типа товара.
Шаг 1: Создание классов с наследованием
Базовый класс Product
class Product {
String name;
double price;
Product(this.name, this.price);
void showDetails() {
print('Название: $name, Цена: $price');
}
}
Product
— это базовый класс "Товар", который имеетname
иprice
, а также методshowDetails()
, который выводит название и цену.
Наследуемые классы для конкретных товаров
Класс для книг
class Book extends Product {
String author;
Book(String name, double price, this.author) : super(name, price);
@override
void showDetails() {
super.showDetails();
print('Автор: $author');
}
}
Book
наследуетProduct
, а также добавляет свойствоauthor
и переопределяет методshowDetails()
, чтобы показать автора.
Класс для электроники
class Electronics extends Product {
String brand;
Electronics(String name, double price, this.brand) : super(name, price);
@override
void showDetails() {
super.showDetails();
print('Бренд: $brand');
}
}
Electronics
наследуетProduct
, добавляя уникальное свойствоbrand
для бренда устройства.
Шаг 2: Главный экран со списком товаров
Теперь создадим главный экран в Flutter с ListView
, который отображает все товары.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Магазин',
home: ProductListScreen(),
);
}
}
class ProductListScreen extends StatelessWidget {
final List<Product> products = [
Book('Сила привычки', 20.0, 'Чарльз Дахигг'),
Electronics('Смартфон', 999.0, 'Samsung'),
Book('Мастер и Маргарита', 15.0, 'Михаил Булгаков'),
Electronics('Ноутбук', 1500.0, 'Apple')
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Список товаров')),
body: ListView.builder(
itemCount: products.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(products[index].name),
subtitle: Text('\$${products[index].price}'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetailScreen(product: products[index]),
),
);
},
);
},
),
);
}
}
В
ProductListScreen
мы создали списокproducts
с объектамиBook
иElectronics
.Когда пользователь нажимает на товар, его отправляют на
ProductDetailScreen
.
Шаг 3: Детальный экран продукта
Теперь создадим экран для показа подробностей о товаре.
class ProductDetailScreen extends StatelessWidget {
final Product product;
ProductDetailScreen({required this.product});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Детали товара')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
product.name,
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
Text('Цена: \$${product.price}', style: TextStyle(fontSize: 18)),
SizedBox(height: 10),
ElevatedButton(
onPressed: () => product.showDetails(),
child: Text('Показать детали в консоли'),
),
],
),
),
);
}
}
ProductDetailScreen
принимает товарproduct
и показывает его название и цену.По нажатию кнопки выводятся детали товара в консоль.
Полный код
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Магазин',
home: ProductListScreen(),
);
}
}
class Product {
String name;
double price;
Product(this.name, this.price);
void showDetails() {
print('Название: $name, Цена: $price');
}
}
class Book extends Product {
String author;
Book(String name, double price, this.author) : super(name, price);
@override
void showDetails() {
super.showDetails();
print('Автор: $author');
}
}
class Electronics extends Product {
String brand;
Electronics(String name, double price, this.brand) : super(name, price);
@override
void showDetails() {
super.showDetails();
print('Бренд: $brand');
}
}
class ProductListScreen extends StatelessWidget {
final List<Product> products = [
Book('Сила привычки', 20.0, 'Чарльз Дахигг'),
Electronics('Смартфон', 999.0, 'Samsung'),
Book('Мастер и Маргарита', 15.0, 'Михаил Булгаков'),
Electronics('Ноутбук', 1500.0, 'Apple')
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Список товаров')),
body: ListView.builder(
itemCount: products.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(products[index].name),
subtitle: Text('\$${products[index].price}'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetailScreen(product: products[index]),
),
);
},
);
},
),
);
}
}
class ProductDetailScreen extends StatelessWidget {
final Product product;
ProductDetailScreen({required this.product});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Детали товара')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
product.name,
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
Text('Цена: \$${product.price}', style: TextStyle(fontSize: 18)),
SizedBox(height: 10),
ElevatedButton(
onPressed: () => product.showDetails(),
child: Text('Показать детали в консоли'),
),
],
),
),
);
}
}
Объяснение кода
Product
— базовый класс для всех товаров. В нем общие свойстваname
иprice
и методshowDetails
.Book
иElectronics
наследуютProduct
, добавляя уникальные свойстваauthor
иbrand
.Наследование помогает не дублировать общие свойства для каждого товара.
Экран
ProductListScreen
показывает список товаров, аProductDetailScreen
выводит детали выбранного товара.
Это приложение помогает видеть, как наследование упрощает код и делает его более структурированным.
Last updated