当我无法访问模块之外的函数或变量时,如何在C中应用SRP原理?

发布于 2025-02-05 18:41:40 字数 2779 浏览 0 评论 0原文

我正在尝试学习将单个职责原则应用于C,但我遇到了一个问题,即我的“模块/文件”无法访问我需要的功能和变量。

例如,我正在创建这个由事件驱动的游戏,该游戏对键盘事件进行轮询,然后做某事。我想将其提取到自己的文件中,但是我无法访问所需的任何功能和变量。

也许我的架构在这里存在缺陷,我做错了。这里最好的做法是什么?

我想重构此代码。 main()的内部是对键盘输入进行轮询的主循环,然后根据按下键的键,它更改了在main.c 喜欢quit = 1plocehip()

但是根据SRP的说法,每个模块应仅对1件事负责。因此,我想将输入处理放在其自己的文件中。但是,我将无法访问main.c中的任何函数/变量 - 因为这就是主要游戏逻辑所占据的位置。

main.c

int main() {
    // ...

    int quit = 0;

    SDL_Init(SDL_INIT_EVERYTHING);
    SDL_CreateWindowAndRenderer(WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_RESIZABLE | SDL_WINDOW_MAXIMIZED, & window, & renderer);

    while (!quit) {
      while (SDL_PollEvent( & event) == 1) {
        switch (event.type) {
          case SDL_QUIT:
            quit = 1;
            break;

          case SDL_KEYDOWN:
            switch (event.key.keysym.sym) {
              case SDLK_RETURN:
                if (!isShooting) {
                  placeShip(playerShips);
                }
                break;

              case SDLK_SPACE:
                if (!isShooting) {
                  rotateShip(playerShips);
                }

                if (isShooting) {
                  shootAtOpponent(renderer, opponentShips, playerShips);
                }

                break;

              case SDLK_ESCAPE:
                quit = 1;
                break;

              case SDLK_w:
              case SDLK_UP:
                if (!isShooting) {
                  if (playerShips[placingShipIndex].rect.y != gridOffsetY) {
                    playerShips[placingShipIndex].rect.y = playerShips[placingShipIndex].rect.y - cellSize;
                  }
                }

// more code...

我很想将其重构为这样的东西:

main.c

include "input.h"

int main()
{
  // ..
  process_input();
  render();
}

input.c errors every eveywhere .... :(

int process_input()
{
  // ERROR: I do not have access to quit inside this file
    while (!quit) {
      while (SDL_PollEvent( & event) == 1) {
        switch (event.type) {
          case SDL_QUIT:
            quit = 1; // ERROR: I do not have access to quit inside this file
            break;

          case SDL_KEYDOWN:
            switch (event.key.keysym.sym) {
              case SDLK_RETURN:
                if (!isShooting) { // ERROR: I do not have access to isShooting inside this file
                  placeShip(playerShips); // ERROR: I do not have access to placeShip inside this file
                } // ERROR: I do not have access to playerShips inside this file
                break;

}

I am trying to learn to apply the Single Responsibility Principle to C but I am running into a problem where my "module/file" does not have access to the functions and variables I need.

For example, I am creating this event-driven game that polls for keyboard events and then does something. I want to extract it into it's own file but then I do not have access to any of the functions and variables that I need.

Maybe my architecture is flawed here and I'm doing it wrong. What is the best practice here?

I would like to refactor this code. Here inside of main() is the main loop that polls for keyboard input and then depending on which key was pressed, it changes variables and calls methods that are defined in main.c like quit=1 or placeShip().

But according to SRP, each module should be responsible for only 1 thing. So, I would like to put the input processing in it's own file. But then I won't have access to any of the functions/variables that are in main.c - since that is where the main game logic lives.

main.c

int main() {
    // ...

    int quit = 0;

    SDL_Init(SDL_INIT_EVERYTHING);
    SDL_CreateWindowAndRenderer(WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_RESIZABLE | SDL_WINDOW_MAXIMIZED, & window, & renderer);

    while (!quit) {
      while (SDL_PollEvent( & event) == 1) {
        switch (event.type) {
          case SDL_QUIT:
            quit = 1;
            break;

          case SDL_KEYDOWN:
            switch (event.key.keysym.sym) {
              case SDLK_RETURN:
                if (!isShooting) {
                  placeShip(playerShips);
                }
                break;

              case SDLK_SPACE:
                if (!isShooting) {
                  rotateShip(playerShips);
                }

                if (isShooting) {
                  shootAtOpponent(renderer, opponentShips, playerShips);
                }

                break;

              case SDLK_ESCAPE:
                quit = 1;
                break;

              case SDLK_w:
              case SDLK_UP:
                if (!isShooting) {
                  if (playerShips[placingShipIndex].rect.y != gridOffsetY) {
                    playerShips[placingShipIndex].rect.y = playerShips[placingShipIndex].rect.y - cellSize;
                  }
                }

// more code...

I would love to refactor this into something like this:

main.c

include "input.h"

int main()
{
  // ..
  process_input();
  render();
}

input.c ERRORS eveywhere.... :(

int process_input()
{
  // ERROR: I do not have access to quit inside this file
    while (!quit) {
      while (SDL_PollEvent( & event) == 1) {
        switch (event.type) {
          case SDL_QUIT:
            quit = 1; // ERROR: I do not have access to quit inside this file
            break;

          case SDL_KEYDOWN:
            switch (event.key.keysym.sym) {
              case SDLK_RETURN:
                if (!isShooting) { // ERROR: I do not have access to isShooting inside this file
                  placeShip(playerShips); // ERROR: I do not have access to placeShip inside this file
                } // ERROR: I do not have access to playerShips inside this file
                break;

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

爱情眠于流年 2025-02-12 18:41:40

您建议的重构,存在一个问题:process_input具有一个wird循环,直到游戏结束后才退出,因此只有在退出时才能调用Render()。一种可能性是使用您的主循环来提取事件,然后在另一个模块内进行所有处理:

include "logic.h"

static bool ProcessQuit(event)
{
   //Verify if must quit and return boolean
}

int main()
{
  // ...
  while (!quit) 
  {
     if (SDL_PollEvent(&event) == 1) 
     {
        logic_Process(event.type);

        quit = ProcessQuit(event);
     }
}

然后,在逻辑模块下,您可以具有其他功能来协助处理,甚至创建logic.c调用的其他模块。例如,您可以创建一个从logic.c调用的渲染模块
至于封装,您可以在每个模块上声明静态变量,以便仅从模块本身中看到它们。

该体系结构将是这样的:
主要(泳池事件,退出游戏)
逻辑(其他一切)
渲染(在屏幕上显示结果)

另一个选项是具有逻辑并在同一级别上渲染(两者都从MAIN调用),但是您需要弄清楚如何将数据传递到逻辑到渲染。这取决于您需要通过多少数据。如果有很多,则可以在主(上下文)上创建一个结构变量,并在每个呼叫上传递对逻辑和渲染的引用。

#include "logic.h"
#include "render.h"

typedef struct
{
  //your information
} Context_t;

static Context_t Context = {//initialization};

static bool ProcessQuit(event)
{
   //Verify if must quit and return boolean
}

int main()
{
  // ...
  while (!quit) 
  {
     if (SDL_PollEvent(&event) == 1) 
     {
        logic_Process(&Context, event.type);
        render_Process(&Context);

        quit = ProcessQuit(event);
     }
}

祝你好运!

The refactoring you propose, has the problem that process_input has a while loop that does not exit until the game is over, so you get to call render(), only when you exit. One possibility is to use your main loop just to pull events, and do all the processing inside another module:

include "logic.h"

static bool ProcessQuit(event)
{
   //Verify if must quit and return boolean
}

int main()
{
  // ...
  while (!quit) 
  {
     if (SDL_PollEvent(&event) == 1) 
     {
        logic_Process(event.type);

        quit = ProcessQuit(event);
     }
}

Then, under the logic module you can have other functions to assist the processing, or even create additional modules called by logic.c. For example, you can create a render.c module, called from logic.c
as for encapsulation, you may declare static variables on each module so that they are only seen from the module itself.

The architecture would be something like this:
main (pool events, quit game)
logic (everything else)
render (show the results on screen)

Another option will be to have logic and render at the same level (call both from main) but then, you need to figure out how to pass data from logic to render. That would depend on how much data you need to pass. If there is plenty, you may create a structure variable on main (Context), and pass a reference to both logic and render, on each call.

#include "logic.h"
#include "render.h"

typedef struct
{
  //your information
} Context_t;

static Context_t Context = {//initialization};

static bool ProcessQuit(event)
{
   //Verify if must quit and return boolean
}

int main()
{
  // ...
  while (!quit) 
  {
     if (SDL_PollEvent(&event) == 1) 
     {
        logic_Process(&Context, event.type);
        render_Process(&Context);

        quit = ProcessQuit(event);
     }
}

Good luck!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文