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