Джава-12
Привет. Напоминаю в рамках тега изучениеджава (хейтерам банить именно его) я вместе с вами изучаю основы джава. Внезапно интернет у меня стал по карточкам (да-да, мамка наказала). Поэтому периодичность постинга будет завязана на великих шнурках рандома. Продлится это максимум до сентября. Прошу прощения за неудобства. Сегодня узнаем о предотвращении наследования и приведении типов.
В прошлом посте упоминалось динамическое связывание (иногда называемое поздним), суть которого заключается в выборе метода по фактическому типу объекта. Так метод punish для kotuk объявленного как Cat, вызывался из подкласса CatMutant.
Добавим в класс Cat метод, возвращающий имя. Навряд ли при наследовании его придётся каким-либо образом менять. Но вдруг мы забудем, что такой метод существует в суперклассе, и случайно его переопределим (при этом забыв какую-нибудь ключевую деталь), чего нам очень не хочется? Для предотвращения данной ситуации можно использовать ключевое слово final, тогда можно быть уверенным, что метод getName будет работать одинаково в любом случае.
Методы и классы с ключевым словом final называются конечными.
Как стало понятно тоже можно сделать и с классом. Например, класс String является конечным, и, используя один из методов класса String, мы ссылаемся именно на символьную строку. В противном случае можно было бы наследовать класс String (пусть будет подкласс Chars), переопределить метод N, объявить переменную типа String, присвоить ей экземпляр класса Char и в будущем не понимать, почему метод N работает не так, как с другими объектами класса String (вспомните про динамическое связывание).
Теперь о приведение типов. Приведением типов называется процесс принудительного преобразования из одного типа в другой. Вот код, который написал джек:
В первых трех строках кода красным выделено имя переменной типа CatMutant, чёрным тип переменной. В первой строке мы присваиваем переменной типа Cat переменную типа CatMutant. Компилятор позволяет нам это сделать, однако запоминает фактический тип переменной. Мы какбы говорим компилятору, ты используй эту переменную, но не обращай внимания на его дополнительные возможности.
Однако, он не позволит присвоить эту переменную (cat_CatMutant), переменной типа CatMutant – компилятор не обращает внимание на доп. возможности. Поэтому при компиляции возникнет ошибка (во второй строке).
Чтобы ошибки не возникало используется конструкция из третей строки. Указывая в скобках тип, к которому мы хотим привести переменную, мы говорим компилятору – помнишь я просил тебя забыть о дополнительных возможностях, нужно о них вспомнить.
Теперь обратимся ко вторым трём строкам. Вторая строка аналогично абзацу выше. Но третья строка хоть и скомпилируется при выполнении программы выдаст ошибку. Компилятор ответит нам – ты меня обманываешь, нельзя переменную (с реальным типом Cat) привести к CatMutant.
На этом всё, спасибо за внимание.
Джава-11
Привет. Напоминаю в рамках тега изучениеджава (хейтерам банить именно его) я вместе с вами изучаю основы джава. Внезапно интернет у меня стал по карточкам (да-да, мамка наказала). Поэтому периодичность постинга будет завязана на великих шнурках рандома. Продлится это максимум до сентября. Прошу прощения за неудобства.
В прошлом посте мы узнали о наследовании и создали подкласс для класса Cat. К тому же в коде было допущено несколько ошибок, которых я изначально не заметил, надеюсь, в комментариях меня поправили. Сегодня узнаем о полиморфизме и связывании. Изображения с кодом я выкладывать не буду, потренируйтесь самостоятельно писать код.
В классе CatMutant создайте private переменную целочисленного типа Eyes и public метод addEye, который увеличивает переменную Eyes на единицу.
Создайте в основном классе экземпляр класса CatMutant с именем komuk и массив типа Cat размерностью два. Первому элементу массива создайте и присвойте экземпляр класса Cat, а второму komuk. Как вы можете видеть, компилятор позволил присвоить переменной суперкласса (Cats[1]) переменную подкласса (komuk). Эта способность переменной называется полиморфизмом - любая объектная переменная может ссылаться на переменную подкласса.
Теперь попробуйте вызвать Cats[1].addEye, компилятор выдаст ошибку, т.к. тип переменной Cats[1] – Cat и такого метода в классе не существует. Однако если вы вызовете метод punish, то второй элемент может восстановить ногу. Дело в том, что вместе с массивом хранятся тип каждого из элементов и при вызове метода компилятор выполняет следующие действия:
* компилятор проверяет тип элемента и имя метода. Затем ищет все доступные методы под именем метода в классе элемента и во всех его суперклассах.
* затем компилятор разрешает перегрузку методов – по типу передаваемых параметров выбирает метод, которому эти параметры подходят.
* если метод является конструктором или имеет модификатор private, static или final, то компилятору точно известно как вызвать метод (статическое связывание), иначе метод выбирается исходя из типа элемента (динамическое/позднее связывание).
* если используется динамическое связывание, то ищется метод класса, к которому принадлежит элемент. Если в классе такого метода нет, то метод ищется в суперклассе, если его нет в суперклассе, то виртуальная машина идёт вверх по иерархии пока не найдёт метод. Когда метод найден, он вызывается.
На примере Cats[1].getName. Во время вызова этого метода пытается найти метод getName в классе CatMutant, но не находя его обращается к суперклассу Cat. Откуда и выполняется метод.
Выполняем задание на Abstract Factory Pattern часть 2
Представляю Вам вторую часть задания по абстрактной фабрике - Битва танков.
В программе появился учет скоростей разворота и перезарядки танков, небольшие отчеты по совершенным действиям танков, танков теперь 5л+3с+1т. Бои проходя также один на один, но пока разворачивается, к примеру, тяжелый танк легкий успевает его прилично повредить. У танков появились очки хода, которые они тратят на действия. И немного подробнее будет изложено ниже.
Изменена структура проекта:
По замечаниям в прошлых постах исправлены фабрики - теперь для выбора типа танка используется enum:
Мммм...можно почитать тут:
Сильно переработан класс Tank - armor перенесен в абстрактный класс, добавлены переменные curDislocation, actionPoints, создан метод public void doAction(Tank tank), исправлен конструктор с учетом новых переменных:
Изменения коснулись, соответственно, и классов-наследников Tank.
И переработана сама программа TankBattle - танков теперь больше, бой идет, пока одна из сторон не уничтожена, появилась система раздачи очков действий и пауза - 1 секунда перед каждой раздачей, из-за чего появился выброс исключения, часть операций перенесена внутрь классов:
И пример боя:
Начался бой между USSR_MEDIUM и GERMAN_MEDIUM
USSR_MEDIUM расположение - 1
GERMAN_MEDIUM расположение - 0
GERMAN_MEDIUM нанес 50 урона. У противника осталось 150 очков жизни.
GERMAN_MEDIUM нанес 50 урона. У противника осталось 100 очков жизни.
USSR_MEDIUM развернулся.
USSR_MEDIUM нанес 50 урона. У противника осталось 150 очков жизни.
GERMAN_MEDIUM нанес 50 урона. У противника осталось 50 очков жизни.
USSR_MEDIUM нанес 50 урона. У противника осталось 100 очков жизни.
GERMAN_MEDIUM нанес 50 урона. У противника осталось 0 очков жизни.
USSR_MEDIUM уничтожен.
Начался бой между USSR_MEDIUM и GERMAN_MEDIUM
USSR_MEDIUM расположение - 1
GERMAN_MEDIUM расположение - 1
USSR_MEDIUM развернулся.
GERMAN_MEDIUM развернулся.
USSR_MEDIUM нанес 50 урона. У противника осталось 50 очков жизни.
GERMAN_MEDIUM нанес 50 урона. У противника осталось 150 очков жизни.
USSR_MEDIUM нанес 50 урона. У противника осталось 0 очков жизни.
GERMAN_MEDIUM уничтожен.
Начался бой между USSR_LIGHT и GERMAN_LIGHT
USSR_LIGHT расположение - 1
GERMAN_LIGHT расположение - 1
USSR_LIGHT развернулся.
GERMAN_LIGHT развернулся.
USSR_LIGHT нанес 27 урона. У противника осталось 73 очков жизни.
GERMAN_LIGHT нанес 27 урона. У противника осталось 73 очков жизни.
USSR_LIGHT нанес 27 урона. У противника осталось 46 очков жизни.
GERMAN_LIGHT нанес 27 урона. У противника осталось 46 очков жизни.
USSR_LIGHT нанес 27 урона. У противника осталось 19 очков жизни.
GERMAN_LIGHT нанес 27 урона. У противника осталось 19 очков жизни.
USSR_LIGHT нанес 27 урона. У противника осталось -8 очков жизни.
GERMAN_LIGHT уничтожен.
Начался бой между USSR_LIGHT и GERMAN_MEDIUM
USSR_LIGHT расположение - 1
GERMAN_MEDIUM расположение - 1
USSR_LIGHT развернулся.
USSR_LIGHT нанес 20 урона. У противника осталось 180 очков жизни.
USSR_LIGHT нанес 20 урона. У противника осталось 160 очков жизни.
GERMAN_MEDIUM развернулся.
USSR_LIGHT нанес 20 урона. У противника осталось 140 очков жизни.
GERMAN_MEDIUM нанес 57 урона. У противника осталось 43 очков жизни.
USSR_LIGHT нанес 20 урона. У противника осталось 120 очков жизни.
USSR_LIGHT нанес 20 урона. У противника осталось 100 очков жизни.
GERMAN_MEDIUM нанес 57 урона. У противника осталось -14 очков жизни.
USSR_LIGHT уничтожен.
Начался бой между USSR_LIGHT и GERMAN_LIGHT
USSR_LIGHT расположение - 1
GERMAN_LIGHT расположение - 1
USSR_LIGHT развернулся.
GERMAN_LIGHT развернулся.
USSR_LIGHT нанес 27 урона. У противника осталось 73 очков жизни.
GERMAN_LIGHT нанес 27 урона. У противника осталось 73 очков жизни.
USSR_LIGHT нанес 27 урона. У противника осталось 46 очков жизни.
GERMAN_LIGHT нанес 27 урона. У противника осталось 46 очков жизни.
USSR_LIGHT нанес 27 урона. У противника осталось 19 очков жизни.
GERMAN_LIGHT нанес 27 урона. У противника осталось 19 очков жизни.
USSR_LIGHT нанес 27 урона. У противника осталось -8 очков жизни.
GERMAN_LIGHT уничтожен.
Начался бой между USSR_LIGHT и GERMAN_LIGHT
USSR_LIGHT расположение - 0
GERMAN_LIGHT расположение - 0
USSR_LIGHT нанес 27 урона. У противника осталось 73 очков жизни.
GERMAN_LIGHT нанес 27 урона. У противника осталось 73 очков жизни.
USSR_LIGHT нанес 27 урона. У противника осталось 46 очков жизни.
GERMAN_LIGHT нанес 27 урона. У противника осталось 46 очков жизни.
USSR_LIGHT нанес 27 урона. У противника осталось 19 очков жизни.
GERMAN_LIGHT нанес 27 урона. У противника осталось 19 очков жизни.
USSR_LIGHT нанес 27 урона. У противника осталось -8 очков жизни.
GERMAN_LIGHT уничтожен.
Начался бой между USSR_LIGHT и GERMAN_LIGHT
USSR_LIGHT расположение - 1
GERMAN_LIGHT расположение - 0
USSR_LIGHT развернулся.
GERMAN_LIGHT нанес 27 урона. У противника осталось -8 очков жизни.
USSR_LIGHT уничтожен.
Начался бой между USSR_LIGHT и GERMAN_LIGHT
USSR_LIGHT расположение - 0
GERMAN_LIGHT расположение - 1
USSR_LIGHT нанес 27 урона. У противника осталось 73 очков жизни.
GERMAN_LIGHT развернулся.
USSR_LIGHT нанес 27 урона. У противника осталось 46 очков жизни.
GERMAN_LIGHT нанес 27 урона. У противника осталось -8 очков жизни.
USSR_LIGHT уничтожен.
Начался бой между USSR_LIGHT и GERMAN_MEDIUM
USSR_LIGHT расположение - 0
GERMAN_MEDIUM расположение - 1
USSR_LIGHT нанес 20 урона. У противника осталось 180 очков жизни.
USSR_LIGHT нанес 20 урона. У противника осталось 160 очков жизни.
USSR_LIGHT нанес 20 урона. У противника осталось 140 очков жизни.
USSR_LIGHT нанес 20 урона. У противника осталось 120 очков жизни.
GERMAN_MEDIUM развернулся.
USSR_LIGHT нанес 20 урона. У противника осталось 100 очков жизни.
GERMAN_MEDIUM нанес 57 урона. У противника осталось 43 очков жизни.
USSR_LIGHT нанес 20 урона. У противника осталось 80 очков жизни.
USSR_LIGHT нанес 20 урона. У противника осталось 60 очков жизни.
GERMAN_MEDIUM нанес 57 урона. У противника осталось -14 очков жизни.
USSR_LIGHT уничтожен.
Начался бой между USSR_MEDIUM и GERMAN_LIGHT
USSR_MEDIUM расположение - 1
GERMAN_LIGHT расположение - 0
GERMAN_LIGHT нанес 20 урона. У противника осталось 130 очков жизни.
GERMAN_LIGHT нанес 20 урона. У противника осталось 110 очков жизни.
GERMAN_LIGHT нанес 20 урона. У противника осталось 90 очков жизни.
USSR_MEDIUM развернулся.
GERMAN_LIGHT нанес 20 урона. У противника осталось 70 очков жизни.
USSR_MEDIUM нанес 57 урона. У противника осталось -11 очков жизни.
GERMAN_LIGHT уничтожен.
Начался бой между USSR_LIGHT и GERMAN_LIGHT
USSR_LIGHT расположение - 0
GERMAN_LIGHT расположение - 1
USSR_LIGHT нанес 27 урона. У противника осталось 73 очков жизни.
USSR_LIGHT нанес 27 урона. У противника осталось 46 очков жизни.
GERMAN_LIGHT развернулся.
USSR_LIGHT нанес 27 урона. У противника осталось 19 очков жизни.
GERMAN_LIGHT нанес 27 урона. У противника осталось -8 очков жизни.
USSR_LIGHT уничтожен.
Начался бой между USSR_MEDIUM и GERMAN_LIGHT
USSR_MEDIUM расположение - 1
GERMAN_LIGHT расположение - 1
GERMAN_LIGHT развернулся.
GERMAN_LIGHT нанес 20 урона. У противника осталось 50 очков жизни.
USSR_MEDIUM развернулся.
GERMAN_LIGHT нанес 20 урона. У противника осталось 30 очков жизни.
USSR_MEDIUM нанес 57 урона. У противника осталось -38 очков жизни.
GERMAN_LIGHT уничтожен.
Начался бой между USSR_MEDIUM и GERMAN_MEDIUM
USSR_MEDIUM расположение - 1
GERMAN_MEDIUM расположение - 1
USSR_MEDIUM развернулся.
USSR_MEDIUM нанес 50 урона. У противника осталось 10 очков жизни.
GERMAN_MEDIUM развернулся.
GERMAN_MEDIUM нанес 50 урона. У противника осталось -20 очков жизни.
USSR_MEDIUM уничтожен.
Начался бой между USSR_MEDIUM и GERMAN_MEDIUM
USSR_MEDIUM расположение - 1
GERMAN_MEDIUM расположение - 0
GERMAN_MEDIUM нанес 50 урона. У противника осталось 150 очков жизни.
GERMAN_MEDIUM нанес 50 урона. У противника осталось 100 очков жизни.
USSR_MEDIUM развернулся.
USSR_MEDIUM нанес 50 урона. У противника осталось 50 очков жизни.
GERMAN_MEDIUM нанес 50 урона. У противника осталось 50 очков жизни.
USSR_MEDIUM нанес 50 урона. У противника осталось 0 очков жизни.
GERMAN_MEDIUM уничтожен.
Начался бой между USSR_MEDIUM и GERMAN_MEDIUM
USSR_MEDIUM расположение - 0
GERMAN_MEDIUM расположение - 0
USSR_MEDIUM нанес 50 урона. У противника осталось -40 очков жизни.
GERMAN_MEDIUM уничтожен.
Начался бой между USSR_MEDIUM и GERMAN_HEAVY
USSR_MEDIUM расположение - 0
GERMAN_HEAVY расположение - 0
USSR_MEDIUM нанес 40 урона. У противника осталось 460 очков жизни.
GERMAN_HEAVY нанес 90 урона. У противника осталось -40 очков жизни.
USSR_MEDIUM уничтожен.
Начался бой между USSR_HEAVY и GERMAN_HEAVY
USSR_HEAVY расположение - 1
GERMAN_HEAVY расположение - 1
GERMAN_HEAVY развернулся.
USSR_HEAVY развернулся.
GERMAN_HEAVY нанес 80 урона. У противника осталось 420 очков жизни.
USSR_HEAVY нанес 80 урона. У противника осталось 380 очков жизни.
GERMAN_HEAVY нанес 80 урона. У противника осталось 340 очков жизни.
USSR_HEAVY нанес 80 урона. У противника осталось 300 очков жизни.
GERMAN_HEAVY нанес 80 урона. У противника осталось 260 очков жизни.
USSR_HEAVY нанес 80 урона. У противника осталось 220 очков жизни.
GERMAN_HEAVY нанес 80 урона. У противника осталось 180 очков жизни.
USSR_HEAVY нанес 80 урона. У противника осталось 140 очков жизни.
GERMAN_HEAVY нанес 80 урона. У противника осталось 100 очков жизни.
USSR_HEAVY нанес 80 урона. У противника осталось 60 очков жизни.
GERMAN_HEAVY нанес 80 урона. У противника осталось 20 очков жизни.
USSR_HEAVY нанес 80 урона. У противника осталось -20 очков жизни.
GERMAN_HEAVY уничтожен.
App.Tanks.Ussr.UssrHeavyTank@677327b6
Все танки Германии уничтожены!
Исходники программы: https://github.com/Norfin85/TankBattle
Быстрая нейронная сеть для каждого
Данный пост продемонстрирует возможность легко написать свою нейронную сеть на языке Javа. Дабы не изобретать велосипед, возьмем уже хорошо проработанную библиотеку Fast Artificial Neural Network. Использование нейронных сетей в своих Java-проектах — реально. Часто можно услышать упреки в адрес Java касательно скорости выполнения. Мы будем использовать обертку вокруг библиотеки FANN.
Задача
Необходимо написать систему, которая сможет принимать решения за персонажа, который может встретить одного или несколько врагов. Системе может быть известно:
здоровье персонажа в процентах;
наличие пистолета;
количество врагов.
Ответ должен быть в виде одного из действий:
атаковать;
бежать;
прятаться (для внезапной атаки);
ничего не делать.
Для обучения составим таблицу «уроков»:
Здоровье пистолет Враги Действие
50% 1 1 Атаковать
90% 1 2 Атаковать
80% 0 1 Атаковать
30% 1 1 Прятаться
60% 1 2 Прятаться
40% 0 1 Прятаться
90% 1 7 Бежать
60% 1 4 Бежать
10% 0 1 Бежать
60% 1 0 Ничего
100% 0 0 Ничего
Подготовка
Первое, что нужно сделать — собрать и установить libfann.
Затем скачать fannj и jna.
Сделаем файл, который будет содержать набор «уроков»:
11 3 4
0.5 1 1
1 0 0 0
0.9 1 2
1 0 0 0
0.8 0 1
1 0 0 0
0.3 1 1
0 1 0 0
0.6 1 2
0 1 0 0
0.4 0 1
0 1 0 0
0.9 1 7
0 0 1 0
0.5 1 4
0 0 1 0
0.1 0 1
0 0 1 0
0.6 1 0
0 0 0 1
1.0 0 0
0 0 0 1
Теперь обучим нашу ИНС и сохраним ее в файл:
public static void main(String[] args) {
//Для сборки новой ИНС необходимо создасть список слоев
List<Layer> layerList = new ArrayList<Layer>();
layerList.add(Layer.create(3, ActivationFunction.FANN_SIGMOID_SYMMETRIC, 0.01f));
layerList.add(Layer.create(16, ActivationFunction.FANN_SIGMOID_SYMMETRIC, 0.01f));
layerList.add(Layer.create(4, ActivationFunction.FANN_SIGMOID_SYMMETRIC, 0.01f));
Fann fann = new Fann(layerList);
//Создаем тренера и определяем алгоритм обучения
Trainer trainer = new Trainer(fann);
trainer.setTrainingAlgorithm(TrainingAlgorithm.FANN_TRAIN_RPROP);
/* Проведем обучение взяв уроки из файла, с максимальным колличеством
циклов 100000, показывая отчет каждую 100ю итерацию и добиваемся
ошибки меньше 0.0001 */
trainer.train(new File("train.data").getAbsolutePath(), 100000, 100, 0.0001f);
fann.save("ann");
}
Пояснение
Layer
ИНС состоит из слоев нейронов. Первый слой — это нейроны «рецепторы» или нейроны входных данных. Последний слой нейронов выходных данных. Все остальные — это скрытые слои. В нашем случае первый слой имеет 3 нейрона:
уровень здоровья (0.1-1.0);
наличие оружия (1-есть, 0-нету);
количество врагов.
Fann
Объект класса Fann это и есть нейронная сеть, которая создается на основе созданных ранее слоев.
Trainer
Объект класса тренер инкапсулирует алгоритмы обучения нейронной сети переданной при создании тренера. После обучения не забываем сохранить ее в файл.
Проверка результатов
Для проверки нашего обучения воспользуемся следующим кодом:
public static void main(String[] args) {
Fann fann = new Fann("ann");
float[][] tests = {
{1.0f, 0, 1},
{0.9f, 1, 3},
{0.3f, 0, 8},
{1, 1, 8},
{0.1f, 0, 0},
};
for (float[] test:tests){
System.out.println(getAction(fann.run(test)));
}
}
private static String getAction(float[] out){
int i = 0;
for (int j = 1; j < 4; j++) {
if(out[i]<out[j]){
i = j;
}
}
switch (i){
case 0:return "атаковать";
case 1:return "прятаться";
case 2:return "бежать";
case 3:return "ничего не делать";
}
return "";
}
Буду рад услышать конструктивную критику.
Выполняем задание на Abstract Factory Pattern часть 1
В первой части мы создадим абстрактную фабрику танков, по одному экземпляру каждого танка и проведем бой между случайными танками СССР и Германии.
Структура программы:
Весь код программы находится по адресу: https://github.com/Norfin85/TankBattle
Опишу лишь пару, на мой, взгляд интересных моментов.
Момент 1:
Классы LightUssrTank, MediumUssrTank, HeavyUserTank имеют различный показатель armor. Все переменные в классах имеют модификатор private, а значит объявление переменной должно происходить в классе . Но UssrFactory возвращает объекты класса Tank, а значит поле armor будет недоступно в этих объектах. Эту проблему можно решить следующим образом:
В абстрактом классе Tank объявляется абстрактная функция getArmor:
А в конкретных класса объявляется переменная armor и реализация функции getArmor:
Момент 2: в абстрактом классе задается конструктор, а в классе-наследнике UssrMediumTank он используется используя ключевое слово super(), при этом класс UssrMediumTank имеет свой конструктор с большим количеством полей. Это позволяет нам объединять общие параметры для всех классов-наследников в один общий абстрактный класс.
И сама главная программа:
Программа пока очень громоздкая и не учитывает скорость стрельбы при встрече лоб в лоб. Это все будет исправлено во второй части путем создания таймера боя и очков действия танков. Также внутрь объектов будет помещена их ориентация.
И еще некоторые модификации...)
Размышления об Искуственном интеллекте
Я изучаю java программирование.
Честно признаться, нахожусь на самом начальном уровне. Меня даже трудно назвать личинкой программиста))).
Написал код, где программа сообщает мне, что 2 не равно 3.
Вот он:
class proba {
public static void main(String[] args) {
int x = 2;
if (x == 3) {
System.out.println("2 равно 3");
} else {
System.out.println("2 не равно 3");
}
}
}
И вот тут мне пришло в голову, что я могу заставить эту программу обмануть меня. Она будет знать, что 2 НЕ равно 3, но скажет мне другое...
class proba {
public static void main(String[] args) {
int x = 2;
if (x == 3) {
System.out.println("2 равно 3");
} else {
System.out.println("2 равно 3");
}
}
}
Мы называем ложью, когда, зная и думая одно, говорим другое... В данной ситуации программа ЗНАЕТ одно, но говорит другое...
Я понимаю, это довольно примитивный пример искуственного интеллекта, но тем не менее...
P.S.Компиляция и запуск через cmd.
P.P.S. Прошу учесть факт, что это не анализ, или утверждение. Просто свежий (может не верный) взгляд человека, который совсем недавно с головой окунулся во все это таинство)))
Джава-10
Привет. Напоминаю в рамках тега изучениеджава (хейтерам банить именно его) я вместе с вами изучаю основы джава. Внезапно интернет у меня стал по карточкам (да-да, мамка наказала). Поэтому периодичность постинга будет завязана на великих шнурках рандома. Продлится это максимум до сентября (уже точно). Прошу прощения за неудобства.
В прошлом посте мы начали изучать основы ООП и написали класс Cat. Сегодня мы продолжим работать в этом направлении. Для начала сотрём несколько конструкторов, оставив только тот, у которого все четыре свойства задаются аргументами, уберём у свойства birthday ключевое слово final (почему объясню как-нибудь потом), а также удалим свойство sex (глаза мозолит, а толку нет).
Теперь напишем функцию, которая будет уменьшать количество ног у котика. Однако, мы всё-таки на пикабу, а здесь котиков любят. Поэтому котик сохранит ногу, если у него день рождения текущей датой.
Добавим и методы возвращающие дату и количество ног кота, а также изменяющий количество ног. Соответствующе изменим метод punish
А теперь мы переходим к такому понятию ООП как наследование. На свете существует огромное количество разновидностей кошек: кошки-мутанты, кошки-геи, кошки-веганы. И каждой разновидности есть какие-либо особенности. Мутанты, например, умеют летать, геев нельзя наказывать, у веганов нестандартный рацион. Конечно, можно создать массив {«гей», «веган»…} и проверять, например, в методе полёта, является ли котик мутантом, но это создаёт большое количество сложностей\проблем для понимания\ведения кода.
Гораздо легче объявить новый класс и добавить или изменить (переопределить) методы.
Итак, создадим новый класс CatMutant, который будет расширять (extends) класс Cat.
Отличие будет в методе punish, в конце мы добавим вероятность отращивания новой ноги, если умножение минуты наказания на секунду даст число кратное трём.
В результате мы будем иметь следующий код:
Пока всё. Попробуйте создать экземпляры каждого из классов. Придумайте что-нить интересное.
p.s. юухзой в говнишу, сори если чё напутал