【问题标题】:Techniques for object-oriented or modular file and data I/O?面向对象或模块化文件和数据 I/O 的技术?
【发布时间】:2016-06-05 19:30:10
【问题描述】:

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

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

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

这个关于what object should invoke saving 的问题解决了这个问题的一个子主题。这个问题似乎是指工厂模式,其中文件的内容被构建,然后最终写入磁盘。我的问题是关于整体架构,包括用于写入操作的工厂,以及用于读取/获取操作的 (在此处插入模式)

我能想出的最好的东西是外观模式......但是神圣的烟雾是那些外观中的代码丑陋。

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

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


示例

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

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

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

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

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

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

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


从 3 周前编辑...

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

我希望以后避免编写此类代码。

【问题讨论】:

  • 你能把zohoFile 当作一个对象,扩展抽象..File 吗?因此,每次新的应用程序/客户端出现时,您只需要实现特定于它的抽象方法。然后getZohoFiles 将创建List<ZohoFile> 并在每个对象上调用get(或其他)方法。
  • @ketan 这是一个好的开始,但您能否进一步扩展和概括这一点?

标签: oop design-patterns io modularity


【解决方案1】:

此解决方案可能无法完全解决您的问题或疑问的细节,但我想分享一下我为统一 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、文件路径、Web URL...等)是已知的。

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

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

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

【讨论】:

    【解决方案2】:

    Holub 使用 Builder 模式从对象中导出数据(渲染),并使用他命名的 Inverse Builder 模式进行初始化。

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

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

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

    【讨论】:

      【解决方案3】:

      Template Pattern

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

      【讨论】:

        猜你喜欢
        • 2011-04-28
        • 1970-01-01
        • 1970-01-01
        • 2011-08-09
        • 1970-01-01
        • 2018-02-03
        • 2016-08-11
        • 1970-01-01
        • 2011-08-04
        相关资源
        最近更新 更多