c++ OOP 设计 - 将数据成员传递给其他类 - 是否合理
c++ OOP design - passing data member to other classes - is it reasonable?
我还有一个问题,希望能让我的想法变得夏天。
假设我有以下 3 个类:
类玩家:
class Player {
private:
int positionX, positionY;
public:
void move(Board& b) {
// player changes its position on the board(move)
b.removeCharFromBoard(positionX, positionY);
positionX++;
positionY++;
// 'P' indicates a Player in the Board....
b.insertCharToBoard(positionX, positionY, 'P');
}
};
班级董事会:
class Board {
private:
// BOARD_C and BOARD_R are both "#define ..." for some integer number.
char board[BOARD_C][BOARD_R];
};
类游戏引擎:
class GameEngine {
private:
Board* board;
public:
void playTurn(const Player& p) {
p.move(board);
}
};
在您看来,GameBoard的playTurn函数将使用参数"board"调用玩家的移动函数是否合理?我需要这样做才能在棋盘数据成员中标记玩家已更改其位置。它是否保留了 OOP 基本规则?
谢谢大家,辛迪加!
是的,在这种情况下,这似乎是合理的("在这种情况下"的意思是"考虑我能猜到的关于你的GameEngine
和Board
类的语义以及它们的关联/聚合关系的性质"):
- 而是使用智能指针而不是原始指针来保存
Board
对象GameEngine
。 在这种情况下,unique_ptr
可能是您想要的,因为所有其他别名似乎都只是观察者,并且电路板对象的生存期绑定到GameEngine
对象之一。但是,如果需要共享所有权,请选择shared_ptr
.尽量不要使用原始指针、new
和delete
,因为它们会导致错误代码; - 您仍然需要在
Board
类的接口上提供公共函数来修改开发板,因为Player
将无法访问其私有成员变量(board
恰好是一个)。 - 不要
#define
秒,而是使用constexpr
值表示电路板的大小(如果您使用的是 C++11)。您可能还需要考虑使用 Boost.MultiArray 来创建安全的二维 C 样式数组。
你的方法很好。游戏引擎将用作游戏的某种控制器。多亏了它,例如,您可以过滤玩家移动,检查这种移动是否可行,或者在特定的玩家操作的情况下做其他类型的事情。
其次,对于此解决方案,您不必将玩家连接到特定的棋盘,这扩展了您其他选项的可能性,例如在棋盘之间轻松转移玩家。我认为你走得很好:)
您必须考虑您的应用程序将如何更改,以及您希望引入哪些功能。从这段代码来看,它看起来不错,但是当您引入新功能时,它会看起来像这样吗?
另一种解决方案是将仅移动逻辑放入玩家,它将更新其位置,然后您的游戏引擎将根据所有玩家当前位置更新棋盘条目。想象一下,一段时间后您将需要实现碰撞检测,然后在每个玩家更新其位置或动作后,将发生碰撞检测并纠正这些动作,并且只有在您的棋盘上才会正确更新。
很多事情已经说了,但如果我可以补充一些东西。
将Board
(无论是否private
)传递给Player
本身并不坏,并且这种设计用于多种体系结构(代码取自SFML 2.0):
void Sprite::draw(RenderTarget& target, RenderStates states) const
{
if (m_texture)
{
states.transform *= getTransform();
states.texture = m_texture;
target.draw(m_vertices, 4, Quads, states);
}
}
RenderTarget
是你的Board
.这里要了解的是,您将仅使用其公共接口(您有权访问)Board
进行操作。在上面的代码中,draw()
是在target
上用于强制其绘制某些内容的方法。
将内部对象传递给更高级别类(如Player
)的整个想法可以解释为桥接OO模式,其中接口Board
可以有多个实现,并且多个类可以实现IBoardManipulator
(或类似的东西)。
也就是说,我想说的是,遵循游戏引擎的总体思路要好得多,即:
- 注册游戏实体(在本例中为玩家)
- 捕获玩家输入
- 摘要并对播放器输入做出反应(请求移动播放器)
- 处理游戏逻辑(检查玩家是否可以移动到给定位置,如果是 - 移动他)
- 对于每个已注册的实体,
GameEngine
将调用draw()
传递Board
作为实体可以使用的目标。 - 从步骤 2 开始重复
我并不是说对于一个简单的架构来说这是必需的,但从长远来看,管理起来比处理每个类似Player
类可以对Board
做的令人讨厌的事情要容易得多。
- GL_SHADERSTORAGE_BUFFER位置是否与其他着色器位置冲突
- MESI协议和std::atomic-它是否确保所有写入立即对其他线程可见?
- "std::list::splice(std::const_iterator pos, std::list&& other)"是否保证将"其他"留空?
- 是否可以使用其他变量为变量分配值,而无需在 C++ 中更改其值?
- 对于BTreeMap和其他依赖于Ord的东西,是否有等效于C++比较器对象?
- MOVNTI 存储是否相对于由同一线程创建的其他 MOVNTI 存储重新排序?
- 在C++单元测试上下文中,抽象基类是否应将其他抽象基类作为函数参数
- 这种比较是否不一致(或者存在其他问题)?
- 了解'this'或其他参数是否为右值
- 如何在 Linux 下使用 c++ 知道文件是否被其他进程使用?
- 严格的别名是否会阻止您通过其他类型写入 char 数组?
- C++如何判断互斥体在阻塞其他线程时是否被单个线程不成比例地占用
- 当其他线程正在编写线程安全时,我是否必须互斥读操作
- 检查IP是否在其他IP网络范围内,并查找下一个可用IP
- cv::cuda::setTo()是否有其他选择
- 如何知道指针是否已在其他地方释放
- 如何检查一个字符串是否包含多个其他字符串?
- 是否可以将多个结构作为一个数据包存储在一个函数中,然后传递给其他函数并在那里提取?
- 除了系统("pause")之外,是否有其他选项可以保持可执行文件打开?
- 在代码的其他部分中对lock_gard和不使用相同的互斥锁是否安全?