C++ 这是设计还是工程? 你会考虑使用一个接口和多态性来扩展这个设计吗?

C++ 这是设计还是工程? 你会考虑使用一个接口和多态性来扩展这个设计吗?,c++,polymorphism,C++,Polymorphism,专业人士 可扩展 封装 自动魔法 缺点 更多的代码 使用起来有点笨重(必须使用不同的类型名称才能获得不同的行为) 由于虚拟函数调用,可能使用效率较低 我的直觉是,对于这种特殊情况,单个if语句和布尔标志是更好的选择,但并非所有人都同意我的观点 你觉得怎么样 原创 // Connects to a local pipe, and naturally // owns that connection struct CommandWriter { CommandWriter() {

专业人士

  • 可扩展
  • 封装
  • 自动魔法
缺点

  • 更多的代码
  • 使用起来有点笨重(必须使用不同的类型名称才能获得不同的行为)
  • 由于虚拟函数调用,可能使用效率较低
我的直觉是,对于这种特殊情况,单个
if
语句和布尔标志是更好的选择,但并非所有人都同意我的观点

你觉得怎么样


原创

// Connects to a local pipe, and naturally
// owns that connection
struct CommandWriter
{
   CommandWriter() {
       fd = open("/path/to/fifo", O_WRONLY);
       if (fd == -1)
           throw std::runtime_error("Could not establish connection to FIFO");
   };

   ~CommandWriter() {
       close(fd);
   };

   // (Has useful member functions here)

   private:
      CommandWriter(CommandWriter const&); // Not relevant to question

      int fd;
};
使用布尔标志扩展

// Adds a constructor where an FD can be specified
// from the call site, and no ownership is taken
struct CommandWriter
{
   CommandWriter() : owns_fd(true) {
       fd = open("/path/to/fifo", O_WRONLY);
       if (fd == -1)
           throw std::runtime_error("Could not establish connection to FIFO");
   };

   CommandWriter(int fd) : fd(fd), owns_fd(false) {};

   ~CommandWriter() {
       if (owns_fd)
          close(fd);
   };

   // (Has useful member functions here)

   private:
      CommandWriter(CommandWriter const&); // Not relevant to question

      int  fd;
      bool owns_fd;
};
用多态性扩展

// Sorry for the poor type names!
struct ICommandWriter
{
   virtual ICommandWriter() {}

   // (Has useful member functions here)

   private:
      ICommandWriter(ICommandWriter const&); // Not relevant to question
};

struct CommandWriter_Connects : ICommandWriter
{
   CommandWriter_Connects() {
       fd = open("/path/to/fifo", O_WRONLY);
       if (fd == -1)
           throw std::runtime_error("Could not establish connection to FIFO");
   };

   ~CommandWriter_Connects() {
       close(fd);
   };

   // (Has useful member functions here)

   private:
      int fd;
};

struct CommandWriter_Uses : ICommandWriter
{
   CommandWriter_Uses(int fd) : fd(fd) {};

   ~CommandWriter_Uses() {};

   // (Has useful member functions here)

   private:
      int fd;
};

这取决于你要用它做什么。如果您有一个大型项目,并且将多次使用该类的变体,那么使其灵活无疑是有意义的

经验法则:

  • 使用它一次-只是保持简单
  • 使用两次-保持简单,并根据需要进行复制和更改
  • 三个或更多-将其推广并使其适用于所有情况

  • 当然也有很多例外,但这是一个起点。

    我同意你的观点,如果你不希望在将来添加更多的功能,布尔解决方案在这里是合适的


    另一种解决方案是使用。这类似于Boost的智能指针的自定义删除器。

    < P>我会考虑工程方面的问题。第二个代码段更加简洁,使用起来也很简单。使用标志来表示对对象的所有权并不是完全惯用的,但它可以经常看到,所以我认为大多数人会很快理解其意图

    保持简单和愚蠢。

    (如果确定将来需要添加更多的代码路径,我更喜欢多态解决方案)。

    为什么不只添加文件描述符?这样,当对象被销毁时,您只需关闭()它,让操作系统处理其余部分:

    CommandWriter::CommandWriter (int _fd) : fd (dup (_fd)) {};
    

    为此添加布尔标志就是发明了一个轮子。使用多态性正在建造一架护卫直升机。

    我更喜欢界面。原因是,界面的用户很清楚,可以有各种实现。也许在一个月后,您需要实现一个CommandWriter,它可以写入db而不是文件(当然,您甚至可以将布尔版本子类化,但对于用户来说,它作为一个界面并不明显)

    对于单元测试,我想说接口是更干净的方法,因为您可以为要测试的类实现存根,这些类使用ICommandWriter


    但是如上所述,如果只想使用一次,只需使用带有布尔标志的版本。

    在多态性代码中:

    // (Has useful member functions here)
    
    是吗?如果在这三个地方(基类和两个派生类)都有很多成员函数,那么拥有和不拥有的编写器就完全不同了。最好将它们划分为不同的类,而不是让一个类根据调用构造函数的布尔标志集的行为非常不同


    我怀疑所有有用的成员函数都在基类中,而所有派生类所做的只是更改构造和销毁。在这种情况下,我需要一个
    smart\u fd
    类来保存一个fd并知道如何处理它(您需要两种情况-调用close或不执行任何操作。
    shared\u ptr
    允许任意销毁函数,但这里可能不需要)

    然后在您的CommandWriter中有一个,并根据调用CommandWriter的构造函数的不同来初始化它


    经验法则:管理资源的类不应该做任何其他事情。

    “过度工程”是一个主观概念,或者至少取决于上下文;您打算如何处理此代码?(为什么所有这些结构,“类”在你看来这么难看?@Raveline:我选择
    struct
    还是
    class
    ,都没有关系。我决定对问题中的代码使用
    struct
    ,以节省使用无意义的
    public:
    说明符所浪费的空间。为什么您不喜欢结构体?期望值通常是模糊的。我想说的是:暂时保留布尔值,如果将来在添加功能时变得混乱,如果有必要,则重构它。+1用于使整个问题变得毫无意义(至少对于这个假设性问题得到证实的现实情况是如此)。:)+1:这里的关键洞察:如果你发现自己正忙于这样的
    ,我应该使用条件或变形来表达备选方案
    决策吗,退后一步,问问你自己
    我需要备选方案吗?
    .a.k.a。“一,二,很多”。程序员不需要能够计数;-)@史蒂夫:特别是因为任何超过两次的事情都会在一个循环中发生…;)我认为是这样的(他说,链接到一篇文章,该文章将你的短语列为一个可接受的变体)。“尽管我怀疑所有有用的成员函数都在基类中,[…]”的确如此。
    smart\u fd
    。尽可能多地使用一些智能指针或其他接口,不要更多。可能
    范围内的ptr
    就是模型。例如,如果
    CommandWriter
    是不可复制的,那么我们的
    smart\u fd
    至少目前不需要。