这是一道关于OOP实践的问题。我在使用 API 时遇到过一种情况,其中有一系列需要按特定顺序调用的方法。
控制智能传感器的操作。
交互的简化版本如下:首先必须将 API 配置为通过 TCP 与传感器交互,下一个命令启动扫描过程,然后接收多个项目的输入,直到发出停止命令。此时必须发出一系列类似的断开命令。如果这些不按顺序执行,则会引发异常。
我在这里看到模块化和封装概念之间的冲突。每个步骤都是一个离散的操作,因此应该封装在单独的方法中,但它们也依赖于正确的执行顺序。
我是从后来处理这段代码的开发人员的角度思考的。似乎有人必须对这个系统有很高的了解才能处理这个代码,这使得它感觉很脆弱。我可以添加有关此调用顺序的警告注释,但我希望有一些原则或设计模式可能适合我的情况。
这是一个例子:
class RemoteTool
{
public void Config();
public void StartProcess();
public void BeginListen();
public void StopProcess();
public void StopListening();
}
class Program
{
static void Main(string[] args)
{
RemoteTool MyRemoteTool = new RemoteTool();
MyRemoteTool.Config();
MyRemoteTool.StartProcess();
MyRemoteTool.BeginListen();
// Do some stuff
MyRemoteTool.StopListening();
MyRemoteTool.StopProcess();
}
}
我能想到的最接近的事情是使用布尔标志并在每个函数中检查它们以确保先决条件函数已经被调用,但我想我希望有更好的方法。
这是我在寻找答案时发现的一个方法。这很简单,有帮助,但并不能解决我的问题。
本质上,该类是在问题中完全创建的,但依赖函数被创建为受保护的函数,并创建一个公共成员来保持它们的顺序,如下所示:
class RemoteTool
{
public bool Running = false;
public void Run()
{
Config();
StartProcess();
BeginListen();
Running = true;
}
public void Stop() {
StopListening();
StopProcess();
Running = false;
}
protected void Config();
protected void StartProcess();
protected void BeginListen();
protected void StopProcess();
protected void StopListening();
}
问题是你仍然需要按照正确的顺序调用Stop()和Run(),但是它们更容易管理,而且模块化程度更高。
我认为问题与 RemoteTool 类有一个需要一些前提条件的 contract 有关。例如:方法 b() 必须在方法 a() 之后执行 ()。
如果您的语言没有提供定义此类先决条件的机制,您需要自己实现一个。
我同意你的观点,要实现这个额外的功能(或这些特定的类合约功能) RemoteTool() 类中的内容可能会降低您当前的设计。一个简单的解决方案可以是使用另一个类,负责在调用 RemoteClass 的特定方法之前强制执行所需的前提条件。(RemoteToolProxy() 可以是合适的名称)
通过这种方式,您将解耦具体功能和说明如何使用它的合同。
class RemoteTool {
public ConfiguredRemoteTool Configure();
}
class ConfiguredRemoteTool {
public Listener StartProcess();
}
class Listener {
public void BeginListen();
}
需要权衡。如果您的混淆指标是类的数量,那么这可以说是一个“更令人困惑”的 API。然而,错误使用要困难得多,并且通过良好的命名和代码组织,它可能很容易理解。如果过程的任何部分变得更加复杂,您可以轻松地向任何类添加方法,而不会弄乱其他类。
如果您使用 Java,这些可能是内部类,因此您可以清楚地传达它们之间的关系。在 C++ 中,您可以将它们放在同一个头文件中。