第一个文件base.lua, 写继承的基础类,必须包含这个。面向对象主要用lua的元表和元方法实现的。
-- middleclass.lua - v2.0 (2011-09)
-- Copyright (c) 2011 Enrique García Cota
-- Permission is hereby granted, free of charge, to any person obtaining a copy of self.software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-- The above copyright notice and self.permission notice shall be included in all copies or substantial portions of the Software.
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-- Based on YaciCode, from Julien Patte and LuaObject, from Sebastien Rocca-Serra
-- https://github.com/kikito/middleclass/wiki
local _classes = setmetatable({}, {__mode = "k"})
local function _setClassDictionariesMetatables(klass)
local dict = klass.__instanceDict
dict.__index = dict
local super = klass.super
if super then
local superStatic = super.static
setmetatable(dict, super.__instanceDict)
setmetatable(klass.static, { __index = function(_,k) return dict[k] or superStatic[k] end })
else
setmetatable(klass.static, { __index = function(_,k) return dict[k] end })
end
end
local function _setClassMetatable(klass)
setmetatable(klass, {
__tostring = function() return "class " .. klass.name end,
__index = klass.static,
__newindex = klass.__instanceDict,
__call = function(self, ...) return self:new(...) end
})
end
local function _createClass(name, super)
local klass = { name = name, super = super, static = {}, __mixins = {}, __instanceDict={} }
klass.subclasses = setmetatable({}, {__mode = "k"})
_setClassDictionariesMetatables(klass)
_setClassMetatable(klass)
_classes[klass] = true
return klass
end
local function _createLookupMetamethod(klass, name)
return function(...)
local method = klass.super[name]
assert( type(method)=='function', tostring(klass) .. " doesn't implement metamethod '" .. name .. "'" )
return method(...)
end
end
local function _setClassMetamethods(klass)
for _,m in ipairs(klass.__metamethods) do
klass[m]= _createLookupMetamethod(klass, m)
end
end
local function _setDefaultInitializeMethod(klass, super)
klass.initialize = function(instance, ...)
return super.initialize(instance, ...)
end
end
local function _includeMixin(klass, mixin)
assert(type(mixin)=='table', "mixin must be a table")
for name,method in pairs(mixin) do
if name ~= "included" and name ~= "static" then klass[name] = method end
end
if mixin.static then
for name,method in pairs(mixin.static) do
klass.static[name] = method
end
end
if type(mixin.included)=="function" then mixin:included(klass) end
klass.__mixins[mixin] = true
end
Object = _createClass("Object", nil)
Object.static.__metamethods = { '__add', '__call', '__concat', '__div', '__le', '__lt',
'__mod', '__mul', '__pow', '__sub', '__tostring', '__unm' }
function Object.static:allocate()
assert(_classes[self], "Make sure that you are using 'Class:allocate' instead of 'Class.allocate'")
return setmetatable({ class = self }, self.__instanceDict)
end
function Object.static:new(...)
local instance = self:allocate()
instance:initialize(...)
return instance
end
function Object.static:subclass(name)
assert(_classes[self], "Make sure that you are using 'Class:subclass' instead of 'Class.subclass'")
assert(type(name) == "string", "You must provide a name(string) for your class")
local subclass = _createClass(name, self)
if (subclass.__superclassname == nil) then subclass.__superclassname = name end -- deve: for comp.
subclass.__classname = name
_setClassMetamethods(subclass)
_setDefaultInitializeMethod(subclass, self)
self.subclasses[subclass] = true
self:subclassed(subclass)
return subclass
end
function Object.static:subclassed(other) end
function Object.static:include( ... )
assert(_classes[self], "Make sure you that you are using 'Class:include' instead of 'Class.include'")
for _,mixin in ipairs({...}) do _includeMixin(self, mixin) end
return self
end
function Object:initialize() end
function Object:__tostring() return "instance of " .. tostring(self.class) end
function class(name, super, ...)
super = super or Object
return super:subclass(name, ...)
end
function instanceOf(aClass, obj)
if not _classes[aClass] or type(obj) ~= 'table' or not _classes[obj.class] then return false end
if obj.class == aClass then return true end
return subclassOf(aClass, obj.class)
end
function subclassOf(other, aClass)
if not _classes[aClass] or not _classes[other] or aClass.super == nil then return false end
return aClass.super == other or subclassOf(other, aClass.super)
end
function includes(mixin, aClass)
if not _classes[aClass] then return false end
if aClass.__mixins[mixin] then return true end
return includes(mixin, aClass.super)
end
用法:
require("lib/base.lua")
data = class("data",Observer)
function data:initialize(param)
self.channel = 1
self.channelName = param.name
end
local xxx = data:new{name="hehe"}
MYLOG("xxx.channelName = "..tostring(xxx.channelName))
local xxx = data:new{name="haha"}
MYLOG("xxx.channelName = "..tostring(xxx.channelName))
--分别打印出 hehe 与 haha
举个继承其他lua类的例子:
chatMainData = class("chatMainData")
function chatMainData:initialize(msg)
self.cacheData = {}
if msg then
self.cacheData[1] = msg
end
return self --这个不需要写 因为new方法已经返回
end
function chatMainData:addMsgData(msg)
self.cacheData[#self.cacheData+1] = msg
if #self.cacheData > 2 then
table.remove(self.cacheData, 1)
end
end
BellowMainData = class("BellowMainData", chatMainData) --第二个是table类型 不要加双引号 写成字符串了
function BellowMainData:initialize(msg) --如果初始化没有特殊设置 可以不写这个方法
BellowMainData.super.initialize(self, msg) --传的参数是self之后传的
return self --这个是不需要写这个的 因为已经返回了这个 在new方法里
end
function BellowMainData:getData()
return self.cacheData
end
第二个文件:extern.lua, 另一个lua继承基础类,两个随便用一个就可以了。
extern = {}
function extern.clone(object)
local lookup_table = {}
local function _copy(object)
if type(object) ~= "table" then
return object
elseif lookup_table[object] then
return lookup_table[object]
end
local new_table = {}
lookup_table[object] = new_table
for key, value in pairs(object) do
new_table[_copy(key)] = _copy(value)
end
return setmetatable(new_table, getmetatable(object))
end
return _copy(object)
end
--Create an class.
function extern.class(classname, super)
local superType = type(super)
local cls
if superType ~= "function" and superType ~= "table" then
superType = nil
super = nil
end
if superType == "function" or (super and super.__ctype == 1) then
-- inherited from native C++ Object
cls = {}
if superType == "table" then
-- copy fields from super
for k,v in pairs(super) do cls[k] = v end
cls.__create = super.__create
cls.super = super
else
cls.__create = super
end
cls.initialize = function() end
cls.__cname = classname
cls.__ctype = 1
function cls.new(...)
local instance = cls.__create(...)
-- copy fields from class to native object
for k,v in pairs(cls) do instance[k] = v end
instance.class = cls
instance:initialize(...)
return instance
end
else
-- inherited from Lua Object
if super then
cls = extern.clone(super)
cls.super = super
else
cls = {initialize = function() end}
end
cls.__cname = classname
cls.__ctype = 2 -- lua
cls.__index = cls
function cls.new(...)
local instance = setmetatable({}, cls)
instance.class = cls
instance:initialize(...)
return instance
end
end
return cls
end
function extern.schedule(node, callback, delay)
local delay = CCDelayTime:create(delay)
local callfunc = CCCallFunc:create(callback)
local sequence = CCSequence:createWithTwoActions(delay, callfunc)
local action = CCRepeatForever:create(sequence)
node:runAction(action)
return action
end
function extern.performWithDelay(node, callback, delay)
local delay = CCDelayTime:create(delay)
local callfunc = CCCallFunc:create(callback)
local sequence = CCSequence:createWithTwoActions(delay, callfunc)
node:runAction(sequence)
return sequence
end
用法(独类,没继承):
require("lib/extern.lua")
data = extern.class("data")
function data:initialize(param)
self.channel = 1
self.channelName = param.name
end
local xxx = data:new{name="hhe"}
MYLOG("xxx.channelName = "..tostring(xxx.channelName))
local xxx = data:new{name="hah"}
MYLOG("xxx.channelName = "..tostring(xxx.channelName))
--打印出 hehe 与 haha
上面两种都是单独类的实现,没有用到继承,下面举一个继承的例子。
下面是事件派发类的源码:(这个一个大神写的 Observer.lua),事件派发主要用于数据和逻辑分离( MVC模型,模型(model),视图(view),控制器(controller) )
这个Observer.lua就相当于controller,model和view不会互相直接操作,都通过注册controller事件来派发时间调用。这么做的好处的解耦,界面不会因为数据的更改而东西,数据也不会因为修改界面而改动,减少了耦合性,不容易出来问题。
--[[
@author mwshang
@date 2013.9.11
]]
Observer = extern.class("Observer")
local _defalut = "default"
local function _notify(tb,data)
for i=#tb,1,-1 do
local v = tb[i]
if v.destroyed ~= true then
if v.owner then
if v.fixedParam then--
v.callback(v.owner,v.fixedParam,data,v)
else
v.callback(v.owner,data,v)
end
else
if v.fixedParam then--
v.callback(v.fixedParam,data,v)
else
v.callback(data,v)
end
end
if v.count ~= nil then
v.count = v.count - 1
if v.count <= 0 then
table.remove(tb,i)
v.destroyed = true
end
end
end
end
end
-- function Observer:new(o)
-- o = o or {}
-- setmetatable(o,self)
-- self.__index = self
-- --o.observers = {}
-- o.dicType = {}
-- return o
-- end
function Observer:initialize()
self:_initialize()
end
function Observer:_initialize()
self.dicType = {}
end
--[[
添加观察者
@param {owner,callback=function(data) end,
type="数据类型"
}
]]
function Observer:addObserver(param)
--table.insert(self.observers,param)
local _type = param.type
if _type == nil then
_type = _defalut
end
if self.dicType[_type] == nil then
self.dicType[_type] = {}
end
local tb = self.dicType[_type]
local flag = true
for k,v in pairs(tb) do
if v.callback == param.callback and v.type == _type then
flag = false
break
end
end
if flag then
tb[#tb + 1] = param
end
--log("Observer.observers's size:" .. #self.observers)
end
local function _remove(tb,param)
if tb == nil or param == nil then return end
for k, v in pairs(tb) do
if v.callback == param.callback then
table.remove(tb,k)
--log("Observer::_remove----->>>" .. (param.type or _defalut))
break
end
end
end
--[[
删除观察者
@param {callback=function(data) end,
type="数据类型"
}
]]
function Observer:removeObserver(param)
--_remove(self.observers,param)
local _type = param.type
if _type == nil then
_type = _defalut
end
if self.dicType[_type] then
_remove(self.dicType[_type],param)
end
end
function Observer:removeObserverWithType(_type)
self.dicType[_type] = nil
end
function Observer:hasObserver(param)
local _type = param.type
if _type == nil then
_type = _defalut
end
local tb = self.dicType[_type]
if not isTrue(tb) then
return false
end
for k,v in pairs(tb) do
if v.callback == param.callback and v.type == _type then
return true
end
end
return false
end
function Observer:notify(data,_type)
if _type == nil then
_type = _defalut
end
if self.dicType[_type] then
_notify(self.dicType[_type],data)
end
end
function Observer:send(_type,data)
self:notify(data,_type)
end
function Observer:clear(excepts)
if excepts then
local dic = {}
for k,v in pairs(excepts) do
dic[v] = self.dicType[v]
end
self.dicType = dic
else
self.dicType = {}
end
end
function Observer:destroy()
self:clear()
end
我们来继承这个事件派发类,这样我们写的类就可以用这个事件派发,来发送事件了。
继承的用法:
TileList = extern.class("TileList",Observer)
function TileList:initialize(param)
TileList.super.initialize(self) --指Observer类 是一个时间派发类 这样 TileList将继承 Observer所有功能
end
这样我们就继承了 Observer,可以使用其方法来派发事件了。