代码之家  ›  专栏  ›  技术社区  ›  tyrondis

“程序到接口”是C++项目中常见的设计原则吗?

  •  4
  • tyrondis  · 技术社区  · 14 年前

    在过去的几天里,我读了很多关于“程序到接口”和“控制反转”的文章。主要是在Java语言的上下文中。我的问题是,它是否也是C++开发中的一种常见实践。优势是什么?缺点是什么?

    是否值得应用于小型项目(如15-20个班)?

    10 回复  |  直到 13 年前
        1
  •  6
  •   KeithS    14 年前

    您所说的原则通常适用于任何OO语言。这里的基本原则是“松耦合”。依赖于另一个类的类(包含它的一个实例并作为其自身工作的一部分调用它的方法)实际上只依赖于依赖项提供的一组功能。如果类定义了对它所依赖的具体类的引用,然后您希望用另一个类替换该类,那么您不仅需要开发新的类,而且还必须将依赖类更改为依赖于新的类型。这通常是不好的,因为如果您的类依赖于许多其他类,您必须在多个地方更改代码,要求您测试涉及这些对象的所有用例,以确保您没有破坏以前工作的功能。

    接口的设计是为了消除这一点,允许基于您知道类将实现的一组通用的、强制的方法,可以互换地使用与祖先无关的多个类。如果您依赖接口而不是依赖于类,那么实现接口的任何类都将实现依赖关系。这允许您编写一个新类来替换旧类,而不需要使用它的类知道不同之处。您需要修改的只是创建填充依赖项的类的具体实现的代码。

    这是一个困惑;当然,你的类依赖者可以说它需要一个idoothing而不是一个doorclass,但是如果依赖者知道如何创建一个doorclass来用作idoothing,你就什么也得不到;如果你想用betterdoer替换doorclass,你仍然必须更改依赖者的co。de.解决方案是给类一个依赖于第三方(创建者)的实例的责任。为此选择的类取决于上下文。如果一个类天生既有依赖者又有实干者,那么将它们组合在一起是一个显而易见的选择。当您有一个类具有两个助手依赖项,并且一个依赖项也需要另一个时,这种情况通常会发生。其他时候,您可以创建一个工厂,它可以为调用者提供一个特定对象的实例,最好是连接了所有依赖项。

    如果您有几个相互依赖的类,或者依赖于许多层次,那么您可以考虑使用IOC框架。IOC容器对工厂来说就像对DAOS的存储库一样;它们知道如何为需要一个或多个依赖项的任何类提供一个完全水合的实例,就像存储库可以从数据库中的数据生成任何完全水合的域对象一样。它通过被告知在特定情况下应使用什么具体类来填充依赖关系来实现这一点,当被要求提供类时,它将实例化该类,提供所需依赖关系(以及依赖关系的依赖关系)的实例。这可以允许A类依赖于B的模式,B类依赖于C,但A不知道C。IOC框架知道这三个方面,并将实例化A B,给它一个新的C,然后给B一个新的A。

        2
  •  7
  •   Stack Overflow is garbage    14 年前

    是的,这是相当常见的,但不是以您可能期望的形式。

    在Java中,接口是形式化的和显式的,并且对接口编程意味着实现特定的接口。 interface .

    在C++中,有时也一样(虽然使用抽象基类而不是接口),但是C++中的另一种常见方式是模板,其中接口是隐式的。

    例如,标准库算法都与迭代器“interface”一起工作,只是代码中从未定义过这样的接口。这是一个惯例,没有别的了。

    公开某些功能需要有效的迭代器,因此公开此功能的任何类型都是迭代器。但它不需要实现某种假设 IIterator 像Java那样的接口。

    这在用户代码中很常见。您经常编写代码来接受模板参数,该参数可能是 作品 . 您通过使用类型隐式定义了一个接口:您从中需要的任何内容都将成为该隐式接口的一部分,类型必须满足该部分才能使用。

    接口从未在代码中正式化,但您仍在使用它并针对它进行编程。

        3
  •  4
  •   Alexander Rafferty    14 年前

    当然!封装是OOP哲学的一个主要部分。通过将实现与类的接口分开,代码变得更加通用。例如,如果我有一个“vector”类,并且我想将内部表示从x和y对更改为长度和方向(假设这是为了提高效率),那么只更改几个处理实现的成员函数比搜索100个源文件要容易得多。r依赖于类实现的每个类。

    是的,小型项目也会受益。当有多个类以不同的方式(可能对于不同的平台)执行相同的操作(比如渲染)时,这个概念也很有用。通过给他们所有相同的接口(或者C++,从同一个基类派生它们),那么任何对象都可以用简单的替换来切换它们。

        4
  •  1
  •   Community CDub    8 年前

    我认为术语可能有些混淆,因为“接口”不是C++语言定义的术语。在您的问题上下文中,您显然是指一个抽象类规范,它可以由一个或多个具体类实现。

    我不会说这很常见,但也不少见——也许介于两者之间?微软的COM是建立在这个概念之上的。

    有关如何完成的详细信息,请参阅此问题: How do you declare an interface in C++?

        5
  •  1
  •   wilhelmtell    14 年前

    C++中的接口比Java要多。简单的答案是 这是一种常见的做法。你是否应该在你的小项目中遵循它取决于具体情况。评判每一个班级,而不是整个项目。一般来说,如果它没有损坏,就不要修复它。

    也就是说,在C++中,有两种接口:支持运行时多态性和支持编译时多态性的接口。运行时多态性与您从Java中知道的非常相似。编译时多态性来自于模板的使用。

    运行时多态性的优点是,它通常会生成一个小的二进制文件,这使得编译器在编译时更容易生成有意义的错误消息。在下面,它还会导致稍微慢一点的二进制代码,因为调用还需要一个取消引用。

    编译时多态性的优点是,通常您的源代码较小,调用的运行时会尽可能快地进行优化。另一方面,因为编译器需要做更多的工作,所以编译时间会变慢。通常编译时间会明显变慢,因为模板通常在头文件中定义,因此对于依赖于模板的每个编译单元,都会一次又一次地重新编译。

        6
  •  1
  •   Edward Strange    14 年前

    我认为这些概念远远超出了简单的OO,但同样适用于大多数的(如果不是全部的)C++中的范例,包括泛型编程。

        7
  •  0
  •   Zan Lynx    14 年前

    好吧,“程序到接口”被任何编写库的语言的人使用。

    库用户不希望库接口一直更改。想象一下,如果你不得不重写你的程序,因为C库的作者决定重新定义“printf”。或者如果Java库决定重新定义ToStand的接口呢?

    所以是的,“程序接口”在C++中使用。

        8
  •  0
  •   Nils    14 年前

    看看标准模板库的设计。例如,msdn channel9有一些不错的视频教程,解释了STL的设计(和MSFTS实现)。

    http://channel9.msdn.com/Shows/Going+Deep/C9-Lectures-Introduction-to-STL-with-Stephan-T-Lavavej

        9
  •  0
  •   sanosdole    13 年前

    对于通常的“程序到接口”,这取决于。 如果使用运行时多态性,缺点是执行速度和生成更多类。 如果对接口使用编译时多态性,那么缺点是编译速度和复杂性(涉及编译错误、调试等)。

    两者都具有更好的可维护性的巨大优势。这是通过封装实现的,封装产生更好的可测试性和更强的关注点分离。适应这种思维方式可以将您的问题缩小到由其他组件的接口所包围的较小范围内。

    这种思维方式在任何编程语言中都被认为是很好的实践,即使您没有显式地对接口进行编码。(另见坚实的原则)。

    控制反转是C++的另一种野兽,因为没有良好的广泛接受的标准框架。你应该这样做,但必须自己管理。这里最好的建议是:远离静态,使用“程序到接口”,对于较小的项目,您应该很好。

        10
  •  0
  •   ArBR    13 年前

    接口在Java中很流行,而在C接口中,在接口面向对象编程已经存在之前,(在我看来)C++中最完整的语言不是在接口的基础上长大的。创建接口的主要需求是为了解决必须具有多重继承(C++允许多重继承)的问题。

    在C++中,定义接口不是一种扩展的实践。 但是它们可以通过纯抽象类来模拟 )还有一种常见的做法是定义一个包含声明(.h)和其他包含实现(.cpp)的文件,这可能与纯抽象classes一起作为用现代OO语言创建接口的灵感。