Drip Java Lecture 4
Drip Java Lecture 4
Денис Син
План лекции
Интерфейсы
Абстрактные классы
Исключения
Основные паттерны
2
Интерфейс interface Animal {
void makeSound();
• Определение: Интерфейс — это контракт, который }
определяет какие методы должен реализовать
класс. class Dog implements Animal {
@Override
public void makeSound() {
[Link]("Гав!");
}
}
3
Дефолтные и статические interface Vehicle {
default void startEngine() {
методы (Java 8+) [Link]("Двигатель запущен");
• Дефолтные методы: Позволяют добавлять
}
реализацию в интерфейс без нарушения static int getHorsePower() {
существующих классов. return 150;
• Статические методы: Методы, вызываемые через }
имя интерфейса. }
4
Множественное interface Flyable {
void fly();
наследование }
• Интерфейсы поддерживают реализацию
нескольких интерфейсов. interface Swimmable {
void swim();
}
5
Comparable и Runnable public interface Comparable<T> {
public int compareTo(T o);
• Есть много интерфейсов из стандартной
}
библиотеки
• Runnable – для реализации одно метода запуска public interface Runnable {
какой-то логики /**
• Comparable – для сравнивания объектов * Runs this operation.
*/
void run();
}
6
Comparable
7
Что такое абстрактный abstract class Shape {
abstract double calculateArea(); // Абстрактный
класс? метод
• Класс, который нельзя инстанцировать. Может
void display() {
содержать абстрактные методы (без реализации) [Link]("Площадь: " + calculateArea());
и обычные методы. }
}
8
Абстрактные методы
Не имеют тела (реализации).
9
Абстрактные методы
10
Конструкторы в abstract class Animal {
String name;
абстрактных классах Animal(String name) { // Конструктор
• Могут иметь конструкторы для инициализации
[Link] = name;
полей. }
• Вызываются при создании подкласса. abstract void sound();
}
11
Интерфейсы + interface Drawable {
void draw();
абстрактные классы }
• Абстрактный класс может реализовывать
интерфейс. abstract class Figure implements Drawable {
• Подкласс наследует и расширяет abstract void scale(double factor);
функциональность. }
12
Практическое применение abstract class Game {
abstract void initialize(); // Шаги для реализации
абстрактных классов abstract void play();
• Абстрактный класс определяет скелет алгоритма,
abstract void finish();
оставляя реализацию шагов подклассам
final void run() { // Шаблонный метод
initialize();
play();
finish();
}
}
13
Практическое применение абстрактных классов
14
Number
public abstract class Number implements [Link] {
Когда выбирать:
• Если нужна общая реализация для группы классов.
• Если требуется состояние (поля).
16
Итоги Интерфейсы Абстрактные классы
17
Полиморфизм // Интерфейс Shape
interface Shape {
• Полиморфизм позволяет использовать одно и то
void draw();
же имя метода для различных классов, где }
реализация этого метода может отличаться.
Например, два разных класса могут иметь метод с // Класс Circle, реализующий интерфейс Shape
одинаковым именем, но выполняющим разные class Circle implements Shape {
действия в зависимости от класса объекта, к @Override
которому он применяется public void draw() {
[Link]("Рисуем круг");
}
}
18
Полиморфизм
19
SOLID
• SOLID — набор правил для создания гибкого и поддерживаемого кода.
• Цель: Упростить масштабирование и уменьшить количество ошибок.
• S — Single Responsibility (Единая ответственность).
• O — Open/Closed (Открытость/Закрытость).
• L — Liskov Substitution (Подстановка Лисков).
• I — Interface Segregation (Разделение интерфейсов).
• D — Dependency Inversion (Инверсия зависимостей).
20
Single responsibility class UserManager {
void createUser(User user) { /* ... */ }
• Класс управляет пользователями, отправляет
void sendEmail(User user, String message) { /* ... */ }
письма и сохраняет в файл — нарушение SRP. void saveToFile(User user) { /* ... */ }
}
21
Single responsibility class UserService { void createUser(User user) { /* ... */ } }
class EmailService { void sendEmail(User user, String
• Итог: Каждый класс отвечает за свою логику.
message) { /* ... */ } }
class FileService { void saveToFile(User user) { /* ... */ } }
22
Open closed class PaymentProcessor {
void process(String type) {
• Класс открыт для расширения, но закрыт для
if ([Link]("PayPal")) { /* ... */ }
изменений. else if ([Link]("CreditCard")) { /* ... */ }
• Добавление нового способа оплаты требует }
изменения кода. }
23
Open closed interface PaymentMethod {
void process();
• Новые способы оплаты добавляются без
}
изменения PaymentProcessor
class PayPal implements PaymentMethod {
@Override
public void process() { /* ... */ }
}
class PaymentProcessor {
void process(String type) {
paymentMethods[type].process()
}
}
24
Принцип L (Liskov Substitution) class Bird {
}
• Иерархия корректна, пингвины не «ломают»
логику. class FlyingBird extends Bird {
void fly() { /* ... */ }
}
25
Принцип L (Liskov Substitution) class Bird { void fly() { /* ... */ } }
class Penguin extends Bird {
• Суть: Подклассы должны заменять базовые
@Override void fly() {
классы без сбоев. throw new Error("Пингвины не летают!");
}
}
26
Принцип I (Interface Segregation) interface Worker {
void work();
• Интерфейс заставляет реализовывать ненужные
void eat();
методы. }
class Robot implements Worker {
@Override public void work() { /* ... */ }
@Override public void eat() { /* ... */ } // Робот не
ест!
}
27
Принцип I (Interface Segregation) interface Workable {
void work();
• Клиенты зависят только от нужных методов.
}
interface Eatable {
void eat();
}
28
Принцип D (Dependency class LightBulb {
Inversion) void turnOn() { /* ... */ }
}
• Зависимости строятся на абстракциях, а не на
конкретике.
class Switch {
• Класс Switch зависит от конкретной LightBulb.
private LightBulb bulb = new LightBulb();
void operate() {
[Link]();
}
}
29
interface Switchable {
Принцип D (Dependency void turnOn();
}
Inversion)
• Switch работает с любым устройством через class LightBulb implements Switchable {
интерфейс. @Override
public void turnOn() { /* ... */ }
}
class Switch {
private Switchable device;
Switch(Switchable device) {
[Link] = device;
}
void operate() {
[Link]();
}
}
30
GRASP
GRASP (General Responsibility Assignment Software Patterns) — набор принципов для распределения
обязанностей между классами.
• Information Expert
• Creator
• Controller
• Low Coupling
• High Cohesion
31
Information Expert // Проблема: Где вычислять общую стоимость заказа?
class Order {
List<Product> products;
• Ответственность должна быть назначена классу, // Класс Order знает свои продукты → он и должен
который владеет необходимой информацией. вычислять сумму.
}
class Product {
String name;
double price;
}
// Решение:
class Order {
List<Product> products;
public double getTotalPrice() {
return [Link]().mapToDouble(p -> [Link]).sum();
}
}
32
Creator // Проблема: Кто должен создавать элементы меню?
class Restaurant {
List<MenuItem> menu;
Суть: Класс А должен создавать объекты класса Б, // Ресторан содержит меню → он и создает его элементы.
если: }
• А содержит/агрегирует Б.
class MenuItem {
• А использует Б чаще других.
String name;
double price;
}
// Решение:
class Restaurant {
List<MenuItem> menu = new ArrayList<>();
public void addMenuItem(String name, double price) {
[Link](new MenuItem(name, price));
}
}
33
Controller // Проблема: Обработка нажатия кнопки в UI-классе.
class LoginScreen {
void onLoginButtonClicked() {
Входные запросы системы должны обрабатываться // Проверка логина/пароля, навигация и т.д. → слишком
отдельным классом-«контроллером», а не UI- много логики!
компонентами. }
}
// Решение:
class AuthController {
boolean authenticate(String login, String password) { /* ... */ }
}
class LoginScreen {
AuthController authController = new AuthController();
void onLoginButtonClicked() {
[Link]([Link](),
[Link]());
}
}
34
Low Coupling Слабая // Проблема: Прямая зависимость между классами.
class OrderService {
связанность private MySQLDatabase db; // Жесткая привязка к MySQL
void saveOrder(Order order) {
Минимизируйте зависимости между классами. [Link](order);
}
}
class OrderService {
private Database db; // Зависит от абстракции
OrderService(Database db) { [Link] = db; }
}
35
High Cohesion (Высокая // Проблема: Класс делает слишком много.
class UserManager {
связанность) void createUser() { /* ... */ }
Класс должен решать одну задачу, а его методы — void sendEmail() { /* ... */ }
быть логически связаны.
void generateReport() { /* ... */ } // Не относится к управлению
пользователями!
}
class EmailService {
void sendEmail() { /* ... */ }
}
class ReportService {
void generateReport() { /* ... */ }
}
36
Принцип Polymorphism interface SoundMaker {
void makeSound();
(Полиморфизм) }
// Использование:
List<SoundMaker> animals = [Link](new Dog(), new Cat());
[Link](SoundMaker::makeSound);
37
Принцип Pure Fabrication // Проблема: Класс User не должен заниматься сохранением в
БД.
class User {
Создавайте «искусственные» классы для задач, String name;
которые не относятся к предметной области, но void saveToDatabase() { /* ... */ } // Нарушение! Это не
нужны для технической реализации. ответственность User.
}
class User {
String name;
// Теперь User содержит только данные.
}
38
Принцип Indirection // Проблема: Прямая связь между PaymentService и PayPal API.
class PaymentService {
private PayPalGateway payPal = new PayPalGateway();
void processPayment() {
Вводите промежуточные компоненты, чтобы [Link]();
уменьшить прямую зависимость между классами. }
}
class PaymentService {
private PaymentGateway gateway;
PaymentService(PaymentGateway gateway) {
[Link] = gateway;
}
void processPayment() {
[Link]();
}
}
39
Исключения в Java — Зачем они int a = 10 / 0; // Программа упадет с ArithmeticException
нужны?
try {
• Ошибки в программе (например, деление на
int a = 10 / 0;
ноль, отсутствие файла) могут привести к
} catch (ArithmeticException e) {
аварийному завершению. [Link]("Деление на ноль запрещено!");
• Исключения позволяют управлять ошибками и }
сохранять контроль над выполнением
программы.
40
Иерархия исключений
41
Обработка исключений (try-catch-finally)
try {
FileReader file = new FileReader("[Link]");
} catch (FileNotFoundException e) {
[Link]("Файл не найден!");
} finally {
[Link]("Блок finally выполнен.");
}
42
Checked exceptions public void readFile() {
try {
FileReader file = new FileReader("[Link]");
} catch (FileNotFoundException e) { // Обработка checked
• Компилятор требует их обработки.
исключения
• Примеры: IOException, SQLException
[Link]("Файл не найден.");
}
} // Если не обработать код не скомпилируется
43
Unchecked exceptions public void calculate() {
int[] arr = {1, 2};
[Link](arr[3]); // ArrayIndexOutOfBoundsException
(unchecked)
• Не требуют явной обработки.
}
• Примеры: ArithmeticException,
ArrayIndexOutOfBoundsException.
44
Создание своих исключений class AgeValidationException extends Exception {
AgeValidationException(String message) {
super(message);
}
• Наследуйтесь от Exception (checked) или
}
RuntimeException (unchecked).
// Использование:
void setAge(int age) throws AgeValidationException {
if (age < 0) throw new AgeValidationException("Возраст не
может быть отрицательным!");
}
45
try with resources try (FileReader file = new FileReader("[Link]")) {
// Работа с файлом
} catch (IOException e) {
[Link]("Ошибка чтения файла.");
• Проблема: Утечка ресурсов (например,
}
незакрытые файлы).
// Ресурс file закрывается автоматически!
• Решение: Автоматическое закрытие ресурсов,
реализующих AutoCloseable.
46
Интерфейс AutoCloseable class DatabaseConnection implements AutoCloseable {
@Override
public void close() {
[Link]("Соединение с БД закрыто.");
• Объекты, которые должны быть закрыты,
}
реализуют метод close().
}
// Использование:
try (DatabaseConnection conn = new DatabaseConnection()) {
// Работа с БД
} // [Link]() вызывается автоматически
47
Множественные исключения в try {
// Код, который может вызвать разные исключения
catch } catch (FileNotFoundException | SQLException e) {
[Link]("Ошибка: " + [Link]());
• Java 7+: Можно перечислять исключения через |. }
48
Best practices
Не игнорируйте исключения:
Логируйте ошибки:
49
Итоги
Исключения делают код устойчивым к ошибкам.
50
Зачем нужны классы для // Плохо:
int day = 31;
работы с датами? int month = 12; // Декабрь? А если месяц 0-11?
51
Основные классы ([Link]) LocalDate date = [Link]();
LocalTime time = [Link](14, 30);
LocalDateTime dateTime = [Link](date, time);
• LocalDate: Дата без времени (год, месяц, день).
• LocalTime: Время без даты (часы, минуты,
секунды).
• LocalDateTime: Дата + время.
• ZonedDateTime: Дата + время + временная зона.
52
Всем больше Java