整体架构设计思路
- 抽象层设计:设计一个抽象基类
SystemCommandExecutor
,定义执行系统命令的接口,例如 executeCommand(const std::string& command)
。然后针对不同操作系统,派生出具体的实现类,如 WindowsCommandExecutor
、LinuxCommandExecutor
和 MacOSCommandExecutor
。这样可以将不同操作系统的具体实现细节封装起来,对外提供统一的接口。
- 命令语法差异处理:
- 在每个具体实现类中,针对不同系统的命令语法进行适配。例如,在 Windows 中命令分隔符可能是
&&
,而在 Linux 和 macOS 中是 ;
。可以在每个实现类的 executeCommand
方法中对传入的命令字符串进行预处理,将通用的命令分隔符转换为对应系统的实际分隔符。
- 不同系统下一些命令的参数格式也可能不同,例如获取文件列表,Windows 下是
dir
,Linux 和 macOS 下是 ls
。可以在具体实现类中维护一个命令映射表,将通用命令映射到对应系统的实际命令。
- 性能优化策略:
- 进程复用:对于类 Unix 系统(Linux 和 macOS),可以使用
popen
函数结合管道来复用进程。例如,在执行多个相关命令时,可以先打开一个管道,通过该管道依次发送不同的命令,而不是每次都启动新的进程。对于 Windows,可以使用 CreateProcess
并结合管道来实现类似的效果,但具体实现细节有所不同。
- 缓存机制:对于一些经常执行的命令,可以使用缓存机制。例如,在执行获取系统环境变量的命令时,如果已经执行过一次,可以将结果缓存起来,下次直接返回缓存结果,避免重复执行命令。
关键代码片段示例
- 抽象基类定义
#include <string>
class SystemCommandExecutor {
public:
virtual std::string executeCommand(const std::string& command) = 0;
virtual ~SystemCommandExecutor() = default;
};
- Linux 具体实现类
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <memory>
class LinuxCommandExecutor : public SystemCommandExecutor {
public:
std::string executeCommand(const std::string& command) override {
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(command.c_str(), "r"), pclose);
if (!pipe) {
throw std::runtime_error("popen() failed!");
}
char buffer[128];
std::string result;
while (fgets(buffer, sizeof(buffer), pipe.get()) != nullptr) {
result += buffer;
}
return result;
}
};
- Windows 具体实现类
#include <iostream>
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
class WindowsCommandExecutor : public SystemCommandExecutor {
public:
std::string executeCommand(const std::string& command) override {
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
HANDLE hReadPipe, hWritePipe;
if (!CreatePipe(&hReadPipe, &hWritePipe, &saAttr, 0)) {
throw std::runtime_error("CreatePipe failed");
}
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.hStdError = hWritePipe;
si.hStdOutput = hWritePipe;
si.dwFlags |= STARTF_USESTDHANDLES;
ZeroMemory(&pi, sizeof(pi));
if (!CreateProcess(NULL, const_cast<LPTSTR>(_T(command.c_str())), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
CloseHandle(hReadPipe);
CloseHandle(hWritePipe);
throw std::runtime_error("CreateProcess failed");
}
CloseHandle(hWritePipe);
char buffer[128];
DWORD bytesRead;
std::string result;
while (ReadFile(hReadPipe, buffer, sizeof(buffer) - 1, &bytesRead, NULL) && bytesRead > 0) {
buffer[bytesRead] = '\0';
result += buffer;
}
CloseHandle(hReadPipe);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return result;
}
};
- 使用示例
int main() {
LinuxCommandExecutor linuxExecutor;
std::string linuxResult = linuxExecutor.executeCommand("ls -l");
std::cout << "Linux result: " << linuxResult << std::endl;
WindowsCommandExecutor windowsExecutor;
std::string windowsResult = windowsExecutor.executeCommand("dir");
std::cout << "Windows result: " << windowsResult << std::endl;
return 0;
}