使用策略模式设计软件的问题

Problem in designing software using strategy pattern

我目前正在实施一个小软件,我希望这个软件在 Mac OS 和 Window OS 上工作,所以我想在 [=67] 上使用 GLFW =] 环境和 Window API 用于 Windows 环境(我知道 GLFW 是跨平台的,但这不是重点..)

我的问题是设计实现问题: 我创建了一个 windowManager class 来保存 Window class 的一个实例。 Window 保留一个对象的实例,该对象是 PatternWindow,其中 PatternWindow 是一个接口。我有一个实现 PatternWindow 的对象 PatternGLFW3_VULKAN。这个 PatternGLFW3_VULKAN 有一个成员 GLFWwindow * _window,并且 PatternGLFW3_VULKANglfwCreateWindow(...).

初始化 _window
class Window : public Singleton<Window>
{
public:
  somefunction(...)
  initializePatternWindow(unique_ptr<PatternWindow>&& patternWindow)
  unique_ptr<PatternWindow> getPatternWindow(){return _patternWindow;}

private:
  unique_ptr<PatternWindow> _patternWindow;
} 

class PatternWindow
{
public:
  PatternWindow();
  virtual ~PatternWindow();

  virtual void initialize() = 0;
  virtual void destroy   () = 0;

};



class PatternGLFW3_VULKAN : public PatternWindow
{
public:
  PatternGLFW3_VULKAN ();
  ~PatternGLFW3_VULKAN();

  virtual void initialize();
  virtual void destroy();

  const GLFWwindow& getWindow() const {return *_window;}

private:
  GLFWwindow * _window;
};

我的问题是关于 PatternGLFW3_VULKAN class 中的 getWindow() 函数;我如何在 PatternWindow class 中创建虚拟 getWindow() 函数,以便在 [=80] 处获得 PatternGLFW3_VULKANGLFWwindow* window =] 时间。如果我在 Mac OS 环境中,我可以在我的 PatternWindow 中创建一个虚函数 GLFWwindow& getWindow(),但是如果我 运行 我的软件在 [=76] =]环境,patternWindowclass的虚函数getWindow()的类型GLFWwindow不正确...

如何在 PatternWindow 我的 returns GLFWwindow 或 Windows [=59] 中拥有一个虚拟 getWindow() =] 屏幕在 运行 时间?

编辑:


class PatternWindow
{
public:
  PatternWindow();
  virtual ~PatternWindow();

  virtual void initialize() = 0;
  virtual void destroy   () = 0;
  virtual /*UNKNOW TYPE AT THE COMPILATION*/ getWindow() = 0;

};
/*UNKNOW TYPE AT THE COMPILATION*/

是我的问题,我不知道如何处理它,因为当我在 Mac OS 和 Windows 实例中时获得 GLFWwindow*当我在 Windows 环境中编译时 windows API..

在我的软件的主循环中想要这样的东西

int main(int argc, char** argv)
{
//initialisation of all my managers ans the data ect..

  while(!WindowClosed(Window::getPatternWindow()->getWindow()))
  {
    //DO SOME STUFF
  }
}

你的方向是可以做到的,但你以后可能会后悔。我会从你的设置中推断出你有两个 WindowClosed() 的重载——一个的参数是 GLFWwindow,另一个的参数是 WinAPI 类型。前者会使用 GLFW 方法来检测 window 是否关闭,而后者会使用 Windows API。一个问题是组织之一:有多少文件包含 GLFW 特定的方法?也许您甚至有一个同时包含 GLFW 方法和 Win API 方法的文件?这不一定是错误的,但在漫长的 运行 中可能会很痛苦。另一个问题是这种方法与传统的面向对象方法不同。

不过,我们不要因为缺乏知识而强迫您走一条路。要使这种方法起作用,您可以使用预处理器和 typedef。如果为 Mac 编译,您将使用像 typedef PatternGLFW3_VULKAN WindowType; 这样的行。如果针对 Windows 进行编译,您将使用一行将 WindowType 定义为相应的 Windows 类型。在这些行之间进行选择将通过 #ifdef WINDOWS (或任何最合适的条件)来完成。然后 getWindow() 可以声明为 return WindowType.


更好的方法(您在评论中意识到)是将功能转移到 window 对象。使用 object.function() 而不是 function(object)。这需要在您的界面 class 中使用更多的虚函数,但好处是您的 OS 特定文件较少。

class PatternWindow
{
public:
  PatternWindow();
  virtual ~PatternWindow();

  virtual void initialize() = 0;
  virtual void destroy   () = 0;
  virtual bool closed    () = 0; // <-- New pure virtual function
};


class PatternGLFW3_VULKAN : public PatternWindow
{
public:
  PatternGLFW3_VULKAN ();
  ~PatternGLFW3_VULKAN();

  virtual void initialize();
  virtual void destroy();
  virtual bool closed();   // <-- OS-specific code is no longer in an extra file

private:
  GLFWwindow * _window;
};

然后在你的主函数中,调用将是:

while(!Window::getPatternWindow()->closed())

您可以考虑采取更进一步的措施。 (问题适当地没有足够的细节来确定这是否是一个可行的选择。)您可能不需要为您尝试做的事情多态性。假设您要使用以下声明。

class PatternWindow
{
#ifdef WINDOWS // Or whatever test is appropriate
    typedef PatternGLFW3_VULKAN * WindowType;
#else
    typedef /* Windows API type */ WindowType;
#endif
public:
  PatternWindow();
  ~PatternWindow();

  void initialize();
  void destroy   ();
  bool closed    ();

private:
    WindowType _window;
};

此接口不再支持多态性。那是一件坏事?您是否需要在单个操作系统下从PatternWindow派生多个classes?也许不是。这是此 class.

的潜在实现文件
#include "PatternWindow.h"

#ifdef WINDOWS // Or whatever test is appropriate
#include "PatternWinAPI.src"  // <-- File with an implementation based on Win API 
#else
#include "PatternGLFW.src"    // <-- File with an implementation based on GLFW
#endif

如果您不喜欢 .src 扩展名,请使用其他扩展名。只是不要让这些文件看起来像是要自己编译的东西。每个文件都有一个适合它使用的 API 的实现。例如,PatternGLFW.src 可能包含如下函数定义。

void PatternWindow::initialize()
{
    _window = glfwCreateWindow(...);
    // Etc.
}

这消除了多态性的开销并且似乎没有引入编码负担。此外,您不必跟踪哪些操作系统需要哪些文件(更简单的构建设置)。不过,PatternWindow.cpp 的组织并不常见。