lua面向对象

第一个文件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,可以使用其方法来派发事件了。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Lua 中,可以使用“似有字段”(Pseudo-Fields)来模拟面向对象编程中的成员变量。所谓“似有字段”,指的是在表中使用函数来表示一个字段,使得它看起来像一个变量,但实际上是一个函数调用。下面是一个使用“似有字段”实现面向对象的示例: ```lua -- 定义一个类 local MyClass = {} -- 定义一个似有字段 name MyClass.name = function(self, value) if value then self._name = value else return self._name end end -- 定义一个方法 function MyClass:hello() print("Hello, my name is " .. self:name() .. "!") end -- 创建一个实例 local obj = {} setmetatable(obj, { __index = MyClass }) -- 使用 name 字段 obj:name("Jack") print(obj:name()) -- 输出 "Jack" -- 调用方法 obj:hello() -- 输出 "Hello, my name is Jack!" ``` 在上面的示例中,我们定义了一个类 `MyClass`,并在其中使用了一个似有字段 `name`。这个似有字段实际上是一个函数,可以用来设置和获取对象的名称。 然后,我们在类中定义了一个方法 `hello`,用来输出对象的名称。在方法中,我们调用了 `self:name()` 来获取对象的名称,实际上是调用了 `MyClass.name(self)` 函数来获取值。 最后,我们创建了一个实例 `obj`,并使用 `obj:name()` 来设置和获取对象的名称,以及调用 `obj:hello()` 方法来输出对象的名称。 通过使用“似有字段”,我们可以模拟面向对象编程中的成员变量,并在方法中使用它们。需要注意的是,在 Lua 中没有真正的私有变量,所以使用“似有字段”时需要注意保护对象的数据,以避免被外部直接修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值