关闭

lua面向对象

617人阅读 评论(0) 收藏 举报
分类:

第一个文件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

猜你在找
【直播】机器学习&数据挖掘7周实训--韦玮
【套餐】系统集成项目管理工程师顺利通关--徐朋
【直播】3小时掌握Docker最佳实战-徐西宁
【套餐】机器学习系列套餐(算法+实战)--唐宇迪
【直播】计算机视觉原理及实战--屈教授
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之矩阵--黄博士
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之凸优化--马博士
【套餐】Javascript 设计模式实战--曾亮
查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:168211次
    • 积分:2787
    • 等级:
    • 排名:第12808名
    • 原创:104篇
    • 转载:37篇
    • 译文:0篇
    • 评论:24条
    最新评论