【问题标题】:Best way to create objects from different data formats从不同数据格式创建对象的最佳方式
【发布时间】:2012-03-26 21:36:40
【问题描述】:

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

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 可能会让人感到困惑。

我想知道从可扩展性和可维护性的角度来看,最好的解决方案是什么。

【问题讨论】:

  • 澄清一下,您需要一个可以根据不同输入(JSON、XML 等)创建对象的服务吗?那么,返回的对象永远是一样的,只是输入的不同?这听起来确实很像您的代码有些混乱,并且通过一些重组,您只需要使用策略模式'
  • @JustinPihony 我知道这看起来很令人困惑,但是是的,这就是我所需要的。问题是使用这种方法会创建许多不同的对象,我觉得策略不是最合适的。

标签: c# design-patterns


【解决方案1】:

您可以将其设置为接口 (IFormat),而不是将其设置为枚举。

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

每个具体类应该只具有特定格式所独有的内容,例如如何在给定Id 的情况下找到元素/记录。

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

【讨论】:

  • 我不想混淆获取数据的逻辑(我发布的代码)和从中创建实例的逻辑。这是问题的一部分。
  • 问题的一部分是“Foo”不是唯一必须以这种方式创建的对象。对于必须创建的每种类型,我是否应该在“JsonFormat”中有一个方法?我觉得有些不对劲/丢失了。
【解决方案2】:

您在这里显然是在谈论creational patterns,但我认为我们对 Foo 的复杂性了解得不够多,无法明确推荐一个。幸运的是,GoF 创建模式并不多,因此您可以在相当短的时间内阅读所有这些模式。看来您已经了解factory-method 模式,因此您可以跳至abstract factorybuilder 看看它们是否更符合要求。

来自 builder wiki 的提示:

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

希望对您有所帮助。

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

      具体来说,您可以使用 IOC(例如 autofac)和某种类型的注入(我看到您已经接近这种想法了),
      在启动时注册所有可用的格式服务
      (来自配置或简单的一次性初始化,随着时间的推移,您可以在添加新类型时轻松维护)...
      例如实现 IOutputFormatService 接口
      然后,您可以动态地将它们四舍五入(例如,解析、列出所有已实现的格式)
      每个人都可以通过通用界面“完成工作” - 或者如果您“了解他们”,您也可以专门访问它们,如果需要的话,例如 IJsonOutputFormatInterface。
      如果/当您添加(或删除)新的 - 它只是更改的配置部分
      正如其他人所提到的,您只需对每个服务进行编码以执行特定于它的操作、格式呈现等。
      注意:反射不是必需的,它更像是一个重要的概念

      【讨论】:

        【解决方案5】:

        模式工厂方法就是你想要的。模式本身不会删除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);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-07-09
          • 2013-06-17
          • 2023-03-12
          • 1970-01-01
          相关资源
          最近更新 更多