具有多态性的OOP命令设计模式

问题描述 投票:0回答:1

我正在尝试使用 OOP 设计结构和原则为用户系统制作一个类似命令的界面。

所以我有一个抽象的 User 类和从它派生的不同类型的用户。

然后我有 CommandInterface 类 [获取输入字符串(用户输入拆分为 main 中的字符串?(stringstream)],它保存指向基类类型的 LoggedInUser 的指针(User *loggingInUser)并具有命令:

  • login [name] // 使界面以该用户的身份“登录”
  • signup [name] [age] [pass] 等 // 将用户添加到系统本身(不同的类)
  • exit // 如果已登录则注销,如果未登录则关闭界面

登录后,您还可以访问不同类型用户的命令(方法)。假设 User 有一个方法 print() 可以打印出所有用户数据。

User1:用户有方法a();

User2:用户有方法b();

现在如何在只有 User 类型(基类)的指针的情况下调用不同用户的不同方法?

代码(c++/伪):

#include <vector>
#include <string>
#include <unordered_map>
#include <memory>

class CommandInterface {
  static unordered_map<std::string, std::unique_ptr<Command>>> interfaceCommands = {...};
  std::shared_ptr<User> loggedUser = nullptr;
  
  // Singleton
  static CommandInterface* instance;
  CommandInterface() = default;
  std::unique_ptr<System> sys = System::getInstance(); // Instance to system which holds users (also singleton)

public:
  // Singleton
  CommandInterface(const CommandInterface& other) = delete;
  CommandInterface(CommandInterface&& other) = default;
  CommandInterface& operator=(const CommandInterface& other) = delete;
  CommandInterface& operator=(CommandInterface&& other) = default;
  ~CommandInterface() = default;
  static CommandInterface* getInstance();

  

  // Commands
  void signup(const std::string& name, uint8_t age, std::string& userType); // Adds users to System
  
  void login(const std::string& name) {
    if(loggedUser) {
      throw std::exception();
    }
    else {
      loggedUser = sys->getUser(name);
    }
  }
  
  void exitCmd() {
    if(loggedUser) {
      loggedUser = nullptr;
    }
    else {
      // Will be caught so that all the destructors are called
      // Since std::exit(0) won't call the destructors
      throw std::runtime_error("Exit.");
    }
  }
  
  
  std::shared_ptr<User> &getLoggedUser(); // Getter, used by the commands
  
  void executeCommand(const std::string& command, const std::vector<std::string>& args) {
    if(!loggedUser) {
      // Throw exception if command doesn't exist
      interfaceCommands[command]->execute(args);
    }
    else {
      // Throw exception if command doesn't exist (different users also hold static map of their commands to check)
      loggedUser->getCommand(name)->execute(args); // Some pure virtual method
    }
  }
};


class Command {
public:
  virtual ~Command() = default;
  virtual void execute(const std::vector<std::string>& args) const = 0;
};

class PrintCMD : public Command {
public:
  void execute(const std::vector<std::string>& args) const override {
    CommandInterface::getInstance()->getLoggedUser()->print();
  }
};

class ACMD : public Command {
public:
  void execute(const std::vector<std::string>& args) const override {
    CommandInterface::getInstance()->getLoggedUser()->a(); // Error Here
  }
};

class BCMD : public Command {
public:
  void execute(const std::vector<std::string>& args) const override {
    CommandInterface::getInstance()->getLoggedUser()->b(); // Error Here
  }
};

代码显示了示例实现,ACMD 和 BCMD 类中出现了 2 个错误,因为没有找到这样的方法。

那么问题是如何处理“隐藏”派生类方法的多态性?

c++ oop design-patterns command-line command
1个回答
0
投票

您所需要的只是在基类中声明虚拟方法。例如:

class User:
{
   virtual void execute(const std:vector<std::strings>& args) = 0;
}

现在,有了指向子级的 Base-Type 指针,您可以分配给子级重写的虚拟方法。

关于错误:

CommandInterface::getInstance()->getLoggedUser()->b();

尝试使用括号

(CommandInterface::getInstance()->getLoggedUser())->b(); 

还要确保这些 User 方法是公共的。

© www.soinside.com 2019 - 2024. All rights reserved.