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

本文关键字:最佳 是什么 属性 有一个 依赖于 web 调用 服务 | 更新日期: 2023-09-27 18:25:08

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

属性getter进行web服务调用是否合适。这样做的缺点似乎是getter做了不止一件事,并掩盖了调用的开销。我意识到,任何属性getter只需要进行一次web服务调用(通过在进行调用之前检查null或flag)。但在我看来,一个属性获取者可能会为其他属性设置私有字段

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

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

我已经遇到过很多次这个问题,最终我总是更喜欢第二种方法而不是第一种方法。

有什么想法吗?

Seth

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

我会向您抛出另一个选项。您可以使用工厂(类或静态方法)来实例化您的类。工厂将负责进行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

我会使用惰性初始化程序。.NET框架中完全支持它们。参见懒惰(T)。

我想说的是,一种形式的工厂模式并从"创建"类型的静态方法返回class,这允许您在更改检索数据的方式时分离WebService端,从Web Service到Restful等。这也使实现单元测试、异步延迟加载等以及测试变得更容易。您还可以轻松地使用IOC容器或依赖项注入在运行时注入服务API。

为了澄清测试,如果使用Create方法定义接口,可以简单地"交换"或"注入"接口实现。

public MyClass webServiceClass = IMyFactoryInterface.Create();
public static MyClassFactory : IMyFactoryInterface
{
    public static MyClass Create(params anyParametersRequired)
    {    
        // Do Something
    }
}

根据我的经验,让属性getter(或setter)做任何计算成本高昂的事情都是个坏主意。当我看到一个属性时,我通常认为这将是一个快速、简单的操作。

我会避免第二个解决方案(InitWebServiceVals),因为要求消费者了解它并采取额外的行动。当访问第一个属性时,我会在对象的构造函数中调用web服务,这取决于您想在何时访问web服务。

让属性A的访问权进行服务调用,并设置属性B、C和D的值是可以的,这是懒惰的实例化,如果调用最好推迟到第一次需要,那么这是完全合理的。

编辑:

因此,经过一些额外的思考,还有第三种选择,我更喜欢它,这取决于对象的预期用途。如果可能有多个web服务生成属性值,或者的属性值来自web服务,并且应该立即可用,或者甚至对象可能会被实例化而不会立即访问,那么,让构造函数异步地进行服务调用,并使属性getter足够智能以等待该调用完成,这将把服务调用的成本转移到另一个线程。

我建议在构造函数中进行web服务调用,这样在任何人请求属性之前就可以获得性能。如果你不想在构建时立即受到打击,那么你至少可以在构造函数中启动web服务调用async,并在数据可用之前使用属性get块。

Rico Mariani有一篇精彩的帖子,讲述了你不应该在房产中做任何昂贵的事情,因为获得房产价值应该是一项廉价的操作。

http://blogs.msdn.com/b/ricom/archive/2011/12/19/performance-guidelines-for-properties.aspx

如果可能的话,我会避免创建对象然后设置属性。更好的解决方案是创建一个更高级别的提供程序,该提供程序以完全初始化的状态返回所需的对象。如果该服务需要调用一个Web服务,那就顺其自然吧。这可以避免时间依赖性的优点是通信,即获取对象是一项昂贵的操作。

示例:ISomeService.Get()返回一个WidgetISuperWidgetProvider.Get()通过调用ISomeService、获取一些属性并从其他数据源获取其余属性来返回一个SuperWidget。

答案取决于多个因素:

  • 吸气剂的反应时间(吸气剂允许的时间延迟)
  • 服务是同步还是异步
  • 服务呼叫有多"重"
  • 服务呼叫结果更改的频率
  • 您期望代码多久调用一次这个getter

如果回答这些问题,答案是非常清楚和简单的。

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

  • 高速缓存
  • 惰性初始化
  • 构造函数初始化

更新:我觉得你正在试图解决某个"工作"类中的缓存问题,而这个类不应该这样做,如果你需要在服务周围引入一个CachingMyService包装器,它将由你的客户端代码使用。