从不同数据格式创建对象的最佳方法

时间:2012-03-26 21:36:40

标签: c# design-patterns

对于我正在进行的项目,我需要使用不同的源数据格式创建对象,或多或少是这样的:

public class FooService
{
    protected DataFormat Format { get; set; }

    public FooService(DataFormat format = DataFormat.Json)
    {
        Format = format;
    }

    public Foo GetFoo(int id)
    {
        string content = GetContentInFormat("someuri/foo/" + id, Format);

        // Something here must create a "Foo" object
        // based on Format, which could be Json, Xml or other
    }
}

public enum DataFormat
{
    Json,
    Xml
} 

我知道我可以:

1)使用不同的方法并根据格式选择正确的方法:

switch (Format)
{
    case DataFormat.Xml:
       return CreateFooFromXml(content);
    case DataFormat.Json:
       return CreateFooFromJson(content);
    default:
       throw new Exception("Invalid format.");
}

缺点:将会以这种方式创建至少8种不同类型,因此我需要更具可扩展性和可维护性的东西。

2)使FooService成为一个接口或抽象类,并实现具体的类,每种格式一个。

缺点: 所有类中的业务逻辑总是是相同的,除了类实例化。 JsonFooServiceXmlFooService可能令人困惑。

我想从可扩展性和可维护性的角度来了解什么是最佳解决方案。

5 个答案:

答案 0 :(得分:3)

您可以将其设为接口(IFormat)。

,而不是将Format设为枚举

然后,对于每种格式,创建一个实现JsonFormat的具体类(例如IFormat)。

每个具体类应该只包含特定格式的唯一内容,例如如何找到给定Id的元素/记录。

这是“策略模式”:http://en.wikipedia.org/wiki/Strategy_pattern

答案 1 :(得分:2)

你在这里清楚地说creational patterns,但我认为我们不太了解Foo的复杂性,而是明确地推荐一个人。幸运的是,没有那么多的GoF创作模式,所以你可以在相当短的时间内阅读所有这些模式。您似乎已经了解了factory-method模式,因此您可以跳到abstract factorybuilder,看看它们是否更符合要求。

构建器维基的提示:

  
      
  • Builder专注于逐步构建复杂对象。 Abstract Factory强调一系列产品对象(简单   或复杂的)。 Builder返回产品作为最后一步,但到目前为止   就抽象工厂而言,产品会被退回   立即
  •   
  • 构建器通常会构建Composite
  •   
  • 通常,设计开始使用工厂方法(不太复杂,可定制,子类扩散)并向Abstract发展   Factory,Prototype或Builder(更灵活,更复杂)   设计师发现需要更多灵活性的地方。
  •   
  • 有时创建模式是互补的:Builder可以使用其他模式之一来实现构建哪些组件。   抽象工厂,构建器和Prototype可以在其中使用Singleton   的实施方式。
  •   
  • 构建者是fluent interface的合适人选。
  •   

希望有所帮助。

答案 2 :(得分:1)

这是strategy pattern的典型用例,它处理可在运行时选择的算法。可以将switch-cases和long if / else if / else条件转换为优雅的可维护代码

如果您想动态切换数据格式生成器,可以查看MEF等选项,这是扩展应用程序以发现新扩展而无需任何配置的方法

答案 3 :(得分:0)

具体来说,你可以使用IOC(例如autofac)和某种类型的注射(因为我看到你已经接近这种想法), 在启动时注册所有可用的格式服务
(从配置或简单的一次性初始化,随着时间的推移,当您添加新类型时,易于维护)...

例如,实现IOutputFormatService接口
然后,您可以动态舍入它们(例如,解析,列出所有已实现的格式) 并且每个人都可以做这项工作'通过通用界面 - 或者如果您了解它们'你也可以专门访问它们,如果需要的话,比如IJsonOutputFormatInterface 如果/当您添加(或删除)新的时 - 它只是更改的配置部分 正如其他人所提到的,您只需要对每个服务进行编码,以便对其进行特定的处理,格式化渲染等 注意:不需要反思,它更像是一个重要的概念

答案 4 :(得分:0)

模式工厂方法就是你想要的。模式本身不会删除switch语句,但它只存在于一个地方。

但是,您可以将模式与一些反射组合以删除switch语句。

代码(伪代码)

public class FormatterFactory
{
  Dictionary<string, IFormatter> _formatters;

  public void FormatterFactory()
  {
      var baseType = typeof(IFormatter);
      var formatterTypes = AppDomain
            .GetExecutingAssembly()
            .GetTypes.Where(x=>baseType.IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract);

       // convention based. Each formatter must be named like "JsonFormatter"
       foreach (var type in formatterTypes) 
       {
           _formatters.Add(type.Name.Replace("Formatter", "").ToLower(), type), 
       }
  }
  public IFormatter Create(string formatName)
  {
      var type = _formatters[formatName.ToLower());
      return (IFormatter)Activator.CreateInstance(type);

  }
}

用法:

var factory = new FormatterFactory();
var json = factory.Create("json").Serialize(myObject);