【问题标题】:Is it worth it to have separate namespaces for interfaces and implementations?为接口和实现设置单独的命名空间是否值得?
【发布时间】:2014-01-26 15:37:23
【问题描述】:

为接口和实现设置单独的命名空间是否值得?

Stroustrup 在他的 C++ 书(第四版)中的建议是我们应该使用单独的命名空间 用于接口和实现。有经验的人能说一下吗 在这个?我的意思是这听起来不错,但它真的实用吗? 现实世界的项目?

【问题讨论】:

  • 如果没有意义他就不会提到它。
  • @RobertJacobs 还有其他一些 Stroustrup 的 C++ 书籍第四版吗?! :)
  • 我只是觉得你应该把整个标题放在问题的某个地方。
  • “它在现实世界的项目中有意义吗?” 是的,例如在boost 它被广泛使用。以boost::shared_ptr 为例。当我看到namespace detail 时,我立即知道我不必过多查看该代码段,除非有错误消息告诉我这样做。
  • 如果可以的话,这是一个很好的问题,我建议 OP 将其保持开放一天左右,以便获得所有可能的答案并真正挑​​选出最好的答案。我希望你不着急:D

标签: c++ c++11


【解决方案1】:

命名空间告诉您定义属于谁。当然,接口属于与实现不同的组是有意义的;这就是接口的全部意义,关注点分离。

【讨论】:

  • 基本上,我们可以将命名空间视为一个类。有时我们希望将某些部分设为私有(对于实施者),而将其他部分设为公开(对于用户)。由于我们不能使用命名空间来做到这一点,因此我们只能创建单独的命名空间。所以这就是我猜这个建议的重点。
  • @user3111311 根据类来考虑命名空间只会混淆问题。
【解决方案2】:

在执行繁重的代码中(例如,Boost 中的一些元编程怪物),一眼就能看出哪些代码可以直接使用,哪些代码可以放心忽略,这很有用.库的 detail 命名空间中的代码被视为“内部”代码,因此当您在堆栈跟踪中看到 detail 符号时,您无需花时间浏览文档。

我不会说它有巨大的好处,在一般情况下当然不是这样,但既然它不会造成任何伤害,你不妨保持事物整洁和隔离。

【讨论】:

    【解决方案3】:

    在现实世界的项目中有意义吗?

    是的,例如在 boost 中它被广泛使用。以boost::shared_ptr 为例。当我看到 namespace detail 时,我立即知道我没有过多查看该代码段,除非有错误消息告诉我这样做(即使那样,这很可能是我的错)。

    强制性设计的真实世界启发示例

    我猜你知道如何驾驶汽车。有很多接口:方向盘、油门/刹车/离合器踏板、显示器等等。你有兴趣使用这些界面,毕竟,这就是你使用汽车的方式:

    namespace the_company{
      struct wheel{
        void turnLeft(deg);
        void turnRight(deg) { turnLeft(-deg); }
      };
      struct pedal{
        void tap();  
        void press_completely_till_something_happens(); 
          //!< might deadlock if using break and car isn't moving
      };
      struct display{
        so_many_colors lookat();
      };
    }
    

    为了这个示例,我们将把它们组合成一辆车,但是将它们分成不同的命名空间不仅对 OOP 是实用的。

    namespace the_company{    
      struct car{
        public:
          wheel & getWheel();
          pedal & getBreakPedal();
          ...
      };
    }
    

    我们对car 有什么期望?我们可以期待我们可以使用汽车的车轮或踏板,它会起作用:

    car myCar;
    myCar.getGasPedal().press_completely_till_something_happens();
    
    // OH GOD; WHAT HAVE I DONE!?
    
    myCar.getWheel().turnLeft(360);
    
    myCar.getBreakPedal().press_completely_till_something_happens();
    // Shew. That was close.
    

    我们完全可以使用car。顺便说一句,我们没有将wheel 放入car,因为我们公司可能会生产其他使用轮子的东西,例如船、卡车、人造飞机、阀门和其他非车辆的东西,以及display可能会被更多不同的东西使用(电话、显示器、电视,等等)。

    然而,为了真正让汽车运转,它必须有一个引擎。由于引擎是一些相当复杂的机器,我们将它们隐藏在hood

    namespace the_company{
      namespace hood{
        struct engine{
          // heavily optimized code
          // not so nice interface anymore
          // maybe not even documentated
          ...
        };
      }
    }
    

    engine 是一头野兽,它具有可扩展性,适用于任何车辆或重型机械,而且贵公司在优化方面投入了大量精力。现在,每当车主的引擎出现问题时,他都可以简单地查看hood 并检查问题所在。

    但它隐藏在某些东西后面的事实已经从一开始就告诉用户他应该知道他将要做什么。如果他不理解金属/代码,他应该向他的服务维护/支持寻求帮助。

    此外,engine 可能会改变甚至被完全删除,因为我们公司发明了fusion_engine,它可以带来更好的利润。

    这就是namespace detail 对我的意义:复杂的细节,可能会改变,甚至可能只对原始维护者有意义。但这没关系。它不是界面的一部分。

    【讨论】:

    • 虽然这很有创意,但它是 OO 甚至命名空间使用的一个糟糕的例子,我认为它没有真正帮助:P
    • @LightnessRacesinOrbit:我根本不记得写过这个东西。一定是在醒来和第一口咖啡之间发生的。
    • 哈哈。不过,值得保留:)
    猜你喜欢
    • 1970-01-01
    • 2014-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-08
    • 1970-01-01
    • 2011-12-30
    相关资源
    最近更新 更多