Перейти к содержимому
Ktlo

Другой способ реализации Объектно-Ориентированного Программирования

Рекомендуемые сообщения

Приз - компьютер или робот любой комплектации (кроме креатива) тому, кто реализует readonly-поле объекта через переопределение оператора присваивания.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Метатаблицы Карл...

 

Как ты это сделаешь для "примитивных" типов?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Приз - компьютер или робот любой комплектации (кроме креатива) тому, кто реализует readonly-поле объекта через переопределение оператора присваивания.

Всё уже реализовано. Вот тут например вообще можно устанавливать свои функции для get и set переменной.

 

Как ты это сделаешь для "примитивных" типов?

Можно можно. Даже цифры, и даже нил. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Можно можно. Даже цифры, и даже нил. 

Узнаю Луа.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Можно)

переопределить оператор присваивания

 

Метатаблицы Карл...

Я почитал про метатаблицы поподробнее и всё исправил. Оказывается запретить изменение ключей можно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

ro = {a=1, b=2}
obj = {b=3, c=4}
setmetatable(obj,{__index=ro,__newindex=function(_,_,_)end})

prn(obj.a, obj.b, obj.c) -->1 3 4 (значение obj.b=3 установленное до объявления метаметодов перекрывает ro.b=2, и __index=ro не вызывается.
obj.a=5
obj.b=6
obj.c=7
prn(obj.a, obj.b, obj.c) -->1 6 7 (obj.a=5 выполнил function(_,_,_)end ничего не сделав)
 

Эта строка setmetatable(obj, {__index=ro, __newindex=function(_,_,_)end}) говорит следующее:

Для несуществующих индексов таблицы obj, читать значения из ro, а при попытке записи выполнять ничего function(_,_,_)end

 

Или так: setmetatable(obj,{__index=ro,__newindex=function(t,k,v) print('Иди в пень! '..k..' ' - ридонли!')  end})

 

--===--

 

При попытке добавления нового значения (например obj.d=8) выполнится ничего и значение добавлено не будет.

Чтобы мы могли добавлять новые индексы в obj нужно в нашем ничего проверять, есть ли добавляемый индекс в ro, и если такого индекса нет, то добавлять его в obj.

 

Это можно сделать так: setmetatable(obj, {__index=ro,__newindex=function(t,k,v) local _=rawget(ro,k) or rawset(t,k,v) end})

При попытке записи obj.d=8, наше ничего, сделает: если не ro.k то rawset(t,k,v) наплевав на всякие там метаметамета.

 

Теперь мы можем:

ro = {a=1, b=2}
obj = {b=3, c=4}
setmetatable(obj,{__index=ro,__newindex=function(t,k,v) local _=rawget(ro,k) or rawset(t,k,v) end})

prn(obj.a, obj.b, obj.c, obj.d)
obj.a=5
obj.b=6
obj.c=7
obj.d=8
prn(obj.a, obj.b, obj.c, obj.d)
upd:

Прочел следующие посты и понял, как я далек от объектно-ориентированного програмирования )

Изменено пользователем swg2you

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Уже ближе. Вот пример реализации класса с двумя обычными полями (c,d) и двумя readonly-полями (a,b)

 

 

Class={a=1, b=2, __newindex=function()end}
Class.__index=Class

function Class:new()
    local obj={c=3, d=4}
    setmetatable(obj,self)
    return obj
end

function Class:ShowFields()
  print(self.a, self.b, self.c, self.d)
end

function Class:SetA(Val)
  Class.a=Val
end

function Class:SetB(Val)
  Class.b=Val
end

obj = Class:new()

obj:ShowFields()
obj.a=5
obj.b=6
obj.c=7
obj.d=8
obj:ShowFields()
obj:SetA(5)
obj:SetB(6)
obj:ShowFields()

 

 

RO-поля можно менять при помощи методов класса. Одна проблема - RO-поля общие для всех экземпляров класса

И можно ли будет от такого класса сделать наследника если невозможно добавлять новые поля?

Изменено пользователем Zer0Galaxy

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

И можно ли будет от такого класса сделать наследника если невозможно добавлять новые поля?

Можно:

function newClass()
      local object, private = class()
      setmetatable(object, {}) --Удаляем метатаблицу
      object.foo(...) --Добавляем метод
            --<Что-нибудь>
      end
      setmetatable(object, private) --Возвращаем нашу метатаблицу назад
      return object, private
end

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

 

 

При попытке добавления нового значения (например obj.d=8) выполнится ничего и значение добавлено не будет. Чтобы мы могли добавлять новые индексы в obj нужно в нашем ничего проверять, есть ли добавляемый индекс в ro, и если такого индекса нет, то добавлять его в obj.   Это можно сделать так: setmetatable(obj, {__index=ro,__newindex=function(t,k,v) local _=rawget(ro,k) or rawset(t,k,v) end}) При попытке записи obj.d=8, наше ничего, сделает если не ro.k то rawset(t,k,v) наплевав на всякие там метаметамета.
Так, а как сделать что бы таблица ro была не одна на всех, а своя для каждого экземпляра класса?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Так, а как сделать что бы таблица ro была не одна на всех, а своя для каждого экземпляра класса?

Я далек от ООП, но думаю, что как-то так.

setmetatable(obj1, {__index=ro1,__newindex=function(t,k,v) local _=rawget(ro1,k) or rawset(t,k,v) end})

setmetatable(obj2, {__index=ro2,__newindex=function(t,k,v) local _=rawget(ro2,k) or rawset(t,k,v) end})

 

Или по твоему коду:

Class={a=1, b=2}

function Class:new()
  local obj={c=3, d=4}
  local nc={}
  for k,v in pairs(self) do nc[k]=v end
  setmetatable(obj,{__index=nc,__newindex=function(t,k,v) local _=rawget(nc,k) or rawset(t,k,v) end})
  return obj
end

function Class:ShowFields()
  prn(self.a, self.b, self.c, self.d)
end

function Class:SetA(Val)
  rawset(self,'a',Val)
end

function Class:SetB(Val)
  rawset(self,'b',Val)
end

obj = Class:new() 
obj2 = Class:new()

obj:ShowFields()
obj.a=5
obj.b=6
obj.c=7
obj.d=8
obj:ShowFields()
obj:SetA(5)
obj:SetB(6)
obj:ShowFields()
obj2:ShowFields()
Если я правильно понял, что тебе от этого кода нужно. Изменено пользователем swg2you

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Приз за решение проблемы ReadOnly-полей уходит к swg2you. Жду комплектацию компьютера и адрес куда его отправлять.

Хотелось бы узнать про параметры (t,k,v) функции __newindex. А про функции rawget и rawset поподробнее.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Приз за решение проблемы ReadOnly-полей уходит к swg2you. Жду комплектацию компьютера и адрес куда его отправлять.

Хотелось бы узнать про параметры (t,k,v) функции __newindex. А про функции rawget и rawset поподробнее.

__newindex(t,k,v) - (новый индекс) вызовется если в таблицу t, несуществующему ключу k присвоить значение v

v=rawget(t,k) и rawset(t,k,v) - позволяют получить/присвоить значение v напрямую, игнорируя всякие метаметоды

 

Приз за решение проблемы прошу передать в международный фонд помощи мадагаскарским хомячкам.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Компьютер наилучшей комплектации отправлен на Мадагаскар хомячкам до востребования.

А какие еще интересные функции кроме __index и __newindex могут содержать метатаблицы?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Компьютер наилучшей комплектации отправлен на Мадагаскар хомячкам до востребования.

А какие еще интересные функции кроме __index и __newindex могут содержать метатаблицы?

Почитай это. http://xgm.guru/p/love2d/112958

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Компьютер наилучшей комплектации отправлен на Мадагаскар хомячкам до востребования.

А какие еще интересные функции кроме __index и __newindex могут содержать метатаблицы?

Первоисточник всего: http://www.lua.org/manual/5.2/manual.html#2.4 Изменено пользователем swg2you

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
10.06.2015 в 10:35, LeshaInc сказал:

Любой программист это прочитает.

Лол, реально со второй строки автоматом стало читаться :DDD

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Я уже пару лет периодически читаю этот тред, и меня мучает вопрос, почему, нельзя просто произвести инкапсуляцию сокрытие для Рид-онли переменных, мой вариант:

function Class1()
	local self = {
		["var1"] = "Nothing"
	}
	local private = {
		["var1"] = "Secret!"
	}
	function self.getVar1()
		print(self.var1)
	end
	function self.getPrivateVar1()
		return private.var1
	end
	return self
end

В файле класса, и:

require("class1")
local myObject = Class1()
print(myObject.getPrivateVar1())
--> Secret!

в файле программы.
По-идее к этой переменной никак не получить доступ

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
11 час назад, MrAbad сказал:

По-идее к этой переменной никак не получить доступ

Можно конечно и так, но у такого способа есть маленький недостаток. Для каждого рид-онли поля каждого экземпляра объекта необходимо создавать отдельную функцию. В твоем примере, если я создам несколько экземпляров Class1:

require("class1")
local myObjects={}
for i=1,1000000 do
  myObjects[i]=Class1()
end

будет создано соответствующее количество не только таблиц private но и функций getPrivateVar1. Каждая такая функция будет занимать место в небезграничном ОЗУ, хотя все они выполняют одно и тоже действие.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
В 23.12.2019 в 12:25, Zer0Galaxy сказал:

Для каждого рид-онли поля каждого экземпляра объекта необходимо создавать отдельную функцию.

Хорошо, можно так:
("MyClosure.lua")

function MyClosure(a, b)
    self = {}
    readOnly = {
        var1 = true
    }
    self.a = a
    self.b = b
    function self.printAandB()
        print(self.a, self.b)
    end
    function self.GET(var)
        return readOnly[var]
    end
    return self
end

("main.lua")

require("MyClosure")

local obj1 = MyClosure(3,14)
obj1.printAandB()
--> 3 14
print(obj1.GET("var1"))
--> true

Кстати, я не даром назвал файл "MyClosure", потому что, это не ООП, а в чистом виде замыкание и функциональное программирование

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в тему...

×   Вы вставили отформатированное содержимое.   Удалить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.


×
×
  • Создать...