在工作中,我们的服务电话遵循以下模式:
所以它总是这样:
Dim someRequest as Request = CreateSomeSortOfRequest()
Dim results as Response = Nothing
using proxy as IResultProxy = OurLibrary.Proxy(Of IResultProxy).Create()
results = proxy.GetResults(request)
End Using
然后:
Dim results as Response = Nothing
Using whateverBusiness as new BusinessClass
results = whateverBusiness.ComputeWhatever(request)
End Using
Return results
非常基本的东西,对吗?那些在那里工作了20多年的人现在将继续讨论这些商业课程中是否应该有任何类型的成员变量。永远。想要执行一些非常复杂的操作吗?最好准备通过10到(我已经看到它)30个参数。
对我而言,所有这一切似乎都是不好的做法。只要您保持在狭窄的范围内,将请求移交给业务类的新实例,请求它执行任何操作,它执行任何必要的逻辑,返回结果,并继续您的一天。
我已经调查过,我们只在系统中的一个位置使用线程,而这只是触发不同的服务调用(所有这些都遵循上述模式)。我们不使用实例池,静态变量或其他任何类似的东西,特别是因为我们有上述问题,我们一直认为不应该有任何类范围的变量。
我是否因为认为让这些类具有极其严格且锁定的入口点(即无法访问内部变量)而感到非常高兴,特别是因为无法访问范围之外的业务类实例服务电话?或者我的长辈是否正确地声明类中的任何私有成员变量都是非线程安全的并且永远不应该被使用?
我想我应该提到业务类几乎总是从数据库中加载一些数据,尝试将这些数据拼凑成通常非常深的层次结构,然后返回(或者相反;取出对象,打破它除此之外,有时会执行数百次数据库调用以保存。)
答案 0 :(得分:2)
想要执行一些非常复杂的操作吗?最好准备将10传递给(和我已经看过)30个参数
听起来他们不希望任何国家(无论如何都是公众)在他们的商业课上,这是一个可以理解的高尚愿景,但很少被证明是有用的或实际的一般规则。可能不是30个参数,而是传入结构或请求类。
你可以向他们指出,在他们努力防止状态的过程中,10-30个参数会带来一系列问题。
如精彩代码分析工具nDepend的文档中所述:
NDepend的:
NbParameters :方法的参数数量。 Ref和Out也被计算在内。传递给IL中的实例方法的this引用不计入参数。
建议: NbParameters 高于 5的方法可能会很难调用并可能降低性能。您应该更喜欢在声明类型中使用其他属性/字段来处理多种状态。另一个替代是提供专用于处理参数传递的类或结构(例如,请参阅类
System.Diagnostics.ProcessStartInfo
和方法System.Diagnostics.Process.Start(ProcessStartInfo))
- Holy swiss cheese Batman, tell me more。
它可以说与客户端将请求对象传递给WCF服务时没有什么不同。您正在传递请求对象不是吗?
OP:
我是否因为认为让这些类具有非常严格且锁定的入口点(即无法访问内部变量)而感到非常高兴
好吧,听起来好像系统已经存在了一段时间,并且在建造过程中已经有了一些长辈应用的最佳实践。这很好。然而,这样的系统可能只会继续保持健壮,因为有人遵循所设置的任何规则......而且你所说的声音听起来很奇怪而且有点不明智。
它也可能是偶然架构的一个例子,系统就是因为它。
e.g。如果有人去,并添加一个公共方法,并说一些公共财产或使私人领域公共可能会扰乱applecart。
我曾经不幸在遗留系统上工作,尽管它似乎没有发生任何事故,但由于公共领域的数量过多,这一切都相当脆弱。 (请注意,这是c ++!)
有人可以说:
"请勿触摸公共领域"
我可以回复:
"好吧,也许我们不应该公开这些字段"
因此他们希望没有实例领域。 c#类带有"任何类型的成员变量"顽皮并不是真正令人担忧的问题。相反,我怀疑问题是线程安全问题,因此他们应该研究如何使调用者或调用者成为线程安全而不是业务类。
通过没有状态来强制执行线程安全,虽然有效是一种大锤方法,并且往往会惹恼OO子系统的其他部分。
听起来他们正在WCF中使用老式线程保护,其中WCF以自己的方式保证线程安全,其方式与 Apartment 模型非常相似COM成功了。
而不是担心lock()
;和同步,为什么不让WCF序列化为你调用:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession,
ConcurrencyMode = ConcurrencyMode.Single)]
public partial class MyService: IMyService, IDisposable
{
// ...
}
InstanceContextMode.PerSession
实质上告诉WCF为每个客户端代理创建一个唯一的私有服务实例。有两个客户打电话?那意味着将创建两个MyService
实例。所以无论这个类的实例成员是什么,都保证不会在另一个实例上踩踏。 (注意,我不会在这里提及statatic
)
ConcurrencyMode = ConcurrencyMode.Single
告诉WCF,必须一个接一个地序列化对此服务实例的调用,并且不允许对服务进行并发调用。这与InstanceContextMode
设置有关。
只需在WCF中设置这两个但功能非常强大的设置,您已经告诉它不仅要创建WCF服务的私有实例,以便多个客户端无法对其进行操作,但即使客户端共享它&# 39;一个线程中的客户端代理并试图同时调用一个特定的服务实例,WCF保证调用该服务将被安全地序列化。
这是什么意思?
不意味着每会话单服务一次只允许一个客户端。这意味着每个客户端代理一次只能调用一次。您的服务很可能会在特定时刻运行多个实例,并且知道一个人不能向另一个人扔石头。
只要您保持在那个狭窄的范围内,就可以将请求移交给新的业务类实例
由于WCF为您建立了一个良好的线程安全生态系统,它在调用堆栈的其他地方有一个很好的后续效果。
了解您的服务入口点是序列化的,您可以自由地实例化业务类并设置公共成员,如果您真的想要。这并不是说另一个线程无论如何都可以访问它。
或者我的长辈是否正确陈述某个类中的任何私有成员变量都是非线程安全的
这完全取决于该课程在其他地方的使用方式。正如设计良好的业务处理层不应该关心调用堆栈是否来自WCF;单元测试;或控制台应用程序;在层中可能存在线程中立性的争论。
e.g。让我们说商务舱有一些实例属性。没有戏剧性,商务舱不会产生线程。所有业务类都会获取一些数据库数据;有一个小提琴并将其返回给来电者。
调用者是您的WCF服务。是WCF服务创建了业务类的实例。但是我听到你说的是什么 - " WCF服务实例已经是线程安全的!"完全正确,谢谢你的关注。 WCF已经建立了一个很好的线程安全环境,因此业务类中的任何实例成员都不应该被另一个线程删除。
我们特定的WCF线程是唯一的线程,它甚至可以识别这个特定业务类的实例。
.NET中的许多类都有状态,其中许多都在私有字段中。这并不意味着它的设计不好。这就是你如何使用需要思考的课程。
WinForms Font
或Bitmap
对象同时具有状态;我怀疑即使是私人会员;并且不应该被多个线程同时摆弄。这不是微软设计糟糕设计的一个例子,而是 应该具有状态的东西。
这两个类是由比我,我和你的长辈更聪明的人创建的,比我们将要工作的代码库更大。
我觉得你质疑长辈真是太好了。有时候我们并不总能做对。
坚持下去!
还有一些时髦的图表,在任何仪表板屏幕上看起来都令人印象深刻。