Lua面向对象设计

  面向对象的基础是类,但Lua中没有提供类的概念,所以我们需要利用Lua现有的机制来实现类似于类的有关oop的一整套概念。基本方案是使用table来实现类机制,并且结合使用self参数和冒号操作。我们先来看看self参数和冒号操作符的用法:

  self参数的使用是很多面向对象语言的要点,大多数OO语言将这种机制隐藏起来,这样程序员不必声明这个参数(虽然仍然可以在方法内使用这个参数)。Lua也提供了通过使用冒号操作符来隐藏这个参数的声明(通过冒号来声明函数)。先来看下这段代码(这里面还不涉及到类的定义,只是纯粹为了解释self和冒号操作):

Account = {balance = 0}

function Account.withdraw(obj, v)
    obj.balance = obj.balance + v
end

a = Account
a.withdraw(a, 100)
print(a.balance)

  也可以将函数写成这样(将obj换成self能更好的表达出该参数的语义):

function Account.withdraw(self, v)
    self.balance = self.balance + v
end

  self本身是一个Lua的保留字,为了不必给每个函数声明都加上self,Lua提供了冒号操作符:

function Account:withdraw (v)
    self.balance = self.balance - v
end

  定义函数时将点改成冒号,函数体内部直接用self参数访问对象自己(self参数表示表自己,也就是对象本身)。同时函数调用也有两种写法,并且这两种写法是通用的:

a.withdraw(a, 100)
a:withdraw(100)

  点操作需要显示传入调用者自身。实际上,冒号的效果相当于在函数定义和函数调用的时候,增加一个额外的隐藏参数。这种方式只是提供了一种方便的语法,并没有什么新的内容。我们可以使用dot语法定义函数而用冒号语法调用函数,反之亦然,只要我们正确的处理好额外的 参。

  Lua中的表其实是一个对象。我们定义一个表作为原型(相当于类定义),然后其他的对象(也是一个表)通过metatable和__index机制来访问原型表中的成员。下面看下类的实现:

Account = {balance = 0}

--将表自己做成metatable,或者也可以在表中加入一个mt成员来作为metatable
function Account:new(o)
    o = o or {}
    setmetatable(o, self)
    self.__index = self
    return o
end

function Account:withdraw(v)
    self.balance = self.balance - v
end

function Account:deposit(v)
    self.balance = self.balance + v
end

a1 = Account:new{}
a2 = Account:new{balance = 100}
a1:withdraw(100)
print(a1.balance)
print(a2.balance)

  为了简洁,直接将类本身定为对象表的metatable。上面的new函数还是有一定的技巧性的,之前用过C++/Java等语言的人,应该不太习惯这种写法。因为在强类型语言中,编程者会尽量避免倾向于展示技巧的写法,而使用更简单、可读性更高的写法。但在使用Lua时需要转换一下思维,尤其是在基于Lua基础的东西来扩展一些概念的时候,各种技巧性的东西会很常见,要习惯。

  类继承的实现其实很简单,直接调用基类的new操作,然后在子类中可以添加一些新的成员或方法:

-- 继承自Account的类(其实就是一个Account对象),SpecialAcount可以重新定义继承来的成员函数,或添加新的成员函数
SpecialAccount = Account:new()

-- 子类实例化,有趣之处是,s的metatable是SpecialAccount
s = SpecialAccount:new{limit = 1000}

  可以看到,其实上面的类也是对象,只是看你怎么去理解它,当把一个对象当做模板原型来用时,它就是一个类,但同时,它也是一个对象,很随意有木有。

  多继承:多继承的想法很简单,就是对于子类中不存在的域,在多个父类中依次查找即可。不过此代码有点复杂,如下所示:

Named = {name = "default"}
function Named:getname() return self.name end
function Named:setname(v) self.name = v end

--k为函数名,list为父类列表
search = function(k, list)
    for i = 1, table.getn(list) do
        local v = list[i][k]        -- 访问第i个父类的k域,存在则返回
        if v then return v end
    end
end

-- 参数为父类列表
createClass = function (...)
    c = {}

    -- 这里面的k为访问的域
    setmetatable(c, {__index = function(t, k) return search(k, arg)   end})

    -- 用作对象的metatable
    c.__index = c
    function c:new(o)
        o = o or {}
        setmetatable(o, c)
        return o
    end

    return c
end

NamedAccount = createClass(Account, Named)
obj = NamedAccount:new{name = "Paul"}
print(obj:getname())

  函数search表示在父类列表list中依次查找名字为k的域。

  函数createClass用于创建多继承的类,参数为父类列表。可以看到对象以多继承类为metatable,而多继承类通过metatable在多个父类中依次查找域。

Lua面向对象设计

时间: 2024-10-06 15:33:51

Lua面向对象设计的相关文章

Lua面向对象设计(转)

首先对于Lua语言,它没有打算被用来进行大型的程序设计,相反,Lua目标定于小型到中型的程序设计,通常是作为大型系统的一部分,所以它只提供了一套精简的元素,很多高级语言的概念都没有.这样Lua就成为了一个既简单又灵活的轻量级语言,但是基本上高级语言中的大多数机制都可以在现有Lua的基础上加以实现. 面向对象的基础是类,但Lua中没有提供类的概念,所以我们需要利用Lua现有的机制来实现类似于类的有关oop的一整套概念.基本方案是使用table来实现类机制,并且结合使用self参数和冒号操作.我们先

让lua面向对象--lua和android

让lua面向对象 lua本身不支持面向对象的特性,但是由于lua是基于原型(prototype)的语言,要实现面向对象的特性也是有一定的方法的,实现方式有很多种, 总结了一下我最近对使用lua实现面向对象的特性,主要可以分为以下两种不同的方式来实现: 1.使用metatable的__index域实现,实现的时候需要利用的lua语言的一些特性才可以实现,主要有: a.将table b作为table a的一个prototype的方法:setmetatable(a, {__index = b}); b

7种面向对象设计的强大之处

凭什么要用面向对象来编程,不用是否可以?今天我们通过讲这么几个设计原则来说明为什么要用面向对象,它的好处在哪里. 一.单一职责原则: 全称:“Single-Responsibility Principle”面向对象设计 说明:就一个类而言,应该只专注于做一件事和仅有一个引起它变化的原因.所谓职责,我们可以理解他为功能,就是设计的这个类功能应该只有一个,而不是两个或更多.也可以理解为引用变化的原因,当你发现有两个变化会要求我们修改这个类,那么你就要考虑撤分这个类了.因为职责是变化的一个轴线,当需求

Java程序员应该了解的10个面向对象设计原则

面向对象设计原则: 是OOPS(Object-Oriented Programming System,面向对象的程序设计系统)编程的核心,但大多数Java程序员追逐像Singleton.Decorator.Observer这样的设计模式,而不重视面向对象的分析和设计.甚至还有经验丰富的Java程序员没有听说过OOPS和SOLID设计原则,他们根本不知道设计原则的好处,也不知道如何依照这些原则来进行编程. 众所周知,Java编程最基本的原则就是要追求高内聚和低耦合的解决方案和代码模块设计.查看Ap

设计模式2 面向对象设计原则

面向对象设计原则  原则的目的 面向对象设计原创表  单一职责原则案例 开闭原则 案例 依赖倒转原则 案例 面向对象设计原则  对于面向对象软件系统的设计而言,在支持可维护性的同时,提高系统的可复用性是一个至关重要的问题,如何同时提高一个软件系统的可维护性和可复用性是面向对象设计需要解决的核心问题之一.在面向对象设计中,可维护性的复用是以设计原则为基础的.每一个原则都蕴含一些面向对象设计的思想,可以从不同的角度提升一个软件结构的设计水平.  面向对象设计原则为支持可维护性复用而诞生,这些原则蕴含

面向对象设计原则

七大原则:开闭原则.里氏代换原则.依赖倒转原则.合成/聚合复用原则.迪米特法则.接口隔离原则,单一职责原则. 开闭原则是面向对象的可复用的基石.其他六种原则是手段和工具. 各规则详细(本部分为转载) http://kb.cnblogs.com/page/214010/ 正如牛顿三大定律在经典力学中的位置一样,“开-闭”原则(Open-Closed Principle)是面向对象的可复用设计(Object Oriented Design或OOD)的基石.其他设计原则(里氏代换原则.依赖倒转原则.合

面向对象设计的SOLID原则

S.O.L.I.D是面向对象设计和编程(OOD&OOP)中几个重要编码原则(Programming Priciple)的首字母缩写. SRP The Single Responsibility Principle 单一责任原则 OCP The Open Closed Principle  开放封闭原则 LSP The Liskov Substitution Principle 里氏替换原则 DIP The Dependency Inversion Principle 依赖倒置原则 ISP The

软件工程概论第八章--面向对象设计

面向对象设计主要讲设计的概念.软件体系结构.系统设计.详细设计.应用设计模式.用户界面设计和设计文档等方面知识,面向对象的设计是面向对象技术中比较重要的阶段. 设计的概念中讲了设计活动和设计原则,设计是一个建模活动,此活动能实现从需求分析到软件实现间的跨越.设计原则主要有模块化.耦合度和内聚性和复用性,模块化可以使复杂的系统简化,耦合度和内聚性分别是子系统间的关联程度和系统内部的相关程度,降低耦合性提高内聚性.复用性利用以开发的软件元素生成新的软件系统. 软件体系结构主要有仓库体系结构,分层体系

【设计模式】#001 面向对象设计的八个原则

1.对于面向对象的软件系统设计来说,在支持可维护性的同事,需要提高系统的可复用性 2.软件的复用可以提高软件的开发效率,提高软件的质量,节约开发成本,恰当的复用还可以改善系统的可维护性 3.面向对象设计简化成三条 3.1 封装变化点 3.2 对接口编程 3.3 多使用组合,少使用继承 点击查看大图: