Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在使用factory模式时,我是否应该以任何方式避免向下投射?_C++_Oop_Factory Pattern_Downcast - Fatal编程技术网

C++ 在使用factory模式时,我是否应该以任何方式避免向下投射?

C++ 在使用factory模式时,我是否应该以任何方式避免向下投射?,c++,oop,factory-pattern,downcast,C++,Oop,Factory Pattern,Downcast,我正在从事一个实现专有协议的服务器项目。服务器是用C++实现工厂模式的,现在面临下注问题。 我正在研究的协议是为低速网络的自动控制而设计的,如RS485、ZigBee、窄带PLC等。我们用工厂模式设计了主服务器。当接收到一个新的帧时,我们首先识别该帧的相关设备类型,调用factory方法生成一个新的“parser”实例,并将该帧分派给parser实例 我们的专有协议是用纯二进制实现的,我们可能需要的每一个信息都记录在帧本身中,因此可以尽可能简单地定义基本接口。我们还将为我们的工厂实现自动注册方法

我正在从事一个实现专有协议的服务器项目。服务器是用C++实现工厂模式的,现在面临下注问题。 我正在研究的协议是为低速网络的自动控制而设计的,如RS485、ZigBee、窄带PLC等。我们用工厂模式设计了主服务器。当接收到一个新的帧时,我们首先识别该帧的相关设备类型,调用factory方法生成一个新的“parser”实例,并将该帧分派给parser实例

我们的专有协议是用纯二进制实现的,我们可能需要的每一个信息都记录在帧本身中,因此可以尽可能简单地定义基本接口。我们还将为我们的工厂实现自动注册方法(这里省略了与std::map操作相关的详细代码):

  • 使用访问者模式实现“智能指针”,以处理从遗留解析器派生的实例:

    class smart_ptr
    {
    public:
        virtual void set(parser *p) = 0;
        virtual void set(legacy_parser *p) = 0;
    };
    
    class parser
    {
    public:
        parser() { }
        virtual int parse(unsigned char *) = 0;
        virtual void copy_ptr(smart_ptr &sp)    // implement "Visitor" pattern
        {
            sp.set(this);
        }
        virtual ~parser() { }
    };
    
    class legacy_parser : virtual public parser
    {
    public:
        legacy_parser() { }
        void copy_ptr(smart_ptr &sp)    // implement "Visitor" pattern
        {
            sp.set(this);
        }
        int parse(unsigned char *str)
        {
            /* CAN NOT DO ANYTHING WITHOUT COMPLETE FRAMES */
        }
        virtual int parse(unsigned char *header, unsigned char *payload) = 0;
    };
    
    class legacy_ptr : public smart_ptr
    {
    private:
        parser *miss;
        legacy_parser *hit;
    public:
        legacy_ptr& operator=(parser *rhv)
        {
            rhv->copy_ptr(*this);
            return *this;
        }
        void set(parser* ptr)
        {
            miss=ptr;
            /* ERROR! Do some log or throw exception */
        }
        void set(legacy_parser *ptr)
        {
            hit = ptr;
        }
        legacy_parser& operator*()
        {
            return *hit;
        }
        ~legacy_ptr()
        {
            if(miss) {
                delete miss;
            }
            if(hit) {
                delete hit;
            }
        }
    };
    
  • 很明显,对我们来说,用dynamic_cast进行降级是最简单的方法,但我们都不喜欢这个想法,因为我们都觉得降级是“邪恶的”。然而,没有人能确切地解释为什么它是“邪恶的”


    在我们做出决定之前,我希望听到更多关于这些选项的评论。

    向下广播,特别是在工厂模式实现中,对我来说非常有意义。它实际上与“程序到接口”的思想相一致。不知道为什么人们会觉得低落是不好的。这就是你所看到的。

    是你第一个邪恶的例子。
    如果您发现您可以做一些违反基本原则的事情,那么您应该发明另一个轮子或尝试另一顶帽子:

    问题是遗留的解析器需要两个帧,而不是原始解析器中的一个帧。因此,一个可能的解决方案是稍微更改原始解析器,使其能够处理多个帧。 例如,如果解析器需要更多的帧,parse可能会返回一个预定义的常量,然后遗留的\u解析器可以这样实现:

    class legacy_parser : public parser {
     public:
      int parse(unsigned char *str) {
        if (parse_header_) {
          // store str in header_
          parse_header_ = false;
          return kExpectMoreFrames;
        } else {
          return parse(header_, str);
        }
      }
     private:
      int parse(unsigned char *header, unsigned char *parload) {
        // ...
      }
      bool parse_header_;
      unsigned char *header_;
    };
    

    如果现有的解析器代码没有意外使用为“更多帧”的含义定义的值,则不会受到影响。

    @RichardLu,这个问题太长了,没有足够的耐心!尽量做到客观。@iammilind:嗯,我的问题在标题中有描述:)我们已经想出了几种方法(在我问题的剩余部分中描述)来避免降级,但我只是想知道这是否值得麻烦。你是对的……看起来我们定义派生类(遗留解析器)的方式违反了Liskov原则,因为原始方法(解析器(unsigned char*)在派生类中无效。这样做的结果可能会导致额外的错误检查过程,即使在现有代码中也是如此。看起来我们最好避免从原始接口派生遗留的解析器,因为它“根本不适合”。我们将独立处理。
    class instance_generator
    {
    public:
        virtual parser *generate() = 0;
        virtual legacy_parser *generate_legacy() { return NULL; }
    };
    
    class extended_parser_factory : public parser_factory
    {
    public:
        legacy_parser *get_legacy_instance(int id);
    };
    
    class smart_ptr
    {
    public:
        virtual void set(parser *p) = 0;
        virtual void set(legacy_parser *p) = 0;
    };
    
    class parser
    {
    public:
        parser() { }
        virtual int parse(unsigned char *) = 0;
        virtual void copy_ptr(smart_ptr &sp)    // implement "Visitor" pattern
        {
            sp.set(this);
        }
        virtual ~parser() { }
    };
    
    class legacy_parser : virtual public parser
    {
    public:
        legacy_parser() { }
        void copy_ptr(smart_ptr &sp)    // implement "Visitor" pattern
        {
            sp.set(this);
        }
        int parse(unsigned char *str)
        {
            /* CAN NOT DO ANYTHING WITHOUT COMPLETE FRAMES */
        }
        virtual int parse(unsigned char *header, unsigned char *payload) = 0;
    };
    
    class legacy_ptr : public smart_ptr
    {
    private:
        parser *miss;
        legacy_parser *hit;
    public:
        legacy_ptr& operator=(parser *rhv)
        {
            rhv->copy_ptr(*this);
            return *this;
        }
        void set(parser* ptr)
        {
            miss=ptr;
            /* ERROR! Do some log or throw exception */
        }
        void set(legacy_parser *ptr)
        {
            hit = ptr;
        }
        legacy_parser& operator*()
        {
            return *hit;
        }
        ~legacy_ptr()
        {
            if(miss) {
                delete miss;
            }
            if(hit) {
                delete hit;
            }
        }
    };
    
    class legacy_parser : public parser {
     public:
      int parse(unsigned char *str) {
        if (parse_header_) {
          // store str in header_
          parse_header_ = false;
          return kExpectMoreFrames;
        } else {
          return parse(header_, str);
        }
      }
     private:
      int parse(unsigned char *header, unsigned char *parload) {
        // ...
      }
      bool parse_header_;
      unsigned char *header_;
    };