我正在重构一个代表某些XML数据的类。目前,该类加载XML本身,属性实现每次都解析XML。我想分解XML逻辑并使用工厂来创建这些对象。但是有几个“可选”属性,我很难找到一种优雅的方法来处理这个问题。
假设XML看起来像这样:
<data>
<foo>a</foo>
<bar>b</bar>
</data>
假设foo和bar都是可选的。类实现看起来像这样:
interface IOptionalFoo
{
public bool HasFoo();
public string Foo { get; }
}
// Assume IOptionalBar is similar
public class Data : IOptionalFoo, IOptionalBar
{
// ...
}
(不要问我为什么会有混合的方法和属性。我没有设计那个界面而且它没有改变。)
所以我有一个工厂,它看起来像这样:
class DataFactory
{
public static Data Create(string xml)
{
var dataXml = new DataXml(xml);
if (dataXml.HasFoo())
{
// ???
}
// Create and return the object based on the data that was gathered
}
}
这是我似乎无法满足优雅解决方案的地方。我做了一些搜索,发现了一些我不喜欢的解决方案。假设我遗漏了构造函数中的所有可选属性:
我能想到的唯一其他解决方案是在数据类中添加一些方法:
class Data : IOptionalFoo, IOptionalBar
{
public static Data WithFoo(Data input, string foo)
{
input.Foo = foo;
return input;
}
}
如果我这样做,Foo的制定者可以是私人的,这让我更快乐。但我真的不喜欢用很多创建方法乱丢数据对象。有很多可选属性。我已经考虑过为每个属性创建一个带有可为空的版本的get / set API的DataInitialization对象,但是很多属性都是可选的,它最终更像是我重构的对象变成了读取的外观/写版本。也许这是最好的解决方案:类的内部读/写版本。
我是否列举了这些选项?我是否需要放弃如此挑剔并坚持上述技巧之一?还是有其他一些我没有想过的解决方案?
答案 0 :(得分:0)
您可以将这些关键字视为虚拟/城堡动态代理/反射/ T4脚本 - 每个人都可以在稍微不同的角度解决问题。
另一方面,这似乎是完全合理的,除非我误解了你:
private void CopyFrom(DataXml dataXml) // in Data class
{
if (dataXml.HasFoo()) Foo = dataXml.Foo;
//etc
}
答案 1 :(得分:0)
我做了什么:
我创建了一个新类,它代表了所有属性的读/写接口。现在,Data类的构造函数通过构造函数获取该类型的实例,并使用只读版本包装读/写属性。这有点乏味,但没有我想象的那么糟糕。