gb-java-devel/jtd3-08-workshop.tex

625 lines
35 KiB
TeX
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

\documentclass[j-spec.tex]{subfiles}
\usepackage{spreadtab}
\begin{document}
\section{Семинар: Обобщения}
\subsection{Инструментарий}
\begin{itemize}
\item \href{https://docs.google.com/presentation/d/1rWHGQBITRElvyKFEjwe8dOinDbAV2ZW18tAK1FXU48U/edit?usp=share_link}{Презентация} для преподавателя, ведущего семинар;
\item \href{https://drive.google.com/file/d/1LWyE8aEy4-1gsognqhXIXwDcoLviVge4/view}{Фон} GeekBrains для проведения семинара в Zoom;
\item JDK любая 11 версии и выше;
\item \href{https://www.jetbrains.com/idea/download}{IntelliJ IDEA Community Edition} для практики и примеров используется IDEA.
\end{itemize}
\subsection{Цели семинара}
\begin{itemize}
\item Практика создания простых обобщений;
\item Создание собственного обобщённого контейнера с описанием базовых алгоритмов (введение в коллекции);
\item Изучение поведения объекта итератора;
\item Закрепление понимания механизмов работы коллекций.
\end{itemize}
\subsection{План-содержание}
\noindent
\begin{spreadtab}{{longtable}{|p{37mm}|l|l|p{90mm}|}}
\hline
@ Что происходит & @ Время & @ Слайды & @ Описание \\
\hline
\endhead
@ Организационный момент & 5 tag(beg) & @ 1-5 & @ Преподаватель ожидает студентов, поддерживает активность и коммуникацию в чате, озвучивает цели и планы на семинар. Важно упомянуть, что выполнение домашних заданий с лекции является, фактически, подготовкой к семинару \\
\hline
@ Quiz & 5 & @ 6-18 & @ Преподаватель задаёт вопросы викторины, через 30 секунд демонстрирует слайд-подсказку и ожидает ответов (по минуте на ответ) \\
\hline
@ Рассмотрение ДЗ лекции & 10 & @ 19-23 & @ Преподаватель демонстрирует свой вариант решения домашнего задания с лекции, возможно, по предварительному опросу, демонстрирует и разбирает вариант решения одного из студентов \\
\hline
@ Вопросы и ответы & 10 & @ 24 & @ Преподаватель ожидает вопросов по теме прошедшей лекции, викторины и продемонстрированной работы \\
\hline
@ Задание 1 & 10 & @ 25-27 & @ Формирование навыков базовой работы с обобщениями \\
\hline
@ Задание 2 & 20 & @ 28-30 & @ Практика написания обобщённого кода с дополнительным описанием алгоритмов манипулирования данными \\
\hline
@ Перерыв (если нужен) & 5 & @ 31 & @ Преподаватель предлагает студентам перерыв на 5 минут (студенты голосуют) \\
\hline
@ Задание 3 & 20 & @ 32-34 & @ Изучение поведения итератора для понимания механизмов его действия и необходимости его использования в работе \\
\hline
@ Задание 4 & 20 & @ 35-38 & @ Закрепление понимания механизмов работы коллекций (в том числе с применением итераторов) \\
\hline
@ Домашнее задание & 5 & @ 39-40 & @ Объясните домашнее задание, подведите итоги урока \\
\hline
@ Рефлексия & 10 tag(end) & @ 41-42 & @ Преподаватель запрашивает обратную связь \\
\hline
@ Длительность & sum(cell(beg):cell(end)) & & \\
\hline
\end{spreadtab}
\subsection{Подробности}
\subsubsection*{Организационный момент}
\begin{itemize}
\item \textbf{Цель этапа:} Позитивно начать урок, создать комфортную среду для обучения.
\item \textbf{Тайминг:} 3-5 минут.
\item \textbf{Действия преподавателя:}
\begin{itemize}
\item Запрашивает активность от аудитории в чате;
\item Презентует цели курса и семинара;
\item Презентует краткий план семинара и что студент научится делать.
\end{itemize}
\end{itemize}
\subsubsection*{Quiz}
\begin{itemize}
\item \textbf{Цель этапа:} Вовлечение аудитории в обратную связь.
\item \textbf{Тайминг:} 5--7 минут (4 вопроса, по минуте на ответ).
\item \textbf{Действия преподавателя:}
\begin{itemize}
\item Преподаватель задаёт вопросы викторины, представленные на слайдах презентации;
\item через 30 секунд демонстрирует слайд-подсказку и ожидает ответов.
\end{itemize}
\item \textbf{Вопросы и ответы:}
\begin{enumerate}
\item Какая основная цель использования Java generics? (1)
\begin{enumerate}
\item Упрощение программирования и повышение безопасности типов
\item Ускорение работы программы и сокращение объема кода
\item Позволяют работать с различными базами данных одновременно
\end{enumerate}
% Неверные ответы: b) и c) - generics не связаны с ускорением работы программы или работой с базами данных, их основная цель - добавить типовую безопасность и упростить программирование.
\item Что такое параметризованный класс в Java generics? (1)
\begin{enumerate}
\item Класс, который принимает параметр типа
\item Класс, который имеет только один параметр типа
\item Класс, который можно использовать только с определенным типом данных
\end{enumerate}
% Неверные ответы: b) и c) - параметризованный класс может иметь любое количество параметров типа и может быть использован с различными типами данных.
\item Какие ограничения можно использовать с wildcard в Java generics? (1)
\begin{enumerate}
\item extends и super
\item only
\item extends
\end{enumerate}
% Неверные ответы: b) и c) - в generics для ограничения типа используются ключевые слова extends и super, а не only или extends.
\item Можно ли создать экземпляр обобщенного типа в Java, внутри класса, описывающего этот тип? (2)
\begin{enumerate}
\item Да, это возможно
\item Нет, такое создание экземпляров обобщенных типов запрещено
\item Это зависит от контекста использования обобщенного типа
\end{enumerate}
% Неверные ответы: a) и c) - экземпляры обобщенных типов не могут быть созданы в Java из-за стирания типов, однако можно создать экземпляр обобщенного класса, указав конкретный тип данных.
\end{enumerate}
\end{itemize}
\subsubsection*{Рассмотрение ДЗ}
\begin{itemize}
\item \textbf{Цель этапа:} Пояснить не очевидные моменты в формулировке ДЗ с лекции, синхронизировать прочитанный на лекции материал к началу семинара.
\item \textbf{Тайминг:} 15-20 минут.
\item \textbf{Действия преподавателя:}
\begin{itemize}
\item Преподаватель демонстрирует свой вариант решения домашнего задания из лекции;
\item возможно, по предварительному опросу, демонстрирует и разбирает вариант решения одного из студентов.
\end{itemize}
\item \textbf{Домашнее задание из лекции:}
\begin{itemize}
\item Написать метод, который меняет два элемента массива местами (массив может быть любого ссылочного типа);
\textbf{Вариант решения}
Задание с подвохом, при решении необязательно было использовать дженерики, формулировка задания не ограничивает используемые в массиве типы, наоборот, явно проговаривается, что массив может быть любого типа.
\begin{lstlisting}[language=Java,style=JCodeStyle]
private static void swap(Object[] arr, int from, int to) {
Object temp = arr[from];
arr[from] = arr[to];
arr[to] = temp;
}
public static void main(String[] args) {
Object[] arr = {1, 2.0f, "hello"};
System.out.println(Arrays.toString(arr));
swap(arr, 0, 2);
System.out.println(Arrays.toString(arr));
}
\end{lstlisting}
\item Большая задача:
\begin{itemize}
\item Есть классы \code{Fruit} -> \code{Apple}, \code{Orange}; (больше не надо);
\item Класс \code{Box} в который можно складывать фрукты, коробки условно сортируются по типу фрукта, поэтому в одну коробку нельзя сложить и яблоки, и апельсины; Для хранения фруктов внутри коробки можете использовать \code{ArrayList};
\item Сделать метод \code{getWeight()} который высчитывает вес коробки, зная количество фруктов и вес одного фрукта(вес яблока -- \code{1.0f}, апельсина -- \code{1.5f}, не важно в каких единицах);
\item Внутри класса коробки сделать метод \code{compare()}, который позволяет сравнить текущую коробку с той, которую подадут в \code{compare()} в качестве параметра, \code{true} -- если их веса равны, \code{false} в противном случае (коробки с яблоками возможно сравнивать с коробками с апельсинами);
\item Написать метод, который позволяет пересыпать фрукты из текущей коробки в другую коробку (при этом, нельзя яблоки высыпать в коробку с апельсинами), соответственно, в текущей коробке фруктов не остается, а в другую перекидываются объекты, которые были в этой коробке.
\end{itemize}
\textbf{Вариант решения}
Создали фрукты с каким то разным весом, создали коробку, которая может вместить только фрукты. Надо фрукты там как то хранить, поэтому -- список. Соответственно при создании можем в нашу коробку какие то фрукты накидать. Соответственно метод, который будет уметь добавлять фрукты в коробку
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={ }]
private interface Fruit { float getWeight(); }
private static class Apple implements Fruit {
static final float weight = 1.0f;
@Override public float getWeight() { return weight; }
}
private static class Orange implements Fruit {
static final float weight = 1.5f;
@Override public float getWeight() { return weight; }
}
public static class Box<T extends Fruit> {
private final List<T> container;
Box(T[] init) {
container = new ArrayList<>();
for (T f : init) { add(f); }
}
void add(T fruit) { container.add(fruit); }
void print() { System.out.println(getWeight()); }
}
\end{lstlisting}
Поскольку в коробке у нас могут быть только одно типа фрукты -- мы можем не перебирать каждый из них, а умножить вес одного на количество.
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={ }]
float getWeight() {
return (container.isEmpty())
? 0
: container.get(0).getWeight() * container.size();
}
\end{lstlisting}
Можно было, по большому счёту, переопределить метод equals() или написать свой метод compare() который принимает вторую коробку и сравнивает вес. Сравнивать можно любые фрукты, значит в методе не подходит параметр типа \code{<T>}
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={ }]
boolean compare(Box<?> with) {
return this.getWeight() - with.getWeight() < 0.0001;
}
\end{lstlisting}
Осталось только уметь пересыпать из одной коробки в другую не смешивая. На входе должна быть коробка того же типа, что и у объекта, и тут два пути, либо пересыпать всё из текущей коробки в другую, либо из другой в текущую, метод назван \code{transferTo()}, поэтому пересыпаться фрукты будут из текущей коробки. Возникает вопрос: если создаётся коробка с яблоками \code{Box<Apple>} и коробка с фруктами \code{Box<Fruit>}, должна ли быть возможность перекинуть из яблочной во фруктовую? Однозначно, нет. Поэтому, в аргументе метода используется \code{Box<? super T>}, таким образом яблоки возможно кидать в яблоки или в яблочных родителей, но не в апельсины.
\begin{lstlisting}[language=Java,style=JCodeStyle,caption={ }]
void transferTo(Box<? super T> dest) {
dest.container.addAll(container);
container.clear();
}
\end{lstlisting}
\end{itemize}
\end{itemize}
\subsubsection*{Вопросы и ответы}
\begin{itemize}
\item \textbf{Ценность этапа} Вовлечение аудитории в обратную связь, пояснение неочевидных моментов в материале лекции и другой проделанной работе.
\item \textbf{Тайминг} 5-15 минут
\item \textbf{Действия преподавателя}
\begin{itemize}
\item Преподаватель ожидает вопросов по теме прошедшей лекции, викторины и продемонстрированной работы;
\item Если преподаватель затрудняется с ответом, необходимо мягко предложить студенту ответить на его вопрос на следующем семинаре (и не забыть найти ответ на вопрос студента!);
\item Предложить и показать пути самостоятельного поиска студентом ответа на заданный вопрос;
\item Посоветовать литературу на тему заданного вопроса;
\item Дополнительно указать на то, что все сведения для выполнения домашнего задания, прохождения викторины и работы на семинаре были рассмотрены в методическом материале к этому или предыдущим урокам.
\end{itemize}
\end{itemize}
\subsubsection*{Задание 1}
\begin{itemize}
\item \textbf{Ценность этапа} Формирование навыков базовой работы с обобщениями.
\item \textbf{Тайминг} 10-15 мин
\item \textbf{Действия преподавателя}
\begin{itemize}
\item Выдать задание студентам;
\item Подробно объяснить, что именно требуется от студентов, избегая упоминания конкретных языковых конструкций;
\item Пояснить студентам пользу и необходимость следования паттерну MVC, проговорить важность разделения логики и открывающиеся возможности при правильном проектировании.
\end{itemize}
\item \textbf{Задание}:
\begin{itemize}
\item Создать обобщенный класс с тремя параметрами (\code{T}, \code{V}, \code{K}). Класс содержит три переменные типа (\code{T}, \code{V}, \code{K}), конструктор, принимающий на вход параметры типа (\code{T}, \code{V}, \code{K}), методы возвращающие значения трех переменных. Создать метод, выводящий на консоль имена классов для трех переменных класса. Наложить ограничения на параметры типа: \code{T} должен реализовать интерфейс \code{Comparable} (классы оболочки, \code{String}), \code{V} должен реализовать интерфейс \code{DataInput} и расширять класс \code{InputStream}, \code{K} должен расширять класс \code{Number}.
\textbf{Вариант решения}
\begin{lstlisting}[language=Java,style=JCodeStyle]
private static class MyClass<T extends Comparable, V extends InputStream & Serializable, K extends Number> {
T t; V v; K k;
MyClass(T t, V v, K k) {
this.t = t; this.v = v; this.k = k;
}
public T getT() { return t; }
public V getV() { return v; }
public K getK() { return k; }
void print() {
System.out.printf("t = %s, v = %s, k = %s",
t.getClass().getName(),
v.getClass().getName(),
k.getClass().getName());
}
}
\end{lstlisting}
\end{itemize}
\end{itemize}
\subsubsection*{Задание 2}
\begin{itemize}
\item \textbf{Ценность этапа} Практика написания обобщённого кода с дополнительным описанием алгоритмов манипулирования данными.
\item \textbf{Тайминг} 15-20 мин
\item \textbf{Действия преподавателя}
\begin{itemize}
\item Выдать задание студентам;
\item Подробно объяснить, что именно требуется от студентов, избегая упоминания конкретных языковых конструкций;
\item Если группа студентов справилась с заданием, а времени осталось более 5 минут, выдавать группе задания «со звёздочкой».
\end{itemize}
\item \textbf{Задание}:
\begin{itemize}
\item Описать собственную коллекцию -- список на основе массива. Коллекция должна иметь возможность хранить любые типы данных, иметь методы добавления и удаления элементов.
\textbf{Вариант решения}
\begin{lstlisting}[language=Java,style=JCodeStyle]
private static class OwnList<T> {
Object[] arr;
int count;
OwnList() {
arr = new Object[1];
count = 0;
}
void add(T item) {
if (count == arr.length) {
Object[] newArr = new Object[arr.length * 2];
System.arraycopy(arr, 0, newArr, 0, arr.length);
arr = newArr;
}
arr[count++] = item;
}
T remove() {
if (count == 0) throw new NoSuchElementException();
T temp = (T) arr[--count];
arr[count] = null;
return temp;
}
@Override
public String toString() {
return Arrays.toString(arr);
}
}
\end{lstlisting}
\end{itemize}
\end{itemize}
\subsubsection*{Задание 3}
\begin{itemize}
\item \textbf{Ценность этапа} Изучение поведения итератора для понимания механизмов его действия и необходимости его использования в работе.
\item \textbf{Тайминг} 20-25 мин
\item \textbf{Действия преподавателя}
\begin{itemize}
\item Выдать задание студентам;
\item Подробно объяснить, что именно требуется от студентов, избегая упоминания конкретных языковых конструкций;
\end{itemize}
\item \textbf{Задание}:
\begin{itemize}
\item Написать итератор по массиву. Итератор -- это объект, осуществляющий движение по коллекциям любого типа, содержащим любые типы данных. Итераторы обычно имеют только два метода -- проверка на наличие следующего элемента и переход к следующему элементу. Но также, особенно в других языках программирования, возможно встретить итераторы, реализующие дополнительную логику.
\textbf{Вариант решения}
\begin{lstlisting}[language=Java,style=JCodeStyle]
private static class ArrayIterator<T> {
private final T[] array;
private int index = 0;
public ArrayIterator(T[] array) {
this.array = array;
}
public boolean hasNext() {
return index < array.length;
}
public T next() {
if(!hasNext())
throw new NoSuchElementException();
return array[index++];
}
}
public static void main(String[] args) {
Integer[] arr = {1,2,3,4};
ArrayIterator<Integer> it = new ArrayIterator<>(arr);
while (it.hasNext()) {
System.out.print(it.next() + " ");
}
}
\end{lstlisting}
\item [$*_1$] Написать итератор таким образом, чтобы его возможно было использовать для цикла \code{foreach}.
\textbf{Вариант решения}
Указать, что для этого достаточно реализовать интерфейс \code{Iterator<T>}.
\begin{lstlisting}[language=Java,style=JCodeStyle]
class ArrayIterator<T> implements Iterator<T>{
private T[] array;
private int index = 0;
public ArrayIterator(T[] array) {
this.array = array;
}
@Override
public boolean hasNext() {
return index < array.length;
}
@Override
public T next() {
if(!hasNext())
throw new NoSuchElementException();
return array[index++];
}
}
\end{lstlisting}
\end{itemize}
\end{itemize}
\subsubsection*{Задание 4}
\begin{itemize}
\item \textbf{Ценность этапа} Закрепление понимания механизмов работы коллекций (в том числе с применением итераторов).
\item \textbf{Тайминг} 20-25 мин
\item \textbf{Действия преподавателя}
\begin{itemize}
\item Выдать задание студентам;
\item Подробно объяснить, что именно требуется от студентов, избегая упоминания конкретных языковых конструкций;
\end{itemize}
\item \textbf{Задание}:
\begin{itemize}
\item Описать интерфейс \code{Person} с методами \code{doWork()} и \code{haveRest()}. Написать два класса работник и бездельник, реализующих интерфейс. Работник работает, и не умеет бездельничать, в то время как бездельник не умеет работать, но умеет отдыхать. Написать обобщённые классы \code{Workplace} и \code{Club}, содержащие массив из \code{Person}. В классах необходимо вызывать у всего массива людей вызывать соответствующие методы.
\textbf{Вариант решения}
\begin{lstlisting}[language=Java,style=JCodeStyle]
interface Person {
void doWork();
void haveRest();
}
private static class Worker implements Person {
@Override public void doWork() {
System.out.println("Work!"); }
@Override public void haveRest() {
System.out.println("What?");
}
}
private static class Idler implements Person {
@Override public void doWork() {
System.out.println("No!"); }
@Override public void haveRest() {
System.out.println("Chill!");
}
}
private static class Workplace<T extends Person> {
Person[] arr;
public Workplace(T... people) {
arr = people;
}
void work() {
for (Person person : arr) { person.doWork(); }
}
}
private static class Club<T extends Person> {
Person[] arr;
public Club(T... people) {
arr = people;
}
void chill() {
for (Person person : arr) { person.haveRest(); }
}
}
public static void main(String[] args) {
Workplace<Person> w = new Workplace<>(new Worker(), new Worker(), new Idler());
Club<Person> c = new Club<>(new Worker(), new Worker(), new Idler());
w.work();
c.chill();
}
\end{lstlisting}
\end{itemize}
\end{itemize}
\subsubsection*{Домашнее задание}
\begin{itemize}
\item \textbf{Ценность этапа} Задать задание для самостоятельного выполнения между занятиями.
\item \textbf{Тайминг} 5-10 минут.
\item \textbf{Действия преподавателя}
\begin{itemize}
\item Пояснить студентам в каком виде выполнять и сдавать задания
\item Уточнить кто будет проверять работы (преподаватель или ревьювер)
\item Объяснить к кому обращаться за помощью и где искать подсказки
\item Объяснить где взять проект заготовки для дз
\end{itemize}
\item \textbf{Задания}
\begin{enumerate}
\item [5-25 мин] Выполнить все задания семинара, если они не были решены, без ограничений по времени;
\textbf{Все варианты решения приведены в тексте семинара выше}
\item [25 мин] 1. Внедрить итератор из задания 2 в коллекцию, написанную в задании 3 таким образом, чтобы итератор был внутренним классом и, соответственно, объектом в коллекции.
\begin{lstlisting}[language=Java,style=JCodeStyle]
private static class OList<T> implements Iterable<T> {
class ArrayIterator<T> implements Iterator<T> {
private int index = 0;
@Override
public boolean hasNext() {
return index < count;
}
@Override
public T next() {
if(!hasNext())
throw new NoSuchElementException();
return (T) arr[index++];
}
}
Object[] arr;
int count;
Main.OList.ArrayIterator iter;
OList() {
arr = new Object[1];
count = 0;
this.iter = new ArrayIterator<T>();
}
void add(T item) {
if (count == arr.length) {
Object[] newArr = new Object[arr.length * 2];
System.arraycopy(arr, 0, newArr, 0, arr.length);
arr = newArr;
}
arr[count++] = item;
}
T remove() {
if (count == 0) throw new NoSuchElementException();
--count;
T temp = (T) arr[count];
arr[count] = null;
return temp;
}
@Override
public Iterator<T> iterator() {
return iter;
}
@Override
public Spliterator<T> spliterator() {
return Iterable.super.spliterator();
}
@Override
public String toString() {
return Arrays.toString(arr);
}
}
\end{lstlisting}
\item [15 мин] 2. Написать класс Калькулятор (необобщенный), который содержит обобщенные статические методы: \code{sum()}, \code{multiply()}, \code{divide()}, \code{subtract()}. Параметры этих методов -- два \textbf{числа} разного типа, над которыми должна быть произведена операция.
\begin{lstlisting}[language=Java,style=JCodeStyle]
private static class Calculator {
public static <T extends Number, U extends Number> double sum(T num1, U num2) {
return num1.doubleValue() + num2.doubleValue();
}
public static <T extends Number, U extends Number> double multiply(T num1, U num2) {
return num1.doubleValue() * num2.doubleValue();
}
public static <T extends Number, U extends Number> double divide(T num1, U num2) {
return num1.doubleValue() / num2.doubleValue();
}
public static <T extends Number, U extends Number> double subtract(T num1, U num2) {
return num1.doubleValue() - num2.doubleValue();
}
}
public static void main(String[] args) {
System.out.println(Calculator.sum(2, 2.0));
System.out.println(Calculator.multiply(2.0f, 2.0));
System.out.println(Calculator.divide(2L, 2.0));
System.out.println(Calculator.subtract(2, 2));
}
\end{lstlisting}
\item [10 мин] 3. Напишите обобщенный метод \code{compareArrays()}, который принимает два массива и возвращает \code{true}, если они одинаковые, и \code{false} в противном случае. Массивы могут быть любого типа данных, но должны иметь одинаковую длину и содержать элементы одного типа.
\begin{lstlisting}[language=Java,style=JCodeStyle]
private static <T> boolean compareArrays(T[] array1, T[] array2) {
if (array1.length != array2.length) {
return false;
}
for (int i = 0; i < array1.length; i++) {
if (!array1[i].equals(array2[i])) {
return false;
}
}
return true;
}
\end{lstlisting}
\item [10 мин] 4. Напишите обобщенный класс \code{Pair}, который представляет собой пару значений разного типа. Класс должен иметь методы \code{getFirst()}, \code{getSecond()} для получения значений пары, а также переопределение метода \code{toString()}, возвращающее строковое представление пары.
\begin{lstlisting}[language=Java,style=JCodeStyle]
private static class Pair<T1, T2> {
private T1 first;
private T2 second;
public Pair(T1 first, T2 second) {
this.first = first;
this.second = second;
}
public T1 getFirst() { return first; }
public T2 getSecond() { return second; }
@Override public String toString() {
return "(" + first + ", " + second + ")";
}
}
public static void main(String[] args) {
Pair<Integer, String> pair1 = new Pair<>(1, "one");
System.out.println(pair1.getFirst()); // 1
System.out.println(pair1.getSecond()); // "one"
System.out.println(pair1); // "(1, one)"
Pair<String, Double> pair2 = new Pair<>("pi", 3.14);
System.out.println(pair2.getFirst()); // "pi"
System.out.println(pair2.getSecond()); // 3.14
System.out.println(pair2); // "(pi, 3.14)"
}
\end{lstlisting}
\end{enumerate}
\end{itemize}
\subsubsection*{Рефлексия и завершение семинара}
\begin{itemize}
\item \textbf{Цель этапа:} Привести урок к логическому завершению, посмотреть что студентам удалось, что было сложно и над чем нужно еще поработать
\item \textbf{Тайминг:} 5-10 минут
\item \textbf{Действия преподавателя:}
\begin{itemize}
\item Запросить обратную связь от студентов.
\item Подчеркните то, чему студенты научились на занятии.
\item Дайте рекомендации по решению заданий, если в этом есть необходимость
\item Дайте краткую обратную связь студентам.
\item Поделитесь ощущением от семинара.
\item Поблагодарите за проделанную работу.
\end{itemize}
\end{itemize}
\newpage
\end{document}