如果我的某个类具有一些由Web服务调用填充的只读属性,那么设计此方法的最佳方法是什么?
属性getter是否适合进行Web服务调用。看起来这样做的缺点是,吸气剂不仅仅是一件事,而且会掩盖呼叫费用。我意识到任何属性getter只需要调用一次Web服务(通过在调用之前检查空值或标志)。但是,单个属性getter可能会为其他属性设置私有字段似乎闻到了我。
另一方面,如果我有一个调用Web服务并更新私有字段的公共方法(即InitWebServiceVals),我将在方法和属性getter之间创建时间依赖关系。因此API模糊了在调用“InitWebServiceVals”之前不应读取属性的事实。
或者是否有其他方法或模式可以解决这个问题?例如,在构造函数中调用webservice?或者这通常表明存在设计问题?
我已经多次遇到过这个问题而且我总是更喜欢第二种方法。
有什么想法吗?
赛斯
答案 0 :(得分:8)
我会向你抛出另一个选择。您可以使用工厂(类或静态方法)来实例化您的类。工厂将负责进行Web服务调用并将属性值移交给类(通过类中接受值的参数化构造函数,或通过将setter声明为内部函数)。
这样做的另一个好处是可以将“我的班级如何获得这些价值”与课堂本身脱钩。
所以:
var myClass = MyClass.Create(); // where create is a static
// or
var myClass = MyClassFactory.Create(); // using a separate factory
// or
var myClass = MyClass.CreateFromTestData(value1, value2, value3); // etc
答案 1 :(得分:2)
我会使用延迟初始化器。它们完全支持.NET框架。请参阅Lazy(Of T)。
答案 2 :(得分:2)
我会避免使用第二个解决方案(InitWebServiceVals),因为要求消费者了解它并采取额外措施。当访问第一个属性时,我会在对象的构造函数或中进行Web服务调用,具体取决于您希望获取访问Web服务的时间。
拥有属性A的访问权限进行服务调用并且还设置属性B,C和D的值是可以的,这是懒惰的实例化,并且如果在第一次需要之前调用更好,则完全合理。
编辑:
所以在经过一些额外的考虑之后,还有第三种选择,我喜欢它更好一些,具体取决于对象的预期用途。如果可能有多个Web服务生成属性值,或者不来自Web服务并且应该立即可用的属性值,或者甚至可能是对象将被实例化而不是立即访问,然后让构造函数异步进行服务调用,并使属性getter足够智能等待该调用完成将把服务调用的成本卸载到另一个线程。
答案 3 :(得分:2)
根据我的经验,让财产获取者(或制定者)做任何计算上昂贵的事情都是一个坏主意。当我看到一个属性时,我通常认为它将是一个快速,简单的操作。
答案 4 :(得分:2)
我会说Factory Pattern的一种形式,并从“创建”类型的静态方法返回类,这允许您在Web上更改从Web检索数据的方式服务到Restful等它也使得更容易实现单元测试,异步延迟加载等以及测试。您还可以轻松地使用IOC容器或依赖注入在运行时注入Service API。
为了澄清测试,如果使用Create Method定义接口,则可以简单地“交换”或“注入”接口实现。
public MyClass webServiceClass = IMyFactoryInterface.Create();
public static MyClassFactory : IMyFactoryInterface
{
public static MyClass Create(params anyParametersRequired)
{
// Do Something
}
}
答案 5 :(得分:0)
我建议在构造函数中进行Web服务调用,以便在任何人要求获取属性之前获取性能。如果您不想在构造时立即获取命中,那么您至少可以在构造函数中启动Web服务调用异步,并使属性获取阻塞,直到数据可用。
Rico Mariani有一篇很好的文章,关于如何在房产获取方面不做任何昂贵的事情,因为获得房产价值应该是一项廉价的操作。
http://blogs.msdn.com/b/ricom/archive/2011/12/19/performance-guidelines-for-properties.aspx
答案 6 :(得分:0)
如果可能,我会避免创建对象然后设置属性。更好的解决方案是创建一个更高级别的提供程序,在完全初始化的状态下返回所需的对象。如果该服务需要调用Web服务,那么就这样吧。这使您可以避免时间依赖性和具有通信的优势,使对象成为一项昂贵的操作。
实施例: ISomeService.Get()返回一个Widget ISuperWidgetProvider.Get()通过调用ISomeService返回一个SuperWidget,获取一些属性,并从其他数据源获取其余属性。
答案 7 :(得分:0)
答案取决于多种因素:
如果回答这个问题,答案非常简单明了。
有三种主要策略可以帮助您:
更新:我觉得你正试图在一些不应该这样做的“工作”类中解决缓存问题,如果是这种情况你需要在服务周围引入一个CachingMyService包装器,将由你的客户代码。