★網站前端技術發展太快, 新手很難抉擇要學的東西, 大家學了什麼

CSS:https://colorlib.com/wp/free-css3-frameworks/
JS:https://colorlib.com/wp/javascript-frameworks/
HYBRID APP:https://blog.jscrambler.com/10-frameworks-for-mobile-hybrid-apps/
2d/3d Game:https://www.diycode.cc/topics/16
Desktop:https://electron.atom.io/
IOT:https://webduino.io/

上述只是冰山一角, UI/UX視覺整合, 前端資安, 後端node.js, Social Plugin, SEO, 自動化測試, 大數據分析, 資料視覺化, RWD, AI, Google Map, 語音辨識, 文字轉發音, 影像辨識, VR/AR, Webphone, WebRTC, midi, GrouthHacker, 程式混淆壓縮加密, 程式編譯如Typescript/Kotlin編譯成js, 版控只能git了,讓你玩不完....老實說有點噁心, 而且沒談到各框架生態系與外掛....哈哈 Orz

後端工作如後台開發, 金流, 後台資安, 大數據分析, 自動化測試, 排程, BOT, 轉檔, 檔案管理, RESTFUL API撰寫, 伺服器調教維運, 資料庫調教維運, LOG管理, 種類相較較少, 當然不是說比前端簡單, 後端工作需要深度學習與經驗. 個人推薦python作為後端開發程式會很省力, 因為投資報酬率還不錯. 或者想省掉後端管理的工就用firebase也是不錯選擇

2016年2月25日 星期四

Corona SDK Lua OOP 設計

了解OOP之前先了解 Metatables 與 Metamethods。Lua 中的 table 由於定義的行為,我們可以遍歷所有的 key-value,但是我們不可以對兩個 table 進行相加,也不可以比較兩個表的大小。Metatables 允許我們改變 table 的行為,例如,使用 Metatables 我們可以定義 Lua 如何計算兩個 table 的相加操作 a+b。當 Lua 試圖對兩個表進行相加時,他會檢查兩個表是否有一個表有 Metatable,並且檢查 Metatable 是否有__add方法實作。如果找到則執行這個 __add 函式 ( 所謂的 Metamethod ) 去計算結果。Lua 中的每一個表都有 Metatable 可添加。預設 Lua 新建立的 table 不帶 metatable。任何一個表都可以是其它表的 metatable,一組相關的表可以共享一個 metatable(描述他們共同的行為)。一個表也可以是自身的 metatable ( 描述其私有行為 )。簡單來說我們設置好 metatable 後,可以為該表格定義特殊函示 Metamethod,以雙底線 __ 開頭的函示:

t = {}
print(getmetatable(t)) --> nil
t_mt = {} -- 建立 table 作 metatable 用
setmetatable(t, t_mt) -- 設置 t 的 metatable 是 t_mt

以下我們示範兩個 table 相加

Set = {}
Set.mt = {} -- 建立 metatable 給 Set

function Set.new (t)
    local set = {}
    setmetatable(set, Set.mt) -- 設置 metatable
    for _, l in ipairs(t) do set[l] = true end
    return set
end

s1 = Set.new{10, 20, 30, 50}
s2 = Set.new{30, 1}
print(getmetatable(s1)) --> table: 0x7f953bd03f20
print(getmetatable(s2)) --> table: 0x7f953bd03f20

Set.mt.__add = function (a,b) -- 實作宇集(union) __add metamethod
    local res = Set.new{}
    for k in pairs(a) do res[k] = true end
    for k in pairs(b) do res[k] = true end
    return res
end

print_r(s1 + s2) -- table: 0x7fcc855f2e10 {[1] => true, [30] => true, [10] => true, [50] => true, [20] => true}

print_r 不清楚請參考前一篇 Corona SDK Lua 程式語言基礎
metamethod 不只有 __add 可以實作, 還有 __mul(乘)、__sub(減)、__div(除)、__unm(負)、__pow(冪)、__eq(等於)、__lt(小於)、__le(小於等於)...等,較常使用應該是__tostring 跟物件導向設計要使用的 __index。下面先介紹 __tostring,隱含物件轉字串實作:

Set.mt.__tostring = function (set)
    return "[Set Object]"
end

print(s1,s2) --> [Set Object] [Set Object]

接下來介紹 __index。當我們存取一個表不存在的變數時,返回結果應為nil,這是正確的,但並不完全正確。實際上,這種存取變數時會觸發 lua 解釋器去查找 __index metamethod:如果不存在,返回結果為nil;如果存在則由__index metamethod 返回結果。延續上面範例:

print(s1.width) --> nil (其實有觸發預設 __index,且回傳 nil)
Set.mt.__index = function() -- 覆寫 __index 方法
    return "觸發__index"
end
print(s1.width) -->觸發__index (建立預設值的概念)
--所以無論如何存取 table 未定義變數時都一定會隱含執行 __index metamethod

我們可以發現 __index 可以用來作為物件導向的繼承概念,給予繼承物件預設值(子物件屬性會繼承父物件屬性)。假設我們想建立一些表來描述窗戶物件。每一個表必須描述窗戶物件的一些參數,比如:位置,大小,顏色風格等等。所有的這些參數都有預設的值,當我們想要建立窗戶物件的時候只需要給出非預設值的參數即可建立我們需要的窗戶物件。首先,我們實作一個原型和一個構造函數,他們共享一個 metatable:

-- 建立名稱空間
Window = {}
-- 建立 prototype 變數
Window.prototype = {x=0, y=0, width=100, height=100}
-- 建立 metatable
Window.mt = {}
-- 宣告建構子
function Window.new (o)
    setmetatable(o, Window.mt)
    return o
end
-- 建立預設值來自 prototype 變數
Window.mt.__index = function (table, key)
    return Window.prototype[key]
end
-- 創造 Window 物件
w = Window.new{x=10, y=20}
print(w.width) --> 100 (來自 prototype 的變數)

特殊用法:Window.mt.__index,當他是一個表的時候,Lua 將在這個表中看是否有缺少的變數。所以,上面的那個例子可以使用第二種方式簡單的改寫為

Window.mt.__index = Window.prototype --跟用函示意思一樣但寫法簡潔
w = Window.new{x=10, y=20}
print(w.width) --> 100 (相當執行 Window.prototype["width"])

接下來進入我們正式主題物件導向設計
首先我們要改變 table 中函示的宣告方式:

T = {val=1}

function T.func(v)
    return T.val + v
end

--第一次改寫,用 self 程式更有彈性
function T.func(self, v)
    return self.val + v
end

--第二次改寫,隱藏第一個函示參數 self 用:
function T:func(v)
    return self.val + v
end

在Lua中,使用前面我們介紹過的繼承的思想,很容易實現prototypes。更明確的來說,如果我們有兩個對象 a 和 b,我們想讓 b 作為 a 的 prototype 只需要

setmetatable(a, {__index = b})

這樣,當對象 a 使用任何不存在的成員都會到對象 b 中查找。術語上,可以將 b 看作類別,a 看作物件。我們來設計建構子:

function T:new (o)
    o = o or {}
    setmetatable(o, self) --優化程式,讓本身 T 作為 metatable
    self.__index = self --讓本身 T 表內所有參數被 o 繼承。這樣子的話,一個類不僅提供方法,也提供了他的實例成員的預設值
    return o
end

嘗試建立物件:

local t = T:new({val=2})
print(t.val) -- 2,因為直接設 val,不會再去找 __index 表的 val
print(t:func(10)) -- 12,t 未定義 func 屬性,但是解析器會找查 metatable 的 __index 表,所以使用了 getmetatable(t).__index.func(T,v) 意即 T:func(v)

所以類的設計跟使用方法長這樣:

--MyOOP.lua

--成員屬性設定
MyOOP = {
    a = 1,
    b = 2
}

--私有函示設定
local function privateFunc()
    print("123")
end

--公開函示設定
function MyOOP:new(o)
    o = o or {}
    setmetatable(o, self)
    self.__index = self
    return o
end

function MyOOP:func1()
    print("func1")
end

function MyOOP:func2()
    print("func2")
    --privateFunc()
end

return MyOOP

--main.lua
local MyOOP = require("MyOOP")
local oop = MyOOP:new()
oop:func1()

呈上例,接下來談繼承,很簡單,設置變數 ExtendMyOOP 實例化 MyOOP:new(),再定義子類 ExtendMyOOP 新方法或覆寫函示即可。

ExtendMyOOP = MyOOP:new()

function ExtendMyOOP:func1()
    print("extend func1")
end

local e = ExtendMyOOP:new{b=1000.00} --當 new 執行的時候,self 參數指向 ExtendMyOOP。所以,e 的 metatable 是 ExtendMyOOP,__index 也是 ExtendMyOOP。
e:func1() --> extend func1 (直接使用覆寫方法,不會再找 __index)
e:func2() --> func2 (Lua 在 e 中找不到 func2 函示,它會到 ExtendMyOOP 中查找,在 ExtendMyOOP 中找不到,會到 MyOOP 中查找)
print(e.a) --> 1 (Lua 在 e 中找不到 a 變數,它會到 ExtendMyOOP 中查找,在 ExtendMyOOP 中找不到,會到 MyOOP 中查找)
print(e.b) --> 1000 (直接使用覆寫變數,不會再找 __index)

有任何問題歡迎留言~
官方範例

沒有留言:

張貼留言