我并不是游戏开发的从业人员,甚至连软件开发都不是,但至少我是程序员。
我认为,一个【面向对象】的理念在学习过程中的重要性远大于对于代码本身含义的认识。 这一点可以在诸多书籍中得到论证,但很奇怪的一件事是,绝大部分的视频入门教程和并没有过多的强调这一点。
系列收藏夹:https://cowlevel.net/collection/3476202
嘿,你做的不错!你已经有了一个计算器对嘛?
或者你没有,因为这没必要。我要做的并不是要告诉你们计算器要怎么写,而是要怎么吧一个过程更加的面向对象
那么换个问题,你们已经了解到了一些简单的,封装和职责之类的事情对吧。
但是我们并没有从其中收获好处,反而增加了我们的工作量
0需求
那么这部分我们就开始着手准备一些真正使我们受益的工作
或许你还记得,我们使用了
- number *= 10
- number += num
复制代码
来增加我们数字的位数,而且他很有用。正在你非常高兴的时候,你(内心中的)老板敲了敲你的桌子“嗨,你的计算器做的不错,可惜它只能计算软件提供的数字,我们的客户需要它能计算其他的一些什么,比如一个分数?”
显然,违逆老板不是一个好的选择,你只能去修改你的代码
这部分很复杂,但是我会尽力将他讲的通俗。
通俗并不是什么好事,但在这种情况下是必要的
1功能分析
显然我们需要一个数字,这个数字可以决定并改变自己的类型,当我们输入新内容,这个数字将把新内容加入他们自己的后方,然后这个数字可以与其他数字做加减法。
再附加一个额外功能,我们会比较数字的种类,让复杂的数主导运算。
因此,我们设计分为两个部分,一个万能数,代表一个数字,维护着数字类型和数字内容,以及一个抽象的数字,完成数字内容的工作
2抽象数
我们的第一个抽象数实现他本来的功能
- var number = 0
- var nClass = "AbsBaseNumber"
- func get_class():
- return nClass
- pass
复制代码
显然Godot的get_class并不是这么好用
- func set_number(num):
- number = num
- pass
- func can_push(num):
- return (num is int)
- pass
复制代码
对输入的内容进行判断,而符合基本数字要求的是int
- func push_number(num):
- number *= 10
- number += num
- pass
复制代码
把输入的num推到自己的数据内
- func get_data():
- return number
- pass
- func get_number():
- return str(number)
- pass
复制代码
使用number会得到一个可显示的字符串,
而使用data则可以获得一个可使用的data,这个data并不一定是实际上的数,可能会包含许多信息,这些信息会被负责计算的数字加以运用
由于我们现在只有一类抽象数,并不需要考虑一个高级抽象数被从一个低级抽象数转换所需要的内容
同样,我们也没有考虑当高级抽象数运算时,get_data()该如何运作,或许在处理高级数字的时候,我们需要先获取他的类,再用独特的算法对应处理这个数字
3数
在有了抽象的数字后,我们使用一个数字类来控制抽象数字
- func push_number(num):
- if number.can_push(num) :
- number.push_number(num)
- pass
复制代码
用来向数字推入一个符号,由于我们只有一种抽象数,因此并没有考虑无法推入数字的情况。
我们在未来会加入“升级”方式,逐个询问抽象数,直到有一个肯接受我们的输入
- func get_data():
- return number
- pass
- func get_number():
- return number.get_number()
- get_data会获取数所表示的抽象数,而get_number则会返回一个可显示在屏幕上的字符串
- func set_number(num):
- number = num
- pass
- func can_operation(num):
- return NM[number.get_class()] >= NM[num.get_data().get_class()]
- pass
复制代码
判断当前抽象数能否控制这个运算,或许未来会有更复杂的环境需要更复杂的条件
我们既然已经把增加数字和获取显示的功能交给数字处理
我们要更改核心逻辑处理相应事物的部分,
把他们修改成 get_number()和push_number()
4运算
到现在为止都一切顺利,但是运算的职能被我们交给了math类来做
现在我们要收回这部分功能
但,慢着,我们把一个简单的数字变成了一个复杂的三层结构
我们现在需要 万能数→ 抽象数→ 数
在抽象的部分,他可以知道他自己,我们通过更高层的逻辑来限制输入的抽象数在他处理范围之内。
number是自身存储的数据,而num是传入的抽象数,我们使用get_data来获取对方存储的数据加以运算
- func do_add(num, ans):
- ans.set_number(number + num.get_data())
- return ans
- pass
- func do_sub(num, ans):
- ans.set_number(number - num.get_data())
- return ans
- pass
复制代码
将当前数字作为运算的控制者时,会先调用被控制的data,并返回一个抽象数ans
而在万能数的部分,我们需要根据自己的抽象数建立一个相同等级的抽象数作为答案接收,放入一个万能数的答题卡
number是自身存储的抽象数,为了保证存储答案的部分等级与其本身相同,我们使用自身存储来赋值一个临时变量来接受答案
num是传入的一个万能数,我们使用get_data来拿到他的抽象数
把对方的抽象数交给自身抽象数进行处理,我们在此之前需要完成等级判定
- func operation(num, type, ans):
- var tNum = number
- if type == BusiLogic.BT["ADD"]:
- number.do_add(num.get_data(), tNum)
- ans.set_number(tNum)
- elif type == BusiLogic.BT["SUB"]:
- number.do_sub(num.get_data(), tNum)
- ans.set_number(tNum)
- elif type == BusiLogic.BT["EQU"]:
- ans = self
- else :
- ans.set_number( tNum.set_number(0) )
- return ans
- pass
复制代码
而最后,我们需要改写这项工作之前的主人
创建一个新的万能数,作为答案存储
- var tNum = MyNumber.new()
- if num1.can_operation(form[0]):
- tNum = num1.operation(form[0], symb, tNum)
- else:
- tNum = form[0].operation(num1, symb, tNum)
复制代码
选择合适的控制者控制整个运算
系列文章
面向对象的程序设计在游戏开发中使用(一):类
面向对象的程序设计在游戏开发中使用(二):方法
面向对象的程序设计在游戏开发中使用(三):三大特性
面向对象的程序设计在游戏开发中使用(四):五大原则
面向对象的程序设计在游戏开发中使用(五):基本计算器
面向对象的程序设计在游戏开发中使用(六):数与抽象数面向对象的程序设计在游戏开发中使用(七):享受劳动果实
作者:Kingfeng
来源:奶牛关
原地址:https://cowlevel.net/article/2053862