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);