抽象与现实——关于HIT 软件构造 lab2 P3 Playing chess的一些想法

在HIT软件构造课的lab2中,最后一个问题P3的要求是让我们从零开始设计一套ADT,并实现特定功能(就是围棋与国际象棋的基本操作)

在此前,实验的所有问题基本上都是按照已给出的代码,阅读规约来完成代码,实现规约里函数的功能,但是这个问题要求的是我们从头开始自行设计,可能许多的同学,包括我,都会感到头疼和无处下手

经过一个多星期的努力,我最终还是很好地解决了这个问题,下面就分享一下我是如何一步一步解决抽象与现实之间的联系这个难题。

我们知道,将一个现实存在的东西抽象化,需要了解这个现实存在物体的主要特征和性质。我们需要关心的是这个物体抽象之后能够核心地影响抽象物体本质的东西,例如在本次实验中,棋盘作为现实物体拥有的大小这个性质是能够影响抽象中的下棋游戏的,但是棋盘作为现实物体必须拥有的的颜色、重量等性质,与抽象中的下棋游戏毫无关联。

所以我们就从这个层面入手,看一看这两个棋类游戏抽象之后必须保存的性质。

在实验手册中,实验的建议给出了6个类:

使用 Java OOP 实现一个简单的棋类模拟软件。为“一盘棋类游戏”、“玩家”、“棋盘”、“棋子”、“棋盘上的位置”、“下棋动作”设计
ADT(类或 接口),命名分别为 Game、Player、Board、Piece、Position、Action。如果针对不同的棋类游戏需要从这些类派生子类或者实现接口,请自行进行设计。

我们需要了解游戏最后的的需求,我们所有的设计都是为了最后实现这些需求

(1) 让用户选择创建一盘国际象棋或一盘围棋,用户输入“chess”或“go” 分别代表国际象棋和围棋;让用户输入两个玩家的名字;
(2) 启动比赛,程序提示玩家双方交替采取行动,直到一方输入“end”而结 束。双方分别采取行动的时候,可以选择以下行为之一,也可以选择“跳 过”(即放弃本次采取行动的权利):
⚫ 将尚未在棋盘上的一颗棋子放在棋盘上的指定位置;
⚫ 移动棋盘上某个位置的棋子至新位置;
⚫ 提子或吃子;
⚫ 查询某个位置的占用情况(空闲,或者被哪一方的什么棋子所占用);
⚫ 计算两个玩家分别在棋盘上的棋子总数。
请自行为用户设计针对上述行为所需输入的数据,用户输入越简洁越好。
(3) 当某一方输入 end 结束游戏之后,双方可以查看本次比赛的走棋历史, 即能够查询自己所走的所有步骤。

那么我们就从这6个类入手,对整个棋类游戏进行架构设计。虽然突然进行架构设计会让人感到疑惑,但是这是抽象的第一步:对整个项目进行最初步的抽象

我个人做架构的顺序是喜欢从下到上,并从中间辐射来检查架构的正确性,并且要拥有极强的严格性,仅有上一级能管控下一级,不允许越级处理。6个类中,我们可以很容易地找到架构的最上层:Game类(用于管理全部类),同样可以找到架构的最下层:Piece类和Position类(不能管理其他类,但却被其他类管理),那么我们就从最下层开始考虑。

我们在考虑最下层的时候,需要考虑能够控制它的上层。我认为作为Position类,Piece类能够控制Position(棋子需要拥有坐标),Board类也能控制Position类(棋盘上有坐标系,有坐标),所以初步构建为Position类为最底层,Piece类和Board类能够控制Position类。

接下来是Piece类和Board类。Piece类映射到现实中是棋子,棋子能被玩家,也就是抽象中的Player类管控,同样的,棋子需要放在棋盘上,所以Piece类也被Board类管控。

然后是Action类,由于只有玩家才有能力行动(改变棋子状态),显然Action类被Player类管控

最后是Game,Player和Board的关系。我个人认为玩家虽然能改变棋子状态,但不应该直接改变棋子在棋盘上的状态,应该交由Game类来管控,所以Player类与Board类由Game类管控

初步架构设计
完成初步架构设计之后,我们进入第二步,开始一一抽象每个类,尽量覆盖完全所有能够影响到最后的抽象棋类游戏的性质。(前面3个会较为细致的介绍,包括方法也会介绍在内)

  1. Posiiton类
    Positon类作为抽象前的坐标,最重要的就是横坐标x与纵坐标y,所以抽象之后仍然需要这两个参数作为其核心性质,同时需要Getter方法和修改坐标的方法。

  2. Piece类
    Piece类作为抽象前的棋子,需要有其坐标、颜色、类型(国际象棋专属)以及状态,其中状态是高度抽象的内容,用于判断棋子的摆放状态(已放置,未放置,被移除等)。Piece类需要的方法除了Getter和Setter之外,还要能改变棋子状态,棋子位置等

  3. Action类
    我思考过设立Action类的目的是什么,因为Player类也能直接更改Piece类。我认为原因是为了增加内聚度,降低耦合度。Player类如果仅能调用Action类的话,能使Player类的内聚度更高,而Player类和Piece类的耦合度会大大降低
    Action类作为抽象前的玩家动作,只需要落子、提子(围棋专属)和移动棋子、吃子(国际象棋专属),并没有特别的操作,我认为这样就可以了,管理Piece类的方法就是通过前面Piece类给出的方法改变棋子状态和位置等。

  4. Board类
    Board类作为抽象前的棋盘,需要有棋盘大小以及抽象的棋盘数据结构来摆放(存储)棋子。我认为用一个二维数组来存储棋子是不错的选择,那么二维数组的index就是坐标,不需要Position类了,所以把Board管理Position类从架构中删除,方法略过。

    此时的架构图更改为下图
    在这里插入图片描述

  5. Player类
    Player类作为抽象前的玩家,需要有名字,一个棋子库,行动能力,以及题目的要求下棋历史。棋子库指的是玩家在棋盘上的棋子(毕竟统计不在场的棋子没有意义,属于无关性质),方法略过。

  6. Game类
    Game类属于高度抽象类型,我们在最后客户端需要能够且只能够调用Game中的方法来实现整个游戏。所以Game里需要有上文提到过的所有客户端需要的操作,具体的不再展开。

到此结束。我认为通过以上过程,我们能够较好地抽象出一套我们所需要的抽象类型,虽然可能在抽象过程中部分方法其实最后没有用上,部分必需的方法没有设计,但是我们还是有了一定的头绪,能够完成开发,在开发中继续完善自己的设计。

最后贴两张我自己最初设计的图,其实和最终的设计还是有很大差距的,但是想要一开始就设计的完美无缺是不可能的事情,但是我们有了思路,在写代码的同时能够不断地更改和完善自己的设计,能够更好地理解需求,完成任务。
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值