面向对象或模块化文件和数据的技术 I/O?

Techniques for object-oriented or modular file and data I/O?

似乎每次我去编写任何处理获取、推送、读取或写入操作的代码时,整段代码都是临时的、丑陋的,并且在确切的上下文之外完全无法使用应用。更糟糕的是,每次设计这些东西时,感觉我都必须重新发明轮子。在我看来,I/O 操作的本质是非常线性的,不太适合模块化或面向对象的模式。

我真的希望有人能告诉我我错了。 是否有面向对象或模块化文件和数据的 techniques/patterns I/O?我可以遵循一些约定来添加 一些 代码可重用性吗? 我知道存在各种工具可以更轻松地读取单个文件,例如 XML 解析器等等,但我指的是使用这些工具的大型设计。

问题不仅限于一种语言;我在 Java、C、Matlab、Python 和其他方面遇到了同样的问题。

这个关于 what object should invoke saving 的问题解决了这个问题的一个子主题。这个问题似乎指的是一种工厂模式,在这种模式下,文件的内容被建立起来,然后最终写入磁盘。我的问题是关于整体架构,包括写操作的工厂,还有 (Insert Pattern Here) 用于 reading/fetching 操作。

我能想出的最好的事情是外观模式...但天哪,那些外观中的代码丑陋。

有人请告诉我存在一种模式,我可以在其中重复使用我的一些代码,或者至少遵循未来读写的模板。

有人问过 Modular Design here,但答案是针对那个提问者的问题的,并不完全有用。


例子

这只是一个例子,是基于我去年做的一个项目。请随意提供一个不同的例子。

我们的程序是一个物理沙箱。我们想要加载 XML 描述沙箱中对象物理属性的数据。我们还需要加载包含 3D 渲染信息的 .3DS 文件。最后,我们需要查询一个 SQL 数据库以找出谁拥有什么对象。

我们还需要能够支持 3D 模型格式。我们还不知道那些文件会是什么样子,但我们想提前设置好代码框架。这样,一旦我们得到新的数据模式,就可以快速实现加载例程。

来自所有 3 个来源的数据将用于在我们的软件中创建对象实例。

稍后,我们需要将位置和速度等物理信息保存到数据库,并将自定义纹理信息保存到本地文件。我们不知道纹理将是什么类型的文件,所以我们只想布置代码结构,以便我们稍后可以放入保存代码。

如果没有某种设计模式,即使是少量对象也会很快导致紧密耦合的网络。

Facade 可以将 objects/data 与相应的文件解耦,但所做的只是将问题集中在输入和输出 Facade 中,这很快就会变成噩梦般的混乱。此外,objects/data 现在与外观紧密耦合,因此没有真正获得模块化。


3 周前编辑...

以前,当我第一次问这个问题时,我已经为我所面临的问题提供了一堆伪代码,但后来我认为它混淆了我的主要问题。可以这么说:我不得不为那组特定的读取操作使用大约 2000 行非常糟糕的代码,它在处理和组织方面做得非常少,而且我再也不能在另一个项目中使用它们中的任何一个.

我想避免以后再写这样的代码。

Holub 使用构建器模式从对象导出数据(渲染),并使用他命名为逆构建器模式的东西进行初始化。

这些 Exporter/Importer 他称之为对象的对象是域模型模型本身的一部分,这是模型应该使用不同数据源持续存在和创建自身的一种方式。

https://youtu.be/CYCNRCrX1zE?t=45m6s

http://www.javaworld.com/article/2072302/core-java/more-on-getters-and-setters.html

此解决方案可能未完全解决您的问题或问题的某些细节,但我想分享我为统一 I/O 操作而采用的方法。我以前在几种不同的高级语言中使用过它。此策略在与序列化结合使用时效果最佳。

两个基本的I/O操作好像是Save/Put和Load/Get。这是最抽象的通用接口,表示:

public interface ObjectRepository
{
    <T> void save(string resourceId, T obj);
    <T> T load(string resourceId);
}

此策略适用于所有类型的 I/O 操作,其中资源 ID(数据库 UUID/GUID/String、文件路径、网络 URL...等)是已知。

最简单的实现因语言和框架而有所不同,但我发现最普遍适用的是依赖于标准序列化形式的实现,即二进制、XML 和 JSON。使用专有对象时,我最常使用 XmlFileRepository,它将我的简单数据对象 to/from Xml 和所选文件路径中的 saves/loads 转换。

此外,如果与抽象工厂模式结合使用,即使是单一类型的对象,使用不同的数据格式输入和输出也是微不足道的。示例代码:

public NewtonianObject load(string respositoryType, string resourceId) 
{
    ObjectRepository repo = RepositoryFactory.create(respositoryType);
    return (NewtonianObject)repo.load(resourceId);
}

public void exportAsXml(string fileName, NewtonianObject obj)
{
    ObjectRepository repo = RepositoryFactory.create("XmlFileRepository");
    repo.save(fileName, obj);
}

Template Pattern

在模板模式中,创建一个与 I/o 操作相关的抽象 class,如果存在任何可重用性,它包含一组抽象方法和一些其他方法。所有外部系统,如数据库、文本...都可以扩展这个抽象 class 并完成特定的工作。