RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1167450
Accepted
Bakuard
Bakuard
Asked:2020-08-18 20:48:32 +0000 UTC2020-08-18 20:48:32 +0000 UTC 2020-08-18 20:48:32 +0000 UTC

保存应用程序数据的架构方法

  • 772

再会。

任务:有一个适用于桌面和安卓的应用程序。您需要定义一种将应用程序数据保存到永久内存的架构方法,同时考虑以下特性:

  1. 某种类型的对象的部分字段是其内部实现的一部分,必须对客户端代码完全隐藏,同时这些字段的值也必须保存。
  2. 存储对象的位置和方法可以在应用程序的移植和开发过程中更改和添加(因此可以使用 SAX 或 DOM 解析器 [Desctop 版本] 将对象保存在存储在用户机器上的 json 或 xml 文件中;保存在关系[SQLite, HyperSql, MySql] 通过 JDBC 或一些 ORM 连接;保存到服务器)。
  3. 某些类型的对象是不可变的。

我尝试了哪些方法:

  1. 为每个需要保存对象的类实现 save() 和 load() 方法。如果您需要以多种方式保存对象,那么对于每个方法,我们都会创建自己的一对方法(例如,saveToJson()、loadToJson() 等)

    我认为的优点:内部实现的字段对客户端代码完全隐藏,同时我们可以轻松保存/加载它们。

    我认为缺点:在我看来,单一责任原则被违反了。第二个缺点是这种方法不能应用于不可变字段(因此,不可变对象),因为它们的初始化只能在调用构造函数时执行(我想将所有应用程序对象保存在统一的方式)。

  2. 使用稍微修改的 Memento 模式(为了保存一个对象,我们获取它的存储对象并保存它。与该模式的经典实现不同,要恢复创建者对象,我们会将存储对象传递给构造函数,而不是特殊的方法)。

    我认为的优点:直接从对象本身读取/写入隐藏字段的值 - 它不起作用。第二个优点是负责保存的代码可以移动到单独的模块中并放在单独的包中。

    我认为缺点:保管人对象必须不仅为创建者对象开放对其状态的访问,而且还为将保存它的对象开放。原来,通过保管人对象,创建者对象间接揭示了它的整个状态。

  3. 在单独的模块中,为要保存的每种类型的对象声明一个 DAO 接口。如果一个类具有不希望提供对客户端代码的访问的字段,则 DAO 接口被实现为嵌套类。

    我认为的优点:由于嵌套类,内部实现的字段对客户端代码完全隐藏。

    我认为缺点:由于嵌套类,负责保存的代码不能完全分离到单独的模块中并放在单独的包中。因此,负责保存的代码被模块和包分开。

问题: 通常如何解决类似的问题?我应该选择我考虑的三个选项之一,如果是,为什么?如果您认为我在描述我考虑的一些解决方案的优缺点时犯了错误,请指出。

java
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    Bakuard
    2020-08-20T11:56:12Z2020-08-20T11:56:12Z

    一开始,我尝试使用 save() 和 load() 方法来完善这个想法。我决定创建一些通用的 Saver 和 Loader 接口,通过它们可以以统一的方式使用 JSON、XML 和 SQL。保存的对象必须具有 save(Saver saver) 方法和带有 Loader 参数的构造函数(不是 load(Loader loader) 方法,而是能够加载最终字段的构造函数)。为了使接口不需要泄露存储对象的隐藏字段,并且可以用于处理任何类型的对象,并且还可以处理 XML、JSON 和 SQL,有必要立即计算它们以处理分层数据结构。我决定做类似的事情:

    public interface Saver {
        public Saver beginSection() throws Exception;
        public Saver endSection() throws Exception;
        public Saver meta(MetaData meta) throws Exception;
        public Saver value(String key, int value) throws Exception;
        public Saver value(String key, boolean value) throws Exception;
        //... Перегрузки метода value() для других типов данных
        public void save() throws Exception;
        public void close() throws Exception;
    }
    

    并下载

    public interface Loader {
        public void beginSection() throws Exception;
        public void endSection() throws Exception;
        public MeatData nextMeta() throws Exception;
        public boolean hasNextTokenInSection() throws Exception;
        public int getInt(String key) throws Exception;
        public boolean getBoolean(String key) throws Exception;
        //... Другие методы nextXXX() для других типов данных.
        public void close() throws Exception;
    }
    

    但是尝试选择通用接口要么导致接口功能极差,不允许使用数据存储格式(XML、JSON、关系数据库表)的特性,要么变得非常不一致和臃肿。此外,根本不可能为所有处理数据的方式选择一个通用的接口(我无法想象接口应该如何与 ORM、XML 和 JSON 一起使用)。结论——试图为世界上的一切建立一个通用接口——一个最初注定要失败的想法。每种数据存储格式都需要以特定方式处理。

    因此,我选择了第二种解决问题的方法(Memento 模式),因为它允许您以特定的方式处理每种数据存储格式(不会将所有内容混为一团),以及完全分离负责从业务逻辑代码中保存的代码,尽管以削弱封装为代价。

    • 3

相关问题

  • wpcap 找不到指定的模块

  • 如何以编程方式从桌面应用程序打开 HTML 页面?

  • Android Studio 中的 R.java 文件在哪里?

  • HashMap 初始化

  • 如何使用 lambda 表达式通过增加与原点的距离来对点进行排序?

  • 最大化窗口时如何调整元素大小?

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    如何从列表中打印最大元素(str 类型)的长度?

    • 2 个回答
  • Marko Smith

    如何在 PyQT5 中清除 QFrame 的内容

    • 1 个回答
  • Marko Smith

    如何将具有特定字符的字符串拆分为两个不同的列表?

    • 2 个回答
  • Marko Smith

    导航栏活动元素

    • 1 个回答
  • Marko Smith

    是否可以将文本放入数组中?[关闭]

    • 1 个回答
  • Marko Smith

    如何一次用多个分隔符拆分字符串?

    • 1 个回答
  • Marko Smith

    如何通过 ClassPath 创建 InputStream?

    • 2 个回答
  • Marko Smith

    在一个查询中连接多个表

    • 1 个回答
  • Marko Smith

    对列表列表中的所有值求和

    • 3 个回答
  • Marko Smith

    如何对齐 string.Format 中的列?

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5