这是 class 避免时间耦合吗
Is this class avoiding temporal coupling
我有一个包装器对象,它接受一个连接字符串并打开一个数据库并在可以使用之前初始化一个 API。阅读 Mark Seemann's blog post on temporal coupling 后,我一直在为尝试重构我的 API 而发疯,所以很清楚。我查看了 .NET class SqlConnection
并且它们在您使用它之前需要 Open
,所以也许这种类型的耦合是不可避免的?我不知道是否有办法做我想做的事,因为它是现有 API 的包装器,但这就是我所拥有的。一次只能有一个连接,否则你必须关闭并重新启动
public class MyService
{
public MyService(string dataSource)
public void StopRequest()
public void StopAPI()
public Response SendRequest(string request, string pass)
}
你看到它需要一个数据源字符串,并启动 API 所以 SendRequests
可以工作但是你一次只能有一个服务所以除非我把它保存在某种形式static var 或 DI 单例,你必须每次都调用 new ..(datasource),即使它总是一样的。唯一困扰我的是如果你调用 StopRequest
或 StopAPI
然后调用 SendRequest
,它当然会抛出错误。我认为这是在避免时间耦合,但需要一些想法。
时间耦合是一种设计味道,并不总是可以避免的。特别是在处理已经存在的 API 或有时需要以特定(临时耦合)顺序进行操作的外部服务时。 SqlConnection
是一个很好的例子,因为它要求你调用 Open
,这是隐式的,我时常忘记做一些事情。另一方面,让 SqlConnection
从其构造函数内部打开连接也是一个坏主意,这也是 Open
方法首先存在的原因。
但在大多数情况下,您可以将时间耦合 API 的复杂性隐藏在抽象背后,并让这种复杂性仅在适配器实现中实现。这避免了应用程序的其余部分必须处理这种时间耦合。
很难就您的用例提供非常具体的反馈,因为缺少一些细节。但我可以想象 StopAPI
到 not 是抽象的一部分,并从适配器上的 Dispose
方法内部调用。
如果交互顺序至关重要且无法抽象,您可以通过让方法 return 需要传递给下一个方法才能运行的实例来防止时间耦合。这使得方法之间的依赖关系非常明确,经过编译器验证,因此消除了时间耦合。例如:
public class MyService
{
public MyService(string dataSource);
public Api StartApi();
}
public class Api : IDisposable
{
public Request SendRequest(string request, string pass);
public void Dispose(); // Calls StopAPI internally
}
public class Request : IDisposable
{
public Response Response { get; }
public void Dispose(); // Calls StopRequest internally
}
我有一个包装器对象,它接受一个连接字符串并打开一个数据库并在可以使用之前初始化一个 API。阅读 Mark Seemann's blog post on temporal coupling 后,我一直在为尝试重构我的 API 而发疯,所以很清楚。我查看了 .NET class SqlConnection
并且它们在您使用它之前需要 Open
,所以也许这种类型的耦合是不可避免的?我不知道是否有办法做我想做的事,因为它是现有 API 的包装器,但这就是我所拥有的。一次只能有一个连接,否则你必须关闭并重新启动
public class MyService
{
public MyService(string dataSource)
public void StopRequest()
public void StopAPI()
public Response SendRequest(string request, string pass)
}
你看到它需要一个数据源字符串,并启动 API 所以 SendRequests
可以工作但是你一次只能有一个服务所以除非我把它保存在某种形式static var 或 DI 单例,你必须每次都调用 new ..(datasource),即使它总是一样的。唯一困扰我的是如果你调用 StopRequest
或 StopAPI
然后调用 SendRequest
,它当然会抛出错误。我认为这是在避免时间耦合,但需要一些想法。
时间耦合是一种设计味道,并不总是可以避免的。特别是在处理已经存在的 API 或有时需要以特定(临时耦合)顺序进行操作的外部服务时。 SqlConnection
是一个很好的例子,因为它要求你调用 Open
,这是隐式的,我时常忘记做一些事情。另一方面,让 SqlConnection
从其构造函数内部打开连接也是一个坏主意,这也是 Open
方法首先存在的原因。
但在大多数情况下,您可以将时间耦合 API 的复杂性隐藏在抽象背后,并让这种复杂性仅在适配器实现中实现。这避免了应用程序的其余部分必须处理这种时间耦合。
很难就您的用例提供非常具体的反馈,因为缺少一些细节。但我可以想象 StopAPI
到 not 是抽象的一部分,并从适配器上的 Dispose
方法内部调用。
如果交互顺序至关重要且无法抽象,您可以通过让方法 return 需要传递给下一个方法才能运行的实例来防止时间耦合。这使得方法之间的依赖关系非常明确,经过编译器验证,因此消除了时间耦合。例如:
public class MyService
{
public MyService(string dataSource);
public Api StartApi();
}
public class Api : IDisposable
{
public Request SendRequest(string request, string pass);
public void Dispose(); // Calls StopAPI internally
}
public class Request : IDisposable
{
public Response Response { get; }
public void Dispose(); // Calls StopRequest internally
}