Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/311.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
Java 让界面变成程序化而不是语义化意味着什么?_Java_C#_Android_C++ - Fatal编程技术网

Java 让界面变成程序化而不是语义化意味着什么?

Java 让界面变成程序化而不是语义化意味着什么?,java,c#,android,c++,Java,C#,Android,C++,目前我正在读《代码完成,第二版》。在第6.2章中,作者讨论了类和接口,并给出了以下建议: 尽可能使接口程序化而非语义化 每个接口由编程部分和语义部分组成。 编程部分由数据类型和其他属性组成 可由编译器强制执行的接口的。语义 接口的一部分包括关于 将使用编译器无法强制执行的接口。这个 语义接口包括诸如“RoutineA必须 在“RoutineB”或“如果dataMember1不可用,RoutineA将崩溃”之前调用 在传递给RoutineA之前初始化。”语义接口 应记录在注释中,但尽量减少接口 依

目前我正在读《代码完成,第二版》。在第6.2章中,作者讨论了类和接口,并给出了以下建议:

尽可能使接口程序化而非语义化
每个接口由编程部分和语义部分组成。 编程部分由数据类型和其他属性组成 可由编译器强制执行的接口的。语义 接口的一部分包括关于 将使用编译器无法强制执行的接口。这个 语义接口包括诸如“RoutineA必须 在“RoutineB”或“如果dataMember1不可用,RoutineA将崩溃”之前调用 在传递给RoutineA之前初始化。”语义接口 应记录在注释中,但尽量减少接口 依赖于文件。接口的任何方面都不能 由编译器强制执行是一个可能被误用的方面。 寻找将语义接口元素转换为编程元素的方法 通过使用断言或其他技术来连接元素

我理解作者所说的语义和编程的含义,但我不理解的是如何将语义接口函数转换为编程接口函数。他提到使用资产或其他技术来实现这一点

让我们以作者为例:

RoutineA必须在RoutineB之前调用。我假设这些例程是接口(公共函数)的一部分,因为这就是问题所在,丑陋的接口

所以,如果在调用RoutineB之前确实必须调用RoutineA,您将如何使用断言或其他技术重新组织此接口

我对此有一些想法,但我不确定这些想法是否正确

假设RoutineA和RoutineB都是公共功能,这意味着它们都应该彼此独立使用,但唯一的限制是,您必须先调用RoutineA,然后才能单独调用RoutineB

如果确实如此,那么您将如何使用断言或其他技术解决此问题

如果我的假设有错误,请随时纠正我

此外,我还特意将此贴在当前标签下,因为像面向对象编程/设计/接口这样的标签点击率很低,这意味着我的问题可能不会被看到很多。

两个可能的答案:

  • Put
    assert(一个被调用的)在例行程序中
    RoutineB
  • 从类的接口中删除
    RoutineB
    ,并使
    RoutineA
    返回具有
    RoutineB
    成员的新对象
在后一种情况下,您可能希望使外部类成为指向内部类的智能指针周围的薄包装,然后
RoutineA
只复制指针

class Impl;
class SecondClass;
class FirstClass
{
    std::shared_ptr<Impl> pimpl;
public:
    FirstClass();
    SecondClass RoutineA(...);
    ...
}

class SecondClass
{
    std::shared_ptr<Impl> pimpl;
    friend class FirstClass;
    SecondClass(const std::shared_ptr<Impl>& impl) : pimpl(impl);
public:
    void RoutineB(....);
}

SecondClass FirstClass::RoutineA(...)
{
    // Do stuff
    return SecondClass(pimpl);
}
class Impl;
二等舱;
头等舱
{
std::共享的ptr pimpl;
公众:
第一类();
二等航线(…);
...
}
二等舱
{
std::共享的ptr pimpl;
朋友一流;
第二类(const std::shared_ptr&impl):pimpl(impl);
公众:
无效线路B(……);
}
第二类第一类::RoutineA(…)
{
//做事
返回二等舱(pimpl);
}

您也可以使用
唯一\u ptr
,但该代码稍长。

我认为您应该在运行时检查限制(“RoutineA必须在RoutineB之前调用”)。标记中的编程语言无法在编译时检查这种限制。 您的代码可能如下所示:

RoutineA()
{
  aCalled = true;
  //some operations..
}
RoutineB()
{
  if(!aCalled) // or an assertion
  {
    throw NotReadyException("RoutineA must be called");
  }
  //some operations..
}

我同意你的看法,这似乎是个很糟糕的建议。如果RoutineA必须在RoutineB之前调用,那么正确的方法是将它们都私有化,并创建一个新的公共RoutineC来实现这一点。@DavidArno这确实是为了解决作者给出的示例而想到的第一个解决方案。但如果我的解释是正确的,那么您也应该能够只调用RoutineB而不执行RoutineA中的代码,但前提是您在调用RoutineB之前至少调用了RoutineA一次(可能多次)。毕竟,它们都是公共的,必须调用两个公共函数来执行一个操作没有任何意义。因此,让RoutineB在执行其特定代码之前调用RoutineA可能是有意义的。@DavidArno这样您就可以为其特定目的调用RoutineA。你也可以自己给RoutineB打电话,因为它会自己给RoutineA打电话。这样,您就可以独立地使用它们。(不过这只是个大脑放屁)@DavidArno:这不正是麦康奈尔的建议吗?你的
RoutineC
和另外两个隐藏在实现中的例子听起来像是“编程接口”的完美例子。@canthinkofanything:我认为这个建议的全部要点是
RoutineA
RoutineB
不应该公开。除此之外,我要说的是,这些名字太笼统了,不能给你准确的答案。你能想出你在这个问题上使用的任何一种语言的真实例子吗?我理解这两点,尽管最后一句确实让我感到困惑。第二个建议很好,因为它迫使在编译时遵循要求。很抱歉,我也不理解最后一段。也许可以换一种说法和/或给出一个具体的例子+第二个建议我也很喜欢!我对第二个解决方案有点好奇wootwoot@Q问:我认为马丁·邦纳斯的答案是正确的,因为他给出了不止一个解决方案。另一种解决方案甚至更好,因为通过布尔检查,RoutineB依赖于RoutineA。这意味着您必须正确处理异常,如果确实有人