是否有用于序列化和反序列化各种格式的对象层次结构的模式?

2024-05-05

给定一个复杂的对象层次结构,幸运的是它不包含循环引用,如何实现支持各种格式的序列化?我不是来讨论实际实施的。相反,我正在寻找可能派上用场的设计模式的提示。

更准确地说:我正在使用 Ruby,我想解析 XML 和 JSON 数据以构建复杂的对象层次结构。此外,应该可以将此层次结构序列化为 JSON、XML,甚至可能是 HTML。

我可以利用Builder这个模式?在任何提到的情况下,我都有某种结构化数据 - 无论是在内存中还是文本中 - 我想用它们来build up其他的东西。

我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种 XML 格式。


我最终创建了一个基于构建器和策略模式的解决方案。我使用生成器模式将解析和构建逻辑提取到自己的类中。这使我能够轻松地分别添加新的解析器和构建器。我使用策略模式来实现单独的解析和构建逻辑,因为该逻辑取决于我的输入和输出格式。

下图显示了我的解决方案的 UML 图。

下面的清单显示了我的 Ruby 实现。实现有点微不足道,因为我正在构建的对象相当简单。对于那些认为这段代码臃肿且类似 Java 的人来说,我认为这实际上是一个很好的设计。我承认,在这种微不足道的情况下,我可以直接将构造方法直接构建到我的业务对象中。但是,我没有在其他应用程序中构建水果,而是构建相当复杂的对象,因此将解析、构建和业务逻辑分开似乎是一个好主意。

require 'nokogiri'
require 'json'

class Fruit

  attr_accessor :name
  attr_accessor :size
  attr_accessor :color

  def initialize(attrs = {})
    self.name = attrs[:name]
    self.size = attrs[:size]
    self.color = attrs[:color]
  end

  def to_s
    "#{size} #{color} #{name}"
  end

end

class FruitBuilder

  def self.build(opts = {}, &block)
    builder = new(opts)
    builder.instance_eval(&block)
    builder.result
  end

  def self.delegate(method, target)
    method = method.to_sym
    target = target.to_sym

    define_method(method) do |*attrs, &block|
      send(target).send(method, *attrs, &block)
    end
  end

end

class FruitObjectBuilder < FruitBuilder

  attr_reader :fruit

  delegate :name=,  :fruit
  delegate :size=,  :fruit
  delegate :color=, :fruit

  def initialize(opts = {})
    @fruit = Fruit.new
  end

  def result
    @fruit
  end

end

class FruitXMLBuilder < FruitBuilder

  attr_reader :document

  def initialize(opts = {})
    @document = Nokogiri::XML::Document.new
  end

  def name=(name)
    add_text_node(root, 'name', name)
  end

  def size=(size)
    add_text_node(root, 'size', size)
  end

  def color=(color)
    add_text_node(root, 'color', color)
  end

  def result
    document.to_s
  end

  private

  def add_text_node(parent, name, content)
    text = Nokogiri::XML::Text.new(content, document)
    element = Nokogiri::XML::Element.new(name, document)

    element.add_child(text)
    parent.add_child(element)
  end

  def root
    document.root ||= create_root
  end

  def create_root
    document.add_child(Nokogiri::XML::Element.new('fruit', document))
  end

end

class FruitJSONBuilder < FruitBuilder

  attr_reader :fruit

  def initialize(opts = {})
    @fruit = Struct.new(:name, :size, :color).new
  end

  delegate :name=,  :fruit
  delegate :size=,  :fruit
  delegate :color=, :fruit

  def result
    Hash[*fruit.members.zip(fruit.values).flatten].to_json
  end

end

class FruitParser

  attr_reader :builder

  def initialize(builder)
    @builder = builder
  end

  def build(*attrs, &block)
    builder.build(*attrs, &block)
  end

end

class FruitObjectParser < FruitParser

  def parse(other_fruit)
    build do |fruit|
      fruit.name  = other_fruit.name
      fruit.size  = other_fruit.size
      fruit.color = other_fruit.color
    end
  end

end

class FruitXMLParser < FruitParser

  def parse(xml)
    document = Nokogiri::XML(xml)

    build do |fruit|
      fruit.name  = document.xpath('/fruit/name').first.text.strip
      fruit.size  = document.xpath('/fruit/size').first.text.strip
      fruit.color = document.xpath('/fruit/color').first.text.strip
    end
  end

end

class FruitJSONParser < FruitParser

  def parse(json)
    attrs = JSON.parse(json)

    build do |fruit|
      fruit.name  = attrs['name']
      fruit.size  = attrs['size']
      fruit.color = attrs['color']
    end
  end

end

# -- Main program ----------------------------------------------------------

p = FruitJSONParser.new(FruitXMLBuilder)
puts p.parse('{"name":"Apple","size":"Big","color":"Red"}')

p = FruitXMLParser.new(FruitObjectBuilder)
puts p.parse('<fruit><name>Apple</name><size>Big</size><color>Red</color></fruit>')

p = FruitObjectParser.new(FruitJSONBuilder)
puts p.parse(Fruit.new(:name => 'Apple', :color => 'Red', :size => 'Big'))
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

是否有用于序列化和反序列化各种格式的对象层次结构的模式? 的相关文章

  • 进度状态报告模式

    我正在实现需要显示进程栏 或进度百分比 的长时间运行的进程 长时间运行的过程的整体逻辑很复杂 各种分页数据检索 因此 我最终在代码中的不同位置硬编码了大量百分比 在更新完成百分比时 什么被认为是最佳设计模式 我发现 JFace 周围使用的模
  • CISC 机器 - 它们不只是将复杂指令转换为 RISC 吗?

    也许我在架构上存在误解 但如果机器有 比如说 乘法指令 该指令是否未转换为更小的指令 或者过于复杂以至于最终与等效的 RISC 指令具有相同的速度 乘法是一个不好的例子 它在两种体系结构中都是一条指令 将上面的 乘法 替换为 CISC 中更
  • 序列化包含 BitmapImage 的对象

    这是关于该主题的进一步问题 如何使用反序列化对象 https stackoverflow com questions 18444861 how to use deserialized object 18455591 18455591我的班级
  • 查询,无法选择列数

    Tag joins quote tags group quote tags tag id order count desc select count tags id AS count tags id tags name Build quer
  • Struts ActionForm 属性应该是什么类型?

    我使用 Struts 1 2 4 继承了这个巨大的遗留 Java Web 应用程序 我有一个关于 ActionForms 的具体问题 其中一些仅具有字符串属性 即使对于数字 其中一些使用看似合适的类型 整数 日期 字符串等 这里的最佳实践是
  • Mac + Ruby:无法访问 Socket 的 ioctl?怎么修?

    一天中的好时光 红宝石代码 def hw address iface sock Socket new Socket AF INET Socket SOCK DGRAM 0 buf iface pack a16h16 sock ioctl S
  • 如何在Java中实现复合模式?

    我想实现一个复合模式Java以便绘制软件开发组织图 因此 我们假设有多个项目经理和多个开发人员 每个开发人员都被分配给一位项目经理 并且每个开发人员都能够使用各种编程语言进行编码 项目经理领导开发人员并准确了解他们的工作量 我对这个设计模式
  • 捆绑安装到开发

    由于某种原因 当我跑步时bundle install它安装到生产中 Your bundle is complete It was installed into RAILS ENV production Arrrghh 我如何切换回开发 No
  • 如何读取rack请求中的POST数据

    当我运行curl命令时 curl v H Content type application json X POST d name abc id 12 subject my subject http localhost 9292 要将包含数据
  • 为什么 C# ProcessStartInfoRedirectStandardOutput 会导致 xcopy 进程失败

    这有点痛苦 因为我现在没有代码 但我会尽力解释 我有一个简单的 C 应用程序 它启动 Ruby 脚本 它还执行一些其他操作 因此它生成一个批处理文件并执行该文件 我正在使用 C 进程对象并设置以下内容 重定向标准输出 true 重定向标准错
  • 使用 iostream << 序列化用户对象

    我想使用运算符 ofstream out file ios out ios binary int i 0xAA out lt lt i 并输出 0x31 0x37 0x30 即 0xAA gt 170 170 如果我使用 write 函数
  • Ruby openssl 文档 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 有没有 Ruby 的在线文档openssl图书馆 我能找到的只是博客文章和第三方文章 而 rdoc 本
  • 获取特定时区一天开始时的时间对象

    如何获取代表给定时区特定日期的一天开始时间的 ruby Time 对象 date Date today date to time in time zone America New York beginning of day 目前输出 gt
  • C 编译器无法在 Mac OS Mountain Lion 上创建可执行文件

    我几乎浏览了每一页 但所有提示都不能解决问题 我正在运行 Mountain Lion 我有 Xcode 所有最新的开发工具 最新的 GCC 等等 我正在尝试设置 rbenv 和 ruby build 一切似乎都正常 但是当我去安装 ruby
  • 从标签中提取 HTML5 数据属性

    我想从标签中提取所有 HTML5 数据属性 就像这个 jQuery 插件 http www orangesoda net jquery dataset html 例如 给定 span class highlight Joe Bloggs s
  • Ruby on Rails 中的垃圾收集器?

    我尝试在 Google 上搜索很多有关 Rails 垃圾收集器的信息 但没有得到可靠的答案 有谁有资源来展示如何垃圾收集是在 Rails 中实现的吗 我们怎样才能控制它呢 Rails 是一个框架 而不是一种语言 Rails 背后的语言称为
  • 在Ruby中做每个,如何在每n个项目中放置一个br

    假设我有 10 个项目要迭代 我想每 3 个项目放置一个 br 就像这个例子一样 我怎样才能在 Ruby 中做到这一点 1 2 3 br 4 5 6 br 7 8 9 br 10 解决方案1 1 10 each slice 3 a puts
  • Rails I18n 翻译范围

    编写完全翻译的应用程序可能会变得乏味 有没有办法为当前上下文设置默认翻译范围 示例 我正在部分内容中写入 deadlines html erb in the 显示 html erb我的行动ProjectsController 现在 因为我想
  • 模块化大型 Grails 应用程序的最佳实践?

    我正在开发的 Grails 应用程序变得相当大 最好将其重构为几个模块 这样我们就不必每次都重新部署整个事情 将 Grails 应用程序拆分为多个模块的最佳实践是什么 特别是 我想创建一个域类 相关服务的包 并将其作为模块在应用程序中使用
  • 您对“大规模 C++ 软件设计”的看法 [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 正在阅读亚马逊评论 https rads stackoverflow com amzn click com 0201633620 and ACC

随机推荐

  • 如何在核心数据中保存通用测量<单位>?

    如何在核心数据中保存和检索通用测量 我想做的是保存Measurement
  • 过滤(包含/排除)文件以查找 Bower 依赖项

    我正在尝试使用 Bower 来管理 Java JSP 服务器端应用程序的客户端依赖项 它有效 我可以访问通过 bower install 解析的客户端库 如 Bower json 中所述 然而 许多不必要的文件被添加到 bower comp
  • Android searchView下拉菜单屏幕宽度

    情况 我的 appcompat 工具栏中有一个 searchview 小部件 允许通过 sqlitedatabase 提供自定义建议 Problem 我无法将下拉建议列表扩展到屏幕的整个宽度 最好的情况下 列表宽度几乎是屏幕的宽度 除了左侧
  • Spring Batch - 读取多行日志消息

    我面临一个问题 在配置了 Spring 集成的 Spring Batch 应用程序中将多行日志消息读取为单个消息 该应用程序必须将多行日志消息 示例异常堆栈跟踪 读取为单个消息 稍后它必须处理并对消息进行分类以进一步建立索引 每行都由其时间
  • 从 ALT+TAB 菜单隐藏无边框窗口

    我正在开发一个带有无边界表单的托盘应用程序 该应用程序在后台运行 如果用户想要执行不同的操作 他们可以通过右键单击托盘图标 NotifyIcon 来打开上下文菜单 所以我的要求是 1 应用程序始终以最小化模式启动 并且将显示托盘图标 2 应
  • Python 有哪些重要的语言特性(习语)需要尽早学习[重复]

    这个问题在这里已经有答案了 我有兴趣了解 StackOverflow 社区认为 Python 的重要语言特性 习语 是什么 将程序员定义为 Pythonic 的特征 Python pythonic 习语 Python 语言自然的或特有的 代
  • mocha 在文件之间共享变量

    我正在尝试在 2 个摩卡测试文件之间连接对象 这是我的 test1 js 文件 一旦执行所有测试用例 该文件应该导出一个变量 var assert require assert var newUser email email protect
  • Javascript:无法停止setTimeout

    我正在开发一个代理服务器检查器 并使用以下代码使用 setTimeout 函数以大约 5 秒的间隔启动请求 function check var url document getElementById url value var proxy
  • 何时使用环境变量与系统属性?

    我想知道以下哪种方法是首选方法 我们可以将事情设置为APP HOME path to file export in profile或类似的东西 并将其访问为System getenv APP HOME 或者 也可以使用属性作为 DAPP H
  • 如何重命名 MongoDB 中对象数组中的嵌套键?

    文件结构 id 5 grades grade 80 mean 75 std 8 mean 90 std 5 mean 85 std 3 根据 mongodb 中的上述文档结构 我想将键grade 重命名为grade db collectio
  • 使用 GestureDetector 时出现 NullPointerException

    下面是在发生不同事件时加载两个不同图像的帧动画的代码 第一个事件是在活动开始时 其他的是onTouch 我在哪里利用GestureDetector为了onDown and onScroll 问题是我得到NullPointerExceptio
  • EF7 中的脚手架不再产生“setter”

    我试图将我的个人项目从 Net 6 升级到 7 主要是为了找出重大更改 因此 我预计有些东西需要返工 情况总是如此 如果在某个时候我敢于完成这个项目 那么它就是一个非营利项目 但目前的情况还远未实现 作为现在的上下文 我正在管理一个包含类别
  • 如何在 R 或 MATLAB 中为散点图创建阴影误差条“框”

    我想在 R 或 MATLAB 中创建一个简单的散点图 涉及两个变量 x 和 y 它们有与之相关的错误 epsilon x 和 epsilon y 然而 我不是添加误差线 而是希望在每个 x y 对周围创建一个 阴影框 其中框的高度范围从 y
  • Django 管理员使用 JWT

    Using 姜戈 1 11 Python 3 6 FE 中的 DRF 与 JWT 我知道 Django 管理员使用会话和基本身份验证 到目前为止我所做的 用 AWS Cognito 替换了 Django 管理员身份验证登录页面 用户转到do
  • Vim / vi 生存指南

    基本的 vim 命令有哪些 新用户需要了解什么才能避免陷入麻烦 请每条评论一条命令 我发现不可替代的 因为它也可以在 vi 中使用 与 vim 的视觉模式不同 是标记 您可以用以下标记标记不同的点m 小写 然后是您选择的字母 例如 x 然后
  • 如何使使用 CSS :after 元素创建的文本可选择?

    我正在使用 css 创建文本 after 但我无法选择生成的文本 例如用于复制和粘贴 是否可以使其可选择 div foo div div after content 123 sample http jsfiddle net jfbc4 2
  • 如何将点光源转换为卵形/椭圆形?

    我希望通过具有不同 x 和 y 值的 vec2 半径将当前的圆形光变成椭圆形 有没有办法根据我当前在片段着色器中的代码来做到这一点 uniform struct Light vec4 colour vec3 position vec2 ra
  • SVG/XML 中有一些innerHTML 替代品吗?

    在 HTML 中 我可以通过提供字符串形式的模板来构建一个简单的模板系统 替换其中的某些部分 然后使用innerHTML到某个容器 var templ span myText span var newContent templ replac
  • 如何动态构造方法?

    我设计了一个类 它非常标准 具有一些方法属性 class foo def f1 self print f1 def f2 self print f2 def fn self print fn 现在我想创建一个包含一组 foo 实例的类 cl
  • 是否有用于序列化和反序列化各种格式的对象层次结构的模式?

    给定一个复杂的对象层次结构 幸运的是它不包含循环引用 如何实现支持各种格式的序列化 我不是来讨论实际实施的 相反 我正在寻找可能派上用场的设计模式的提示 更准确地说 我正在使用 Ruby 我想解析 XML 和 JSON 数据以构建复杂的对象