用于返回可能并不总是完全填充的数据结构对象的设计模式



我有一种情况,我正在查询以XML形式返回数据的RESTful web服务(使用.NET)。我围绕API编写了包装器函数,这样我就不会返回原始XML,而是返回反映XML结构的完整.NET对象。XML可能非常复杂,因此这些对象可能非常大且嵌套严重(例如,包含集合,而集合又可能包含其他集合等)

REST API有一个返回完整结果或基本结果的选项。基本结果返回完整结果所返回的数据的一小部分。目前,我正在处理这两种类型的响应,方法是为这两种请求返回相同的.NET对象,但在基本请求中,一些属性没有填充。这最好通过一个(非常简单化)的代码示例来展示:

public class PersonResponse
{
    public string Name { get; set; }
    public string Age { get; set; }
    public IList<HistoryDetails> LifeHistory { get; set; }
}
public class PersonRequest
{
    public PersonResponse GetBasicResponse()
    {
        return new PersonResponse() 
        { 
            Name = "John Doe", 
            Age = "50", 
            LifeHistory = null 
        };
    }
    public PersonResponse GetFullResponse()
    {
        return new PersonResponse() 
        { 
            Name = "John Doe", 
            Age = "50", 
            LifeHistory = PopulateHistoryUsingExpensiveXmlParsing()
        };
    }
}

正如您所看到的,PersonRequest类有两个方法,它们都返回一个PersonResponse对象。然而,GetBasicResponse方法是一个"lite"版本——它不会填充所有属性(在本例中,它不会填充LifeHistory集合,因为这是一个‘昂贵’的操作)。请注意,这是实际情况的简化版本。

然而,对我来说,这有一种明确的气味(因为GetBasicResponse方法的调用方需要了解哪些属性不会被填充)。

我认为一种更OOP的方法是有两个PersonResponse对象——一个BasicPersonResponse对象和一个FullPersonResponse对象,后者继承自前者。类似于:

public class BasicPersonResponse
{
    public string Name { get; set; }
    public string Age { get; set; }
}
public class FullPersonResponse : BasicPersonResponse
{
    public IList<object> LifeHistory { get; set; }
}
public class PersonRequest
{
    public BasicPersonResponse GetBasicResponse()
    {
        return new FullPersonResponse()
        {
            // ...
        };
    }
    public FullPersonResponse GetFullResponse()
    {
        return new FullPersonResponse()
        {
            // ...
        };
    }
}

然而,这仍然不太"感觉"正确——原因我不完全确定!

有没有更好的设计模式来处理这种情况?我觉得我错过了更优雅的东西?谢谢

我认为您已经描述了代理模式。请参阅此处的详细信息:C#中的GOF设计模式示意图

对于使用继承来添加"额外数据",而不是添加/修改行为,我也有一种挥之不去的糟糕感觉。这样做的主要优点是,方法可以指定它们在参数类型中需要的详细程度。

在这个特定的例子中,我倾向于对数据传输对象(Response对象)使用第一种方法,但随后立即使用这个数据传输对象来创建数据模型对象,其确切性质在很大程度上取决于您的特定应用程序。数据传输对象应该是内部的(因为数据字段的存在或不存在是一个实现细节),公共对象或接口应该提供更适合消费代码的视图。

最新更新