Zer0Galaxy 2 127 Опубликовано: 11 июня, 2014 В данной статье я хотел бы показать, как можно применять объектно-ориентированный подход при программировании на lua. Если Вы ранее не сталкивались с ООП в других языках, статья вряд ли станет Вам полезной ибо не предназначена для обучения объектно-ориентированному мышлению, а лишь приводит пример реализации объектов. Lua не относится к объектно-ориентированным языкам, поскольку не содержит стандартных механизмов создания и использования объектов. Но lua-таблица является настолько гибким инструментом, что позволяет реализовать практически любую структуру, присущую другим языкам. В том числе и объекты. Прежде чем создавать экземпляры объекта, необходимо описать соответствующий ему класс. ClassA={} ClassA.__index=ClassAПо большому счету, называть это классом нельзя, поскольку класс — это абстракция, служащая шаблоном для создания объекта. Сдесь же мы имеем дело с вполне реальной таблицей. Поэтому ClassA будем называть объектом-прототипом.Как видите, я не описал никаких полей объекта-прототипа т. к. в отличии от таких языков как Delphi и C++, поля таблицы в lua можно описывать когда угодно, а не только при создании таблицы. Поля будем прописывать в конструкторе класса при создании экземпляра объекта. Единственное поле __index содержит указатель на сам класс. Это нужно будет для правильной работы оператора self. Создадим конструктор: function ClassA:new(_Name) local obj={Name = _Name} setmetatable(obj,self) print('Constructor ClassA for '..obj.Name) return obj endЧто делает конструктор?Строка 1. Создает экземпляр теперь уже объекта, описывает поля объекта и присваивает полям начальные значения. Строка 2. Переопределяет метатаблицу вновь созданного объекта, в результате чего объект получает доступ к методам класса. Методов пока нет, но они будут описаны позже. Строка 3. Это необязательная строка. Я ее сюда вставил для демонстрации работы конструктора. Строка 4. Возвращает созданный объект. Теперь создадим парочку методов: function ClassA:Metod1() print('Metod1 of ClassA for '..self.Name) end function ClassA:Metod2() print('Metod2 of ClassA for '..self.Name) endЗачем два? В дальнейшем один из них будет наследован, а другой перекрыт методом наследника. И так, мы создали объект-прототип. Пора создавать экземпляры объекта. Экземпляры будем хранить в таблице objects. Для создания экземпляра вызываем конструктор objects={} for i = 1,2 do objects[i] = ClassA:new('Object#'..i) end Смотрим что получилось for i=1,2 do objects[i]:Metod1() objects[i]:Metod2() end Вот программа в полном сборе. ClassA={} ClassA.__index=ClassA function ClassA:new(_Name) local obj={Name = _Name} setmetatable(obj,self) print('Constructor ClassA for '..obj.Name) return obj end function ClassA:Metod1() print('Metod1 of ClassA for '..self.Name) end function ClassA:Metod2() print('Metod2 of ClassA for '..self.Name) end objects={} for i = 1,2 do objects[i] = ClassA:new('Object#'..i) end for i=1,2 do objects[i]:Metod1() objects[i]:Metod2() end Если все сделано правильно, после запуска программы Вы должны наблюдать вот такие сообщения: [ATTACH]115[/ATTACH] В следующий раз я расскажу о наследовании методов объекта и их полиморфизме. 2 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Zer0Galaxy Автор темы 2 127 Опубликовано: 12 июня, 2014 В прошлый раз мы научились создавать объекты в lua и вызывать их методы. Нами был создан класс ClassA (хорошо, не класс, а объект-прототип), имеющий одно поле (Name) и два метода (Metod1, Metod2). Были созданы два экземпляра объектов и вызваны их методы. Сегодня мы попытаемся создать наследника от ClassA, добавим ему еще одно поле, унаследуем один из методов без изменений, а второй переопределим. Так же как и класс-родитель, наследник изначально представляет собой пустую таблицу: ClassB={} ClassB.__index=ClassB setmetatable(ClassB,ClassA)После выполнения setmetatable, ClassB внешне будет представлять собой точную копию ClassA, т. е. унаследует все его методы.Изменения начнем с конструктора function ClassB:new(_Name,_Size) local obj=ClassA:new(_Name) obj.Size=_Size setmetatable(obj,self) print('Constructor ClassB for '..obj.Name) return obj endКаковы отличия в конструкторах родителя и наследника? Как видим, для создания объекта наследник использует конструктор родителя, а не создает объект «с нуля». Это конечно не обязательно, но такова классика. Другое отличие — новое поле, которое будет хранить воображаемый размер нашего объекта.Переходим к методам. Metod1, как и договаривались оставляем нетронутым, а вот Metod2 переопределим. function ClassB:Metod2() ClassA.Metod2(self) --inherited print('Metod2 of ClassB for '..self.Name..'. Size is '..self.Size) endТут я показал как из метода объекта-наследника вызвать метод объекта-родителя. Но это тоже при необходимости.Вот собственно и всё. Помимо ранее созданных объектов ClassA, создаем еще два экземпляра нового объекта objects={} for i = 1,2 do objects[i] = ClassA:new('Object#'..i) end for i = 3,4 do objects[i] = ClassB:new('Object#'..i, i*i) endИ посмотрим что получилось for i=1,4 do objects[i]:Metod1() objects[i]:Metod2() endУ меня получилось вот что:[ATTACH]116[/ATTACH] Обращаю внимание, что для объектов 3 и 4 конструктор и Metod2 выполняются дважды — сначала от ClassA, затем от ClassB. Мы рассмотрели такие особенности ООП как наследование и полиморфизм. А вот как реализовать на lua сокрытие данных объекта от доступа извне (по моему, это называется инкапсуляцией) я пока не знаю. Если знаете — пишите. Для тех кто все таки решил попробовать себя в объектно-ориентированном программировании, напоминаю — следите за пунктуацией. Имя поля отделяем точкой, имя метода — двоеточием. Это важно. 4 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Alex 4 683 Опубликовано: 3 июня, 2015 Нашел в Блоге еще записи о программировании в стиле ООП на луа, но там как-то все сумбурно. Дмитрий, Вячеслав. Просьба! Напишите понятным языком, как оно должно выглядеть на примере. Я там попросил в блоге Вячеслава, чтобы вы нам, нубасам, объяснили про метаметоды и прочее, приват и паблик свойства, как избавиться от двоеточия без явного указания аргумента self или чего там. Вот мол, молоток, вот гвоздь, забивается он так-то и так-то. Не знаю, правда, нужна ли эта абракадабра для наших черепашек , я лично обхожусь программками маленькими, написанными в процедурном стиле, мне этого хватает с головой, но все же. Видимо для больших проектов, сложных графических интерфейсов и прочего можно применить парадигму ООП. Если там грамотный и мощный класс сконструирован с кучей полезных методов, почему и не использовать их при создании уже своих классов с наследованием. Может, народ будет создавать объекты с описанием свойств реакторов, и писать им методы отгрузки топлива и управления мощностью. Не сильно даже пока понимаю, где оно нужно. вот, что пока понятно простому обычному человеку и мне в частности, если что не так, поправьте, что я тут написал: term = require('term') term.clear() --Создадим два класса, родительский и класс потомок -- ==========Cоздадим класс Игроки, это родительский класс=============== -- примечание: Я создал класс Игроки, но это не абстрактный класс, так как он позволяет создавать непосредственно -- экземляр класса, то есть конкрентый объект. Абтрактные классы можно только наследовать и они должны -- иметь хотя бы один абстрактный метод, но и производным классом его назвать нельзя, видимо, так как он ни от -- какого класса не наследует ни свойств, ни методов. print('============ ВЫПОЛНЕНИЯ ПРОГРАММКИ ===========') ClassPlayers = {} -- теперь проинициализируем поля, процедуры и фунции нашего класса function ClassPlayers:new(age, uuid, ip) local obj = {} obj.age = age or nil -- возраст, по умолчанию nil obj.uuid = uuid or 'uuid' -- по умолчанию 'uuid' obj.ip = ip or '1.1.1.1' -- по умолчанию '1.1.1.1' --далее превращаем таблицу в класс setmetatable(obj,self) self.__index = self return obj -- возвращаем наш объект (экземпляр класса) end -- функция получения свойств function ClassPlayers:get() return self.age, self.uuid, self.ip end -- функция изменения свойств function ClassPlayers:set(age, uuid, ip) self.age = age self.uuid = uuid self.ip = ip end -- создадим наших первых игроков! Это конкретные объекты, экземпляры класса Игроки Alex = ClassPlayers:new(36, "abc-zxc-1234567-vvv", '192.168.1.0') -- мы создали объект Алекс, у которого есть какие-то свойства Bob = ClassPlayers:new(28, "zxc-qwe-0987654-bbb", '192.168.1.2') -- мы создали объект Боб, у которого есть какие-то свойства print('>>> проверим объект Алекс') print(Alex:get()) print('>>> меняем Алекса и проверяем, что получилось') Alex:set( 35, '111-aaa-bbb', '192.168.1.1') print(Alex:get()) -- =========Создадим подкласс Администраторы========== ClassAdmins = {} --пусть у этого подкласса будет свой метод Бан и метод Бла-бла, а так же один переназначенный метод гет function ClassAdmins:blabla() print('Отлично, метот Бла-бла у класса \'Админы\' выполнился') -- здесь может быть все, что угодно, по идее end --Админы имеют также медод Бан function ClassAdmins:ban(user) print ('Юзер '..user..' забанен навеки вечные!!!') end --переназначение метода гет у подкласса Админы function ClassAdmins:get() return "Это злые админы, всех банят и удаляют моды :)" end --наследуемся от родительского класса Игроки setmetatable(ClassAdmins,{__index = ClassPlayers}) -- Создаем дефолтного пока игрока ГрингоСтар без свойств, здесь видно, что метод new используется у родительского класса Игроки. Он там уже один раз -- описан, и его не нужно снова писать в коде и классе для админов. Это, cудя по всему, ключевой момент ООП. print('>>> Создаем и проверяем нашего Гринго, пока это какая-то какашка по умолчанию') -- но это уже самостоятельный объект GringoStar = ClassAdmins:new() --создали админа Гринго со стандарными свойствами ИГРОКА, мы не задали пока ему свойств, хоть и можно было!!! print(ClassPlayers.get(GringoStar)) print('>>> Меняем нашего Гринго так как ему положено быть') GringoStar:set(23, "555-666-sssssss-uuu", '192.168.255.255') -- изменили Гринге свойства, метод set ТОЖЕ описан уже в классе ИГРОКИ!!! print('>>> Вызовем метод гет у Админов') print(ClassAdmins:get()) print('>>> Вызовем метод гет у Игроков для нашего Гринго') -- синтаксис: РодительскийКласс.Метод(сам_объект, параметры) print(ClassPlayers.get(GringoStar)) print('>>> Вызовем метод Бла-бла у Админов') ClassAdmins:blabla() print('>>> Вызовем метод Бан у Админов и в качестве аргумента\nпередадим на растерзание дюпера Васю из 3-А') ClassAdmins:ban('Вася') print('>>> обращаюсь к некоторому свойству Алекса') print(Alex.age) print('>>> Меняю его на 50, Alex.age = 50') Alex.age = 50 print('>>> смотрю свойство age Алекса : ',Alex.age) print('>>> смотрю свойство uuid Гринго : ',GringoStar.uuid) ---Что получилось? Здесь, по идее и замыслу ООП, Гринго обладает всеми свойствами и методами класса Игроки, то есть наследует их, ---а также имеет свои свойтсва и методы класса Админы. вот, что выдала программка: Просьба, можно ли так же с объяснениями написать, если не затруднит о том, что я просил выше, на конкретном примерчике? 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
NEO 4 280 Опубликовано: 3 июня, 2015 Лучше изучить ооп на Java, а потом применять знания эти в луа, так как тут псевдо ооп, изучать ооп в луа испортит все представление об ооп. 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Alex 4 683 Опубликовано: 3 июня, 2015 Лучше изучить ооп на Java, а потом применять знания эти в луа, так как тут псевдо ооп, изучать ооп в луа испортит все представление об ооп. Это понятно. Изучать что-то можно всю жизнь, век живи, век учись, все равно нубом помрешь, как сказал Абдулла ибн Абдурахман. И это если ты по специальности программист. А поиграться в майн ради хобби, это совсем другое. Настоящие программисты нормальные кусок хлеба себе зарабатывают с маслом и икрой черной, а не в какахомайн играют и багованных черепах даже не пытаются запрогать, а мы так, кубики в цикле гоням, считай Нео, это же игра просто. Ты через чур ее близко к сердцу сильно прижал. За сервера переживаешь, браузеры на ОС и пинг стабильный чтобы был у твоей ОпенНет. Все равно что шутер-геймер спросил, какие перки на прокачку плазмогана есть и какие лучше пульки юзать, а ты ему говоришь. Э-э-э-э-э-э-э, чува-а-а-ак, какие пульки, лучше в школу "Морских котиков" в Детройте записывайся и станешь мега-крутым снайпером, дадут пукалку настоящую Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Krutoy 1 126 Опубликовано: 3 июня, 2015 Вячеслав. Просьба! Напишите понятным языком, как оно должно выглядеть на примере. Я ООП сам не открывал а искал в гугле. Я могу сделать статью из копипасты с гугла. Сойдет? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Alex 4 683 Опубликовано: 4 июня, 2015 Я ООП сам не открывал а искал в гугле. Я могу сделать статью из копипасты с гугла. Сойдет? Конечно сойдет! В нете то любой полазить может и инфы там много всякой и винегрета. Но важен пример конкретный. Вот, мол, готовый класс с наследованием для программки для робота, печки, реактора и прочего(с комментариями в коде) Методы не нужны подробные. Важна структура только. Что за подчеркивания одинарные и двойные, что они значат, можно ли скрыть(запретить) изменение свойств вне класса, метаметоды, как уйти от двоеточий, я не сильно понял в той статье, что там за абракадабра. Ты же сам говоришь, что можно так сделать как-то и т.п. У меня солдаты, некоторые не умели читать и писать толком, управляли многомиллионной по стоимости военной техникой высокоточной сложнейшей радиоэлектронной, подстраивали ее и выполняли боевые задачи повышенной важности и сложности по отработке нормативов и выдаче радиолокационной информации о воздушных целях и несли боевое дежурство. Но не имели понятия о транзисторах и законе Ома даже. А знаешь почему? Потому что практически я им показал и рассказал, как и что делать, просто на пальцах объяснил и натренировал их до автоматизма, как обезьян. Понимаешь меня? Думаю, что для ОпенГлассес вполне себе можно написать в стиле ООП несколько мощных классов и пусть народ их юзает на проекте нашем в свое удовольствие, так ведь? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
MisterFunny01 4 Опубликовано: 2 апреля, 2019 03.06.2015 в 15:38, NEO сказал: Лучше изучить ооп на Java Или на с++ (кст я его и изучаю) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах