当您拥有属性依赖于Web服务调用的类时,最佳设计实践是什么?

时间:2012-02-20 16:44:09

标签: c# .net oop design-patterns

如果我的某个类具有一些由Web服务调用填充的只读属性,那么设计此方法的最佳方法是什么?

属性getter是否适合进行Web服务调用。看起来这样做的缺点是,吸气剂不仅仅是一件事,而且会掩盖呼叫费用。我意识到任何属性getter只需要调用一次Web服务(通过在调用之前检查空值或标志)。但是,单个属性getter可能会为其他属性设置私有字段似乎闻到了我。

另一方面,如果我有一个调用Web服务并更新私有字段的公共方法(即InitWebServiceVals),我将在方法和属性getter之间创建时间依赖关系。因此API模糊了在调用“InitWebServiceVals”之前不应读取属性的事实。

或者是否有其他方法或模式可以解决这个问题?例如,在构造函数中调用webservice?或者这通常表明存在设计问题?

我已经多次遇到过这个问题而且我总是更喜欢第二种方法。

有什么想法吗?

赛斯

8 个答案:

答案 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)

答案取决于多种因素:

  • 吸气剂的反应时间(吸气剂的允许时间延迟)
  • 服务是同步还是异步
  • 服务电话如何“沉重”
  • 服务呼叫结果的变化频率
  • 您希望代码调用此getter的频率

如果回答这个问题,答案非常简单明了。

有三种主要策略可以帮助您:

  • 缓存
  • 延迟初始化
  • 构造函数初始化

更新:我觉得你正试图在一些不应该这样做的“工作”类中解决缓存问题,如果是这种情况你需要在服务周围引入一个CachingMyService包装器,将由你的客户代码。