lua面向对象

原创 2015年07月10日 18:23:32

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




相关文章推荐

Lua面向对象封装 链接库

  • 2012年10月18日 14:12
  • 1.2MB
  • 下载

Lua支持面向对象代码

  • 2014年09月09日 17:09
  • 7KB
  • 下载

【quick-cocos2d-x】Lua 面向对象(OOP)编程与元表元方法

面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。 早期的计算机编程是基于面向过程的方法,通过设计一个算法就可以解决当时的问题。随着计算机技术的不断提高,计算机被用于...

Lua知识点全面总结(语法、控制语句、函数、模块、面向对象/prototype、和C的交互等等)

原文链接:http://blog.csdn.net/peerlessbloom/article/details/44081153 基础 弱类型,没有类型定义解释型语言,但是会通过编...
  • Tovids
  • Tovids
  • 2017年02月05日 21:58
  • 151

lua 面向对象的实现及原理

--[[ function func( ... ) -- 对于不定参数的使用 local args = {...} for k,v in ipairs(args) do print(v) e...

cocos2dx-lua中实现面向对象的封装继承

class函数是在"cocos2d-x-3.2/cocos/scripting/lua-bindings/script/extern.lua"中定义的。 -- Cre...

lua的面向对象

本文解释面向对象的一个例子,例子来源于http://www.lua.org/pil/16.2.html 文件UIBase.lua module("UIBase", package.seeall) ...

Lua面向对象之类和继承理解

其实 Lua 中的 table 是一种对象,因为它跟对象一样,有其自己的操作方法: 1 2 3 4 5 6 7 Ro...

Lua学习之10:面向对象与继承

1、简单的面向对象函数

Lua面向对象的实现

元表概念 Lua中,面向对向是用元表这种机制来实现的。元表是个很“道家”的机制,很深遂,很强大,里面有一些基本概念比较难理解透彻。不过,只有完全理解了元表,才能对Lua的面向对象使用自如,才能在写L...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:lua面向对象
举报原因:
原因补充:

(最多只允许输入30个字)