Should a ruby method modify a class's instance method?
I am writing a class in Ruby where I have instance variables (i.e. @person_summary_info
, @name
, @dob
, @favorite_food
) for the class.
To parse a piece of text, I have a public method that I call from outside the class (let's call it interpret
).
This method calls some private class methods such as get_name
that use @person_summary_info
to extract the respective piece of information (in this case, the name of the person). Should those private methods:
a) use the instance @person_summary_info, or get that information through 开发者_JS百科a parameter passed to them (i.e. get_name
vs get_name(person_summary_info)
)
b) modify the instance variable directly and return nothing, or modify nothing outside the scope of the function, and return the result (i.e. inside get_name
, set @name = 'John'
, or return 'John'
)?
What is the best practice here? Thanks!
I have included my best representation of your question in code at the bottom of my answer, but I'd like to present my solution as I understand your dilemma first...
Do this if your name
attribute is meant to be publicly accessible:
class Person
attr_accessor :name
def initialize(name)
@name = name
end
def interpret(text_to_parse)
# I have no idea what you are parsing in real life
self.name = text_to_parse.split.last
end
end
person = Person.new("Frederick")
puts person.name
# => "Frederick"
person.interpret("Please, call me Fred")
puts person.name
# => "Fred"
Do this if your name
attribute should not be (easily) publicly accessible: (For what it's worth, pretty much anything can be accessed one way or another in Ruby. One of the many things that make it awesome!)
class Person
def initialize(name)
@name = name
end
def interpret(text_to_parse)
# I have no idea what you are parsing in real life
@name = text_to_parse.split.last
end
end
person = Person.new("Frederick")
puts person.instance_variable_get("@name")
# => "Frederick"
person.interpret("Please, call me Fred")
puts person.instance_variable_get("@name")
# => "Fred"
And, as mentioned above, here's my best translation of your question into code:
class Person
def initialize
@person_summary_info = { name: "foo" }
@name = "bar"
@dob = "baz"
@favorite_food = "beer"
end
def interpret(text_to_parse)
# Some kind of parsing?
get_name_1
# OR
get_name_2(@person_summary_info)
# OR
get_name_3
# OR
@name = get_name_4
end
private
def get_name_1
@person_summary_info[:name]
end
def get_name_2(person_summary_info)
person_summary_info[:name]
end
def get_name_3
@name = 'John'
end
def get_name_4
'John'
end
end
Hopefully, you can see why there's some confusion in the comments about what you are asking exactly. If nothing else, maybe seeing this will help you to form your question more clearly so we can help!
Finally, you should avoid writing your own getters/setters in Ruby unless you need to hook in some custom code to the getting/setting processes -- use the class-level attr_reader
/attr_writer
/attr_accessor
macros to create them for you.
If interpret() is not meant to change the state of a particular instance of Person, then consider naming the method something like get_name_from_string(string) and possibly making it static, since it doesnt do anything to the state of the instance.
If you want interpret() to change the state of a particular instance of Person, then consider changing the name of the method, prefixing it with set and include the attribute name being set (set_name_from_string()). If several attributes are being set, then perhaps set_from_string() and include a code comment stating what instance variables are being modified. Internally the method could call get/set_name() as described below.
Typically, getter/setter methods are public and should be quite simple, doing what their name suggests: - getName() returns the instance variable @name - setName(name) sets or overwrites the instance variable @name with the value passed in and returns nothing
In Java, this is a type of POJO, specifically Java Beans (excluding the part about needing to be serializable) Its very common programming practice in several different languages to have public setter/getter methods for the instance variables and to also have a default constructor (one that takes no arguments) and another constructor allowing you to set the instance variables upon instantiation of the Object.
using @instance directly from another class is a good way how to get into troubles. Each class should have it's own variables and anything you would like to process or return back should be assigned/returned directly.. that means that way
@instance = my_class.get_name(person_summary_info)
and not
my_class.get_name
Just try to imagine how to test that code using @instance variables and chance to reuse that piece of code..
just my 2c
精彩评论