lovingxiaobing 发表于 2018-7-22 21:30

Lua实现基本的面向对象

{:1_892:}   哈喽,我是小冰。

据小冰完全没有科学的统计得知,大多数游戏都用Lua作为脚本语言。小冰学习过一段时间的Python,但突然又对Lua感兴趣,也去研究一二。


小冰喜欢在已经学习过的计算机语言的基础上进行对比,发现Lua中没有面向对象。但是,发现Lua中的table可以用 . 来访问table内的元素,再利用元表的特性给表附加方法,于是突发奇想就有了以下的代码。

function triangle(a, b, c)
        --用闭包函数作为私有成员
        local function isTriangle(_a, _b, _c)
                if not (_a and _b and _c) then return nil end --判断是否给了三条边
                if not ((_a + _b) > _c) and ((_a - _b) < _c) then return nil end
                return true
        end

        if not isTriangle(a, b, c) then return nil end
       
        local baseClass = {}
        self = setmetatable(baseClass,{})
       
        --初始化
        self.a = a
        self.b = b
        self.c = c
       
        --公有方法
        function self:calcArea()
                --用海伦公式计算三角形面积
                local p = (self.a + self.b + self.c) / 2
                local s = math.sqrt(p * (p - self.a) * (p - self.b) * (p - self.c))
               
                return s
        end
       
        --返回对象实例
        return self
end

--继承,不够再Lua中并不推荐继承。用一次就够了吧....
function StrongTriangle(a, b, c)
        tri = triangle(a, b, c)
        if not tri then return nil end
       
        function tri:calcCirc()
                c = tri.a + tri.b + tri.c
                return c
        end
       
        return tri
end

myTriangle = triangle(3,4,5)
another = StrongTriangle(6,8,10)

print("边长为 a="..myTriangle.a.." b="..myTriangle.b.." c="..myTriangle.c)
print("面积:"..myTriangle:calcArea())

print("边长为 a="..another.a.." b="..another.b.." c="..another.c)
print("面积:"..another:calcArea())
print("周长:"..another:calcCirc())

--对比两个table地址,不一样就成功啦!!!
print(myTriangle,another)


结果:
边长为 a=3 b=4 c=5
面积:6.0
边长为 a=6 b=8 c=10
面积:24.0
周长:24
table: 003C21A8        table: 003C2270

情况看起来一切都OK嘛,在网上还有一种方式,小冰看了看,emmm感觉这种比较酷。小冰再对这个triangle在升级吧。
代码:


-- a,对边;b,邻边;c,邻边(比如靠近直角的邻边)
local function triangle(a, b, c)
--类似于__new__在初始化前进行处理
--检查边长是否合格
local function __new__(_a,_b,_c)
--利用闭包函数作为私有成员
if not (_a and _b and _c) then return nil end
       if not(((_a+_b)>_c)and (_a-_b)<_c) then return nil end
       return true
end

if not __new__(a, b, c) then return nil end
       
        local _triangle = {}
       
        --初始化,因为self作用域的原因,就定义在_triangle域内
        function _triangle:__init__(a, b, c)
                local ob = {}
                setmetatable(ob,self)
                self.__index = self
                --保护基础类
                self.__metatable = ob
                self.__tostring = ob
               
                self.a = a
                self.b = b
                self.c = c
               
                return ob
        end
       
        function _triangle:circumference(_a, _b, _c) --周长
                if __new__(_a, _b, _c) then --判断是否有输入
                        self.a = _a
                        self.b = _b
                        self.c = _c
                end
                return self.a + self.b + self.c
        end
       
        function _triangle:area()
                local p = (self.a + self.b + self.c) / 2
                local s = math.sqrt(p * (p - self.a) * (p - self.b) * (p - self.c))
                return s
        end
       
        function _triangle:center() --内角
                local s = self:area()
                if s then
                        s = s * 2
                else
                        return s --s = nil
                end
                local ret = {}
                ret['C'] = math.deg(math.asin(s / (self.a * self.b))) --角C
                ret['B'] = math.deg(math.asin(s / (self.a * self.c))) --角B
                ret['A'] = 180 - (ret.C + ret.B) --角A
                return ret
        end
       
        function _triangle:show()
       print(string.format("a=%sb=%sc=%s",self.a,self.b,self.c))
       print(string.format("面积:%.4f", self:area()))
       print("周长:", self:circumference())
       local ABC = self:center()
       print("三角形三个内角A,B,C分别为:\n"..string.format("∠A = %.4f\n∠B = %.4f\n∠C = %.4f",ABC.A, ABC.B, ABC.C))
        end
       
        ret = _triangle:__init__(a, b, c)
        ret.init = ret --防止再次调用重构
       
        return ret
end



triangle(3,4,5):show()
print("**************")
triangle(2,2,math.sqrt(3)):show()
print("**************")
triangle(1,2,math.sqrt(3)):show()
print("**************")
t = triangle(1,1,math.sqrt(2))
t:show()


print("----cut line----")


--使用对象的公开方法
print("新的周长:"..t:circumference(6,6,6))
--此时已改变对象中的量
t:show()


运行结果:
a=3b=4c=5
面积:6.0000
周长:        12
三角形三个内角A,B,C分别为:
∠A = 36.8699
∠B = 53.1301
∠C = 90.0000
**************
a=2b=2c=1.7320508075689
面积:1.5612
周长:        5.7320508075689
三角形三个内角A,B,C分别为:
∠A = 64.3411
∠B = 64.3411
∠C = 51.3178
**************
a=1b=2c=1.7320508075689
面积:0.8660
周长:        4.7320508075689
三角形三个内角A,B,C分别为:
∠A = 30.0000
∠B = 90.0000
∠C = 60.0000
**************
a=1b=1c=1.4142135623731
面积:0.5000
周长:        3.4142135623731
三角形三个内角A,B,C分别为:
∠A = 45.0000
∠B = 45.0000
∠C = 90.0000
----cut line----
新的周长:18
a=6b=6c=6
面积:15.5885
周长:        18
三角形三个内角A,B,C分别为:
∠A = 60.0000
∠B = 60.0000
∠C = 60.0000


好啦,这就是小冰所了解的Lua面向对象方式。
初出茅庐,可能对某些知识了解的不够透彻,希望朋友们来教教小冰哟。
小甲鱼:Programming change the world.

lovingxiaobing 发表于 2018-7-22 21:34

本帖最后由 lovingxiaobing 于 2018-7-23 13:40 编辑

emmmm,小冰总结了一下Lua面向对象的类模板。参考一下咯。

--[[
*author:小冰哟
*ps:小冰总结出在Lua中类的模板
--]]


local function className(参数)
local function __new__(_参数)
--利用闭包函数作为私有成员
--这里对参数的处理
--如果通过。默认返回true
       return true
end

if not __new__(参数) then return nil end

--通过局部定义的方式来生成不同的表
        local _className = {}
       
        --私有成员,但不可通过self操作
        local var = xxx
       
        --初始化,_className命名空间内定义self作为类的实例对象
        function _className:__init__(参数)
                local ob = {}
                --在_className命名空间内,此时的self就_className的别名
                setmetatable(ob,self)
                self.__index = self
                --保护基础类
                self.__metatable = ob
                self.__tostring = ob
               
                --初始化对象的成员,公有成员
                self.xxx = xxx
               
                return ob
        end
       
        --公有成员
        function _className:methodName(参数)
          --类的实例对象self.xxx
        end
       
        local ret = _className:__init__(参数)
        ret.__init__ = ret --防止再次调用重构
       
        return ret
end

--继承(不推荐)
--缺点,不能访问父类的私有成员
local function myClassName(参数)
    local _class = className(_参数)
   
    --私有成员
    local var = xxx
    local function methodName(参数)
      --segem.
    end
   
    --公有成员
    _class.xxx = xxx
    function _class:methodName(参数)
      --segem.
      --因为属于_className命名空间内,所以可以使用self
    end
   
    return _class
end


--实例化对象
object = className(参数)
obj = myClassName(参数)


可能存在不足,但对于小冰来说用起来暂时没什么问题,如果you有更棒的方法,欢迎在评论区留言哟,大家一起进步,一起分享知识,分享快乐。
小甲鱼:Programming changes the world.

每文 发表于 2018-7-22 21:45

不太懂欸
页: [1]
查看完整版本: Lua实现基本的面向对象