浅谈OOP与POP
面向对象与面向过程编程是两个相对的编程理念。这里举个例子来展示两者的区别:
假如需要你设计一个国际象棋的程序,你会怎么思考这个问题?
========================================================================================================================================================
面向过程:我会先去从头到底走一遍下棋的流程。首先,需要初始化棋局,即把棋子和棋盘放在可以开局的位置上。然后,黑白双方随机决定走棋先后顺序,并且后续根据这个顺序轮流走棋。在对弈的过程中,有可能出现三种情况:
1. 棋手走一步棋,落子之处没有对方棋子。
2. 棋手走一步棋,落子之处有对方棋子,就将对方的棋子“吃掉”。
3. 棋手走一步棋,对方的国王在下一步的时候就会被“吃掉”,这时需要检查对方在一步内是否有让国王摆脱险境的策略,若有,则棋局继续,否则宣布当前棋手获胜。
当第三种情况出现,并且确认已经将死国王的时候,棋局结束。
这就是国际象棋的完整流程,然后我应该去考虑需要的函数功能:
1. 我们需要一个函数来初始化棋局。
2. 我们需要一个函数来走棋。这个函数需要三个传参,一个是目标棋子,还有一个是目标位置,同时我要获得棋局的信息,也就是指向存储棋盘信息的数据结构的指针。在函数体中,不仅要对棋子进行移动,还要对目标位置是否存在棋子进行判定:如果这个棋子是己方棋子,则返回错误信息;如果这个棋子是对方棋子,则需要“吃掉”这个棋子,还需要考虑是不是要定义一个函数来实现“吃掉”功能。
3. 我们需要一个函数来对双方的国王的处境进行判断,即是否处在被将或者被将死的状态。
4. 我们需要一个函数来结束棋局。
========================================================================================================================================================
面向对象:我会先去把一局国际象棋中涉及到的对象抽象出来。关于对象的概念,可以初步理解为名词,比如棋手是一个名词,棋盘是一个名词,棋子是一个名词。必须注意名词和客观存在的实体的区别。那么对象的属性可以初步理解为形容词或者状语,比如有棋子的棋盘,那么棋盘这个类就需要一个属性叫棋子,用来保存棋盘上的棋子信息。特别的,虽然棋子也可以作为一个单独的类,那么我们就需要根据需求来决定是要新定义一个类来代表棋子这个对象,还是把棋子当成棋盘的一种属性。一种判断的策略是考虑棋子如果当成类,需要什么样的属性和方法。这里如果我们把棋子的移动当成棋手这个类的方法,假如叫做棋手的“走棋”方法,那么我们会发现如果单独把棋子也当成一个类,好像并不能抽象出太多的特征,所以这里我倾向于就定义两个类:棋盘和棋手。
再看类的属性和方法,先说棋盘。棋盘需要存储棋局的信息,当我拒绝定义一个棋子的类,那我有责任要把它当成棋盘的一个属性。我倾向于定义一个Directory,在JAVA中常用map接口,来保存棋子信息键值对,也就是 (key: 当前棋子ID - value: 当前位置) ,当然这样的map得来两个,因为有黑白双方,但是我倾向于在ID上体现,例如白方的棋子ID区间是0-15,黑方棋子ID区间是16-31。这样的设计会节省空间,其中还包括一个本质性的优势:白棋和黑棋并不只是颜色区别,白棋还代表了先手,而黑棋相应就是后手。通过这样的设计,我把先手的棋子ID和后手的棋子ID分隔在了15的上下,如此能带来便利,具体原因留给读者思考。那么怎么来表示这个棋子的状态是在场上还是被“吃掉”了呢?我建议在棋子被“吃掉”的时候,把它的位置设置成一个特殊值。
考虑棋盘的方法,我们可以把方法理解成动词,那么我们需要棋盘能检查双方的国王是否被将或者将死,这个方法的具体代码实现和面向过程思路基本一致,这里提供两个思路:
1. 遍历一方的所有棋子,判断它下一步能走到的所有位置中是否有对方的国王。
2. 针对两个国王,遍历每个种类的棋子下一步能到达的所有位置,检查是否真的存在该类型的对方棋子。
再说棋手。其实是否要定义棋手这个类也存在说法,典型的面向对象程序员一定会把棋手抽象出来,虽然在这个例子中如果把“走棋”这样的方法理解为棋盘的行为也没问题,但是对象的概念意味着更多的可能性,更好的应对改变的适应性,更加贴近真实世界的抽象。设想一下,如果以后你的客户说,想要一个记录棋手胜负场次的功能,或者限制每个棋手每步的走棋时间以及总的走棋时间,到那个时候你一定会感谢当时决定把棋手作为类抽象出来的自己。我的理解是,既然选择了面向对象这种风格,那就要尽可能多的去抽象对象,去考虑各种各样的情形和方法,我们并不是仅仅把下棋这个流程走完就结束了,因为面向对象赋予了我们各种各样的能力和可能性,千万要充分利用它们。
========================================================================================================================================================
经过上面的例子分析,不知道我是否把面向对象和面向过程的不同展现出来了。面向过程的风格比较适合需求固定,对优化要求较高的场景。假如上述国际象棋的小程序要求你嵌入到飞机座椅背后的小屏幕的芯片中时,那你最好面向过程。但如果是一款商业化的国际象棋游戏,那么请面向对象会有优势,你永远不知道客户会有什么样的需求。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律