Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/260.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从不同数据格式创建对象的最佳方法_C#_Design Patterns - Fatal编程技术网

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

C# 从不同数据格式创建对象的最佳方法,c#,design-patterns,C#,Design Patterns,对于我正在处理的项目,我需要使用不同的源数据格式创建对象,大致如下所示: public class FooService { protected DataFormat Format { get; set; } public FooService(DataFormat format = DataFormat.Json) { Format = format; } public Foo GetFoo(int id) {

对于我正在处理的项目,我需要使用不同的源数据格式创建对象,大致如下所示:

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成为接口或抽象类,并实现具体类,每种格式一个

缺点:除了类实例化之外,所有类中的业务逻辑总是相同的。使用
JsonFooService
XmlFooService
可能会让人混淆


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

您可以将格式设置为接口(
IFormat

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

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


这是“策略模式”:

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


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

具体来说,您可以使用IOC(例如autofac)和某种类型的注入(我看您已经接近这种想法了),
在启动时注册所有可用格式服务 (通过配置或简单的一次性初始化,在添加新类型时易于维护)…
例如,实现IOutputFormatService接口
然后,您可以动态地对它们进行取整(例如,解析、列出所有实现的格式)
每个人都可以通过公共界面“完成任务”——或者如果你“了解他们”,你也可以专门访问他们,如IJsonOutputFormatInterface(如果需要)。
如果/当您添加(或删除)新内容时-更改的只是配置部分
正如其他人所提到的,您只需要对每个服务进行编码,就可以执行特定于它的操作、格式呈现等。
注意:反射不是必需的,它更重要的是一个概念,你在这里讲得很清楚,但我认为我们对Foo的复杂性了解不够,无法清楚地推荐一个而不是另一个。幸运的是,没有那么多的GoF创作模式,所以你可以在很短的时间内阅读所有这些模式。看来您已经了解了模式,因此您可以跳到,看看它们是否更符合要求

来自builder wiki的提示:

  • Builder专注于逐步构建复杂对象。抽象工厂强调一系列产品对象(或简单 或复杂)。生成器返回产品作为最后一步,但尽可能 就抽象工厂而言,产品被退回 马上
  • 建设者经常构建一个
  • 通常,设计从使用工厂方法开始(不太复杂,更可定制,子类激增),然后向抽象方向发展 工厂、原型或制造商(更灵活、更复杂)作为 设计师发现哪里需要更多的灵活性
  • 有时,创建模式是互补的:构建器可以使用其他模式之一来实现构建的组件。 抽象工厂、构建器和原型可以在它们的应用程序中使用Singleton 实现
  • 建筑商是一个很好的选择

希望对您有所帮助。

模式工厂方法正是您想要的。模式本身不会删除
开关
语句,但它只存在于一个位置

但是,您可以将该模式与一点反射结合起来,以删除switch语句

代码(伪代码)


为了澄清这一点,您需要一个能够基于不同输入(JSON、XML等)创建对象的服务吗?那么,返回的对象总是相同的,只有输入不同?这听起来很像你的代码有点混乱,经过一些重组,你只需要使用策略模式“@JustinPihony,我知道这看起来很混乱,但是的,这正是我需要的。问题是,有许多不同的对象将使用此方法创建,我觉得策略不是最合适的。我不想混淆获取数据(我发布的代码)的逻辑和从中创建实例的逻辑。这是问题的一部分,问题的一部分是“Foo”不是唯一一个必须以这种方式创建的对象。对于必须创建的每个类型,我是否应该有一个“JsonFormat”的方法?我觉得好像有什么不对劲/遗漏了。
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);