如果解决方案是动态变量名称,则您现在有两个问题。
一般来说,如果你曾经试图使用动态变量名,答案可以是散列表,数组或函数。在这种情况下,功能是适当的。使用extract method refactoring。
注:我的Ruby是生锈的,为编码错误道歉。我将基本保持原来的算法,因为这不是重点。
从一个重复的代码块开始。
# Build grade objects and insert into hash
pass_fail_array = load_csv(pass_fail_file)
grade_collection = pass_fail_array.map{ |e| Grade.new(e) }
grade_hash = {}
grade_collection.each do |x|
grade_hash[x.mark.to_s] = x
end
把它变成一个功能通过在函数声明它包裹并返回代码块的乘积:grade_hash
。该变量的声明之外的功能
def load_from_csv()
pass_fail_array = load_csv(pass_fail_file)
grade_collection = pass_fail_array.map{ |e| Grade.new(e) }
grade_hash = {}
grade_collection.each do |x|
grade_hash[x.mark.to_s] = x
end
return grade_hash
end
注意,只是pass_fail_file
所以把它传递。
def load_from_csv(file)
pass_fail_array = load_csv(file)
grade_collection = pass_fail_array.map{ |e| Grade.new(e) }
grade_hash = {}
grade_collection.each do |x|
grade_hash[x.mark.to_s] = x
end
return grade_hash
end
与函数调用的代码替换。
grade_hash = load_from_csv(pass_fail_file)
提取该方法是消除重复的第一步。
现在我们需要尝试使该功能适用于其他情况。在每个代码块中只有两样东西...
- 要创建新对象的类。
- 将哪个字段放入散列。
第一个很容易,你可以传入类名。这表明这可能是一种类方法。
第二个有点棘手。你可以传入一个函数来说明如何转换为散列。但是这些都是对象,利用。不要告诉该类如何从CSV中加载其对象,而是要求该类从CSV加载对象。这意味着绝对要使它成为一种分类方法。
要处理散列键的问题,请定义一种说明如何获取CSV散列键并使用该键的方法。
# In each class define how to get the key for the CSV
def csv_key
return mark.to_s
end
# In a mixin, put a generic way to load from a CSV
def self.load_from_csv(file)
from_csv = load_csv(file)
objs = from_csv.map{ |e| new(e) }
objs.each do |x|
hash[x.csv_key] = x
end
return hash
end
这一个方法可能做得太多,分成两部分。一个用于从CSV加载对象,另一个用于将对象数组转换为散列。
def self.load_from_csv(file)
return load_csv(file).map{ |e| self.new(e) }
end
def self.hash_from_objects(objs)
objs.each do |x|
hash[x.csv_key] = x
end
return hash
end
则...
grades = Grade.hash_from_objects(
Grade.load_from_csv(pass_fail_file)
)
students = Student.hash_from_objects(
Student.load_from_csv(student_file)
)
courses = Course.hash_from_objects(
Course.load_from_csv(course_catalog_file)
)
这是不是一个伟大的界面,但你可以看到它是如何从procedural programming搬走,你告诉对象做什么,并朝着对象界面,你问对象该怎么做。
下一步是要真正考虑从加载的对象中分离加载对象。
请注意,函数几乎不知道它正在加载的对象。这表明下一步将使一个Factory class从CSV加载对象,而不是将其作为对象接口本身的一部分。 CSV加载程序工厂对象会知道CSV文件和类。它将使用该类的csv_key
方法。
class CSVLoader
attr_reader :file, :class
def load
hash = {}
load_csv(@file).map{ |e| @class.new(e) }.each do |x|
hash[ x.csv_key ] = x
end
return hash
end
end
grades = CSVLoader.new(file: pass_fail_file, class: Grade).load
students = CSVLoader.new(file: student_file, class: Student).load
courses = CSVLoader.new(file: course_catalog_file, class: Course).load
这是一个很好的开始。
非常感谢,这非常有帮助。我可以看到你是如何一步一步完成的,并且你所链接的资源非常棒。我可以开始看到如何思考界面的应用。起初我很困惑加载行为是否应该被认定为一个类,因为我不认为我想要它的多个实例,但是你通过它的方式可以帮助我更多地了解如何应用'工厂类'模式,同样感谢你 – zqe