Вы достигли нового уровня
— Привет, Амиго! Хочу сегодня тебе рассказать о причинах существования интерфейсов. Тебе очень часто придется слышать, что такой-то класс, объект или сущность поддерживает определенный интерфейс. Что же это значит – поддерживать интерфейс?
В более широком смысле интерфейс какой-нибудь вещи – это механизм взаимодействия этой вещи с другими предметами. Например, пульт от телевизора – это дистанционный интерфейс. Собака понимает и исполняет команды — это значит, что собака поддерживает голосовой интерфейс (управления). Если все это подытожить, то можно сказать, что интерфейс – это стандартизированный способ взаимодействия двух вещей, и этот стандарт известен двум сторонам. Когда человек говорит собаке «сидеть», он отдает команду в соответствии с «голосовым интерфейсом управления собакой», и если собака выполняет эту команду, то мы говорим, что собака поддерживает этот интерфейс.
Так же и в программировании. Методы – это действия над объектом, над его данными. И если класс реализует определенные методы, то он «поддерживает исполнение» определенных команд. Какие же преимущества дает объединение методов в интерфейс?
1) Каждый interface, как и class, имеет уникальное имя. Обе стороны могут быть на 100% уверены, что вторая сторона поддерживает именно нужный (известный им) интерфейс, а не похожий.
2) Каждый интерфейс налагает определенные ограничения на тот класс, который собирается поддерживать его. Класс сам решает (его разработчик), что он будет делать в случае вызова его методов, которые он унаследовал от интерфейса, но результат должен находиться в пределах ожиданий. Если мы скомандовали собаке «сидеть», и она покрутилась 5 минут на месте и села, то это – поддержка интерфейса. А если она вместо этого вцепилась вам в ногу, то ни о какой поддержке тут не может быть и речи. Выполнение команды не привело к ожидаемым результатам.
Допустим, ты с друзьями участвуешь в написании компьютерной игры. И тебе досталась работа запрограммировать поведение одного персонажа. Один ваш коллега уже написал код по отображению всех персонажей на экран. Второй, отвечающий за сохранение игры на диск, написал код по сохранению всех объектов игры в файл. Каждый из них написал много кода и сделал интерфейс для взаимодействия с ним. Например, это может выглядеть так:
Другими словами, чтобы поддержать реализацию какого-то интерфейса (группы интерфейсов) в своем классе нужно:
1) Унаследоваться от них
2) Реализовать объявленные в них методы
3) Методы должны делать то, для чего они предназначены.
Тогда остальной код программы, который ничего не знает о твоем классе и его объектах, сможет успешно работать с ним.
— А почему код может ничего не знать о моем классе?
— Допустим, ты взял код программы, который кто-то написал год назад. Или твои друзья купили/лицензировали движок игры у кого-то еще. Есть рабочий код игры. Тысячи объектов, которые взаимодействуют друг с другом. И они могут с легкостью правильно взаимодействовать с твоими объектами, если взаимодействие организовано через интерфейсы, и ты правильно реализовал эти интерфейсы в своих классах.
— Круто! Не знал что так можно.
— На этом принципе основаны все большие проекты. Уже давно никто ничего не пишет с нуля.
Люди тоже не изобретают математику и алфавит каждый раз заново, а изучают все то, что было придумано до них.
— Привет, Амиго! У меня для тебя хорошая новость! Сегодня вечером у тебя определенно будет хорошее настроение.
— Да ну?
— Да. Ведь ты будешь отлично знать интерфейсы. Ха-ха-ха! Вот тебе десять(!) задач. Не скучай, Амиго!
— Привет, Амиго! Вчера ты уже слушал лекцию про абстрактные классы. Теперь пришло время углубить наши познания. Хочу научить тебя правильно пользоваться абстрактными классами.
Сложно представить аналогию абстрактного класса в реальной жизни. Обычно класс является моделью какой-нибудь сущности. Но абстрактный класс содержит не только реализованные методы, но и не реализованные. Что же это значит? Аналогом чего является абстрактный класс и есть ли у него аналоги в реальном мире?
На самом деле есть. Представь себе почти законченный кузов машины на конвейере. Туда могу поставить как спортивный двигатель, так и экономичный. Как кожаный салон, так и матерчатый. Конкретная реализация машины еще не определена. Более того, таких конкретных реализаций на основе этого кузова предполагается несколько. Но в таком виде машина никому не нужна. Это — классический абстрактный класс: его объекты не имеют смысла, поэтому их создание запрещено, класс имеет смысл, но только для его многочисленных полноценных наследников, которые будут созданы на его основе.
— Это не сложно.
— Но могут быть и более абстрактные аналогии. Больше похожие на интерфейсы, с несколькими реализованными методами. Например, профессия переводчик. Без уточнения, с какого, и на какой язык, получим «абстрактного переводчика в вакууме». Или телохранитель. Про него может быть известно, что он владеет восточными единоборствами и может защитить клиента. Но какими именно единоборствами, и каким способом защитить клиента – это уже «особенности реализации» каждого конкретного телохранителя.
Давай посмотрим пример:
— Действительно, по смыслу очень напоминает интерфейс с несколькими реализованными методами.
— Да, абстрактные классы такого типа мы будем часто встречать среди стандартных классов JavaSE.
— Привет, Амиго! Я собирался помочь тебе сегодня с задачами. Но слишком устал. А вечером у меня еще много дел: нужно выпить пива и с друзьями поиграть в покер. Так что удачи, дружище! Решай задачи.
— Привет, Амиго! Наконец-то мы добрались до очень интересной темы. Сегодня я расскажу тебе про . На самом деле множественное наследование очень интересный и мощный инструмент. И если бы не некоторые проблемы, то в Java было бы множественное наследование классов. Но т.к. его нет, придется довольствоваться множественным наследованием интерфейсов. Что тоже не мало.
Представь, что ты пишешь компьютерную игру. И ее герои – твои объекты – должны демонстрировать очень сложное поведение: ходить по карте, собирать предметы, выполнять квесты, общаться с другими героями, кого-то убивать, кого-то спасать. Допустим, ты смог разделить все объекты на 20 категорий. Это значит, что если тебе повезет, ты можешь обойтись всего 20-ю классами, для их описания. А теперь вопрос на засыпку: сколько всего уникальных видов взаимодействия у этих объектов. Объект каждого типа может иметь уникальные взаимодействия с 20-ю видами других объектов (себе подобных тоже считаем). Т.е. всего нужно запрограммировать 20 на 20 – 400 взаимодействий! А если уникальных видов объектов будет не 20, а 100, количество взаимодействий может достигнуть 10,000!
— Ничего себе! Теперь понимаю, почему программирование такая непростая работа.
— Она простая. Благодаря многим абстракциям. И в не последнюю очередь – множественному наследованию интерфейсов.
Очень часто можно упростить взаимодействие объектов, если взаимодействовать будут не объекты, а их роли и/или способности. А способности, как мы уже знаем, легко добавляются в класс, когда он реализует некоторый интерфейс.
Когда пишется большая программа, обычно с этого сразу и начинают:
1) Определяют все существующие способности/роли.
2) Затем описывают взаимодействие между этими ролями.
3) А потом просто наделяют все классы их ролями.
— А можно пример?
— Конечно. Давай рассмотрим роли, на основе героев мультика «Том и Джерри».
Зная всего эти три роли (интерфейса) можно написать программу и описать корректное взаимодействие этих ролей. Например, объект будет гнаться (посредством интерфейса Moveable) за тем, «кого ты можешь съесть» и убегать от того, «кто может съесть тебя». И все это без знаний о конкретных объектах. Если в программу добавить еще объектов (классов), но оставить эти роли, она будет прекрасно работать – управлять поведением своих объектов.
— Привет, Амиго! Билаабо расскажет тебе о различиях абстрактного класса и интерфейса. Их несколько.
— Вот это я понимаю. Кратко и по существу.
— Спасибо, Амиго.
— Привет, Амиго! Сейчас я тебе расскажу про два интерфейса – InputStream и OutputStream. Объявлены они как абстрактные классы, но если начать разбираться, то можно увидеть, что по своей сути – это интерфейсы. Почти все их методы абстрактные, кроме нескольких незначащих методов. Очень похожи на нашего «телохранителя», которого мы рассматривали.
Это очень интересные интерфейсы. Пока что я специально буду называть их интерфейсы, чтобы ты понял, зачем они нужны. А потом мы поговорим, почему же их все-таки сделали абстрактными классами.
— Хорошо. Так что это за интерфейсы?
— Сейчас расскажу.
Есть такая интересная вещь в Java как «поток». Поток – это очень простая сущность. И его простота есть залог очень мощного механизма обмена данными. Потоки бывают двух видов: поток для чтения и поток для записи.
В поток для записи, как ты уже, наверное, догадался, можно записывать данные. Для этого у него есть метод write(). Из потока для чтения можно данные читать. Для этого у него есть метод read().
InputStream – это интерфейс потока чтения, описывающий такую способность: «из меня можно читать байты».
А OutputStream– это, соответственно, интерфейс потока записи, описывающий способность: «в меня можно записывать байты».
— И это все?
— Фактически да. Но все дело в том, что в Java есть очень много классов, которые умеют работать с интерфейсами InputStream и OutputStream. Например, ты хочешь прочитать файл с диска и вывести его содержимое на экран. Нет ничего проще.
Представь, что мы написали класс, и добавили ему способности InputStream и OutputStream.
Если мы корректно реализовали поддержку этих интерфейсов, то объекты нашего класса теперь можно сохранить в файл на диске. Просто вычитав их содержимое через метод read. Или загрузить из файла, создав объект и записав в него содержимое файла через метод write.
Теперь добавим в него методы read и write
Это, конечно, не реализация интерфейсов InputStream и OutputStream, но очень похоже.
— Да, это понятно. А как все-таки сохранить содержимое такого объекта в файл?
— Давай я напишу тебе пример:
— Ух ты! Действительно, очень похоже на работу с InputStream/OutputStream. Потоки – это крутая вещь!
— А то!
— Я тебе что, не рассказывал про интерфейсы? Тогда ты многое потерял. Вот если замечательные лекции. Их когда-то написал мой давний друг:
Cсылка, интерфейсы, множественное наследование, абстрактные классы
— Привет, Амиго! Вот хорошее видео. Я уже два часа терплю, чтобы не смотреть. Давай быстрее сюда.
— Здорово, боец!
— Здравия желаю, товарищ генерал!
— У меня для тебя шикарная новость. Вот тебе задания для закрепления полученных навыков. Выполняй их каждый день, и твои навыки будут расти с неимоверной скоростью. Они специально разработаны для выполнения их в Intellij IDEA.
— Те задания были для духов. Для дедушек я добавил бонусные задания повышенной сложности. Только для старослужащих.
Слайд 1Решение С1 по информатике — поиск ошибок в программе со сложным
(повышенный уровень, время – 30 мин)
Слайд 2 в программе осуществлен ввод лишних данных; ошибка в операторе условия
ВОЗМОЖНЫЕ ВАРИАНТЫ ОШИБОК:
Слайд 3входные данные – числовые выражения и задание содержит три вопроса
каких входных данных программа работает неверно (вопрос для всех классов заданий С1);определить лишнюю часть представленной программы;исправить предложенную программу.входные данные – числовые выражения, но вопросов два
(т.е. в исходной части программы две ошибки);входные данные – числовые, вопросов два, оба касаются исправления программы, но второй вопрос сформулирован довольно жёстко (требует не содержать логических функций и т.д.)входные данные – строковые переменные, а в остальном соответствует первому классу заданий С1.
Классификация заданий С1
Слайд 4Задача№1. Требовалось написать программу, при выполнении которой с клавиатуры считываются координаты
точки на плоскости (x, y — действительные числа) и определяется принадлежность этой точки заданной заштрихованной области (включая границы). Программист торопился и написал программу неправильно.
Слайд 5Перерисуйте и заполните таблицу, которая показывает, как работает программа при аргументах,
принадлежащих различным областям (A, B, C, D, E, F, G и H).Точки, лежащие на границах областей, отдельно не рассматривать. В столбцах условий укажите «да», если условие выполнится, «нет», если условие не выполнится, «—» (прочерк), если условие не будет проверяться, «не изв.», если программа ведет себя по-разному для разных значений, принадлежащих данной области. В столбце «Программа выведет» укажите, что программа выведет на экран. Если программа ничего не выводит, напишите «—» (прочерк). Если для разных значений, принадлежащих области, будут выведены разные тексты, напишите «не изв». В последнем столбце укажите «да» или «нет».Укажите, как нужно доработать программу, чтобы не было случаев ее неправильной работы. (Это можно сделать несколькими способами, достаточно указать любой способ доработки исходной программы.)
Последовательно выполните
следующее:
Слайд 6Элементы ответа
Слайд 8Возможная доработка (Паскаль, разбиение области на две части прямой x =
Слайд 9Задача №2. Требовалось написать программу, которая решает уравнение «a |x|
= 6» относительно х для любых чисел а и b, введенных с клавиатуры. Все числа считаются действительными. Программист торопился и написал программу неправильно.
Последовательно выполните три задания: Приведите пример таких чисел a, b, x, при которых программа неверно решает поставленную задачу.Укажите, какая часть программы является лишней.Укажите, как нужно доработать программу, чтобы не было случаев ее неправильной работы. (Это можно сделать несколькими способами, поэтому можно указать любой способ доработки исходной программы).
Слайд 10Пояснениеa = 1, b = −1, x = 0. Значение x может
быть не указано. Значения а и b могут быть любыми ненулевыми числами с разными знаками. Ошибка программиста состоит в том, что программаработает неправильно при любых ненулевых а и Ь, имеющих разные знаки.
Лишняя часть: не нужно вводить х с клавиатуры; верно: readln(a, Ь).
Слайд 11Задача№3 Требовалось написать программу, при выполнении которой с клавиатуры считываются координаты
точки на плоскости (x, y — действительные числа) и определяется принадлежность этой точки заданной закрашенной области (включая границы). Ученик написал такую программу:
Слайд 12При проверке работы программа выполнялась по шагам для некоторых контрольных значений
х и у, при этом был заполнен протокол тестирования. В результате неаккуратного обращения протокол был испорчен, частично сохранились только четыре строки:
Последовательно выполните следующее.Восстановите уцелевшие строки протокола, заполнив все клетки таблицы. Там, где содержание восстанавливается неоднозначно, запишите любое возможное значение. Например, если для нескольких областей получается одинаковая строка таблицы, укажите в графе «Область» любую из этих областей.2. Укажите, как нужно доработать программу, чтобы не было случаев её неправильной работы.
Слайд 13Пояснение2. Для написания правильной программы необходимо разделить требуемую область на части
и описать каждую из них. Например, можно выделить области FGLM, HN и QR. При этом получается такой фрагмент программы (пример на Паскале):
Слайд 15Задача№4Требовалось написать программу, при выполнении которой с клавиатуры считывается натуральное число
N, не превосходящее 109, и выводится количество цифр этого числа. Программист торопился и написал программу неправильно.
1. Напишите, что выведет эта программа при вводе числа 584.
3. Укажите одно число для которого эта программа будет работать верно.
2. Найдите все ошибки в этой программе (их может быть одна или несколько). Укажите все строки (одну или более), содержащие ошибки, и для каждой такой строки приведите правильный вариант. Обратите внимание, что требуется найти ошибки в имеющейся программе, а не написать свою, возможно, использующую другой алгоритм решения. Исправление ошибки должно затрагивать только строку, в которой находится ошибка.