访问ruby对象中对象的属性
我正在构建一个访问ruby对象中对象的属性,ruby,oop,object-oriented-analysis,Ruby,Oop,Object Oriented Analysis,我正在构建一个LineItemGenerator对象,其目的是在给定所需属性的情况下生成属性值数组 问题是给定对象将对象作为属性。因此,给定的“属性”实际上是“嵌套属性” 目标是通过创建一些输入数据结构和使用一些算法,从item访问请求的嵌套属性,在本例中是item.name和item.style.name 目前,我将我的“嵌套属性”输入数据结构表示为数组数组,nested\u attributes 我的算法叫做#generate 它采用原始的项和嵌套的_属性。接下来,它映射嵌套的_属性,通过在
LineItemGenerator
对象,其目的是在给定所需属性的情况下生成属性值数组
问题是给定对象将对象作为属性。因此,给定的“属性”实际上是“嵌套属性”
目标是通过创建一些输入数据结构和使用一些算法,从item
访问请求的嵌套属性,在本例中是item.name
和item.style.name
目前,我将我的“嵌套属性”输入数据结构表示为数组数组,nested\u attributes
我的算法叫做#generate
它采用原始的项
和嵌套的_属性
。接下来,它映射嵌套的_属性
,通过在每次迭代中将消息发送到原始项
,将每个嵌套的_属性
减少为一个“属性”
class Style
attr_reader :name
def initialize name:
@name = name
end
end
class Item
attr_reader :name, :style
def initialize name:, style:
@name = name
@style = style
end
end
class LineItemGenerator
def generate item:, nested_attributes:
nested_attributes.map do |nested_attribute|
nested_attribute.reduce(item) do |obj, attribute| # <-- algorithm using #reduce to burrow in
obj.send(attribute)
end
end
end
end
require 'minitest/autorun'
class SomeTest < Minitest::Test
def test_it_returns_the_right_line_item
style = Style.new name: 'cool'
item = Item.new name: 'pants', style: style
# input data structure is array or arrays
nested_attributes = [[:name], [:style, :name]]
input = { item: item, nested_attributes: nested_attributes}
output = LineItemGenerator.new.generate input
assert_equal ['pants', 'cool'], output
end
end
在这种情况下,有没有更好的方法?我的输入数据结构有更好的选择吗?这对我来说更像是一个软件设计问题,因此我将从设计角度来处理它
- 每次从一个组件的角度进行推理李>
- 将我们试图传达的内容与实施方式分开
LineItemGenerator
的工作是为给定所需属性的项目生成属性值数组
基于此,一个LineItemGenerator
:
- 获取具有属性的项
- 在给定所需属性列表的情况下,实现
生成属性值
这可能看起来像:
LineItemGenerator.new(@item).generate_attribute_values(:name, :style)
我要删除generate
,因为它在这里似乎不是正确的词。我们只是检索和过滤现有值,而不是创建新的属性值对象
LineItemGenerator.new(@item).attribute_values(:name, :style)
在这一点上,我考虑一个<代码>项目<代码>应该暴露给我们的代码> LineItemGenerator < /代码>。
- 项目具有属性
- 属性有值,这意味着它们也应该有名称李>
基于这种理解,我可以将LineItemGenerator
实现为:
class LineItemGenerator
def initialize(item)
@item = item
end
def attribute_values(*attribute_names)
@item.attributes.select { |attribute| attribute_names.include?(attribute.name) }.map(&:value)
end
end
此时,需要履行两项合同:
项目需要实现#属性
item.attributes
需要返回一组响应#name
和#value
现在,让我们从一个项目的角度来思考。
-一个项目有许多属性(例如名称和样式)。
-相关属性值可以在项
对象上定义,也可以委托给其他对象
合同1很难履行:
class Item
attr_reader :attributes
end
契约2更加灵活,因为它可以在条目或单个属性类上实现。如果某个属性不是应用程序中的首要关注点,我会在项上实现它
class Item
attr_reader :attributes
Attribute = Struct.new(:name, :value)
def initialize(name:, style:)
@attributes = [
Attribute.new(name: :name, value: name),
Attribute.new(name: :style, value: style)
]
end
end
如果系统的某些其他部分需要作为一级关注点与属性交互:
# TODO: DRY up using inheritance or modules
class Style
attr_reader :value
def initialize value:
@value = value
end
def name
:style
end
end
class ItemName
attr_reader :value
def initialize value:
@value = value
end
def name
:name
end
end
class Item
attr_reader :name, :style, :attributes
def initialize item_name:, style:
@name = item_name
@style = style
@attributes = [@name, @style]
end
end
对于一个纯Ruby问题,两个小时后没有答案可能意味着读者不理解它。您实际上是在说,“研究我的代码以理解问题”。这不会产生兴趣。你必须更准确地陈述你的问题。举个例子可能会有很大帮助。如果您给出一个,请确保所有数据都是有效的Ruby对象(例如,no[1,2,3…]
),为每个输入对象分配一个变量(a=[1,2,3]
),以便读者可以剪切和粘贴您的代码,并在答案和注释中引用这些变量,而无需定义它们,并显示您想要的结果。这也可能意味着今天是星期六:)。请参阅编辑和包含测试。这有助于澄清问题吗?对于这个问题,您的用例是什么?一个行\u项可以有多少类型的对象
?为什么一个属性数组
而不是名-值-键值对的散列?@mbigras散列要求#属性
的用户知道这将返回一个原始数据结构,并将解析数据结构的责任交给调用方。属性
对象也更容易扩展(例如添加格式方法等)。事实上,您可以返回属性列表
,而不是数组
,数组可能是提取属性值
(例如项.属性.值(名称)
)的更直观的地方。然后,如果应用程序的其余部分不关心属性的概念,我们将其委托回项.attribute\u值
,以完成整个循环
# TODO: DRY up using inheritance or modules
class Style
attr_reader :value
def initialize value:
@value = value
end
def name
:style
end
end
class ItemName
attr_reader :value
def initialize value:
@value = value
end
def name
:name
end
end
class Item
attr_reader :name, :style, :attributes
def initialize item_name:, style:
@name = item_name
@style = style
@attributes = [@name, @style]
end
end