I'm learning ruby and also rails and when learning I came across a couple examples of people making their methods private and then creating another, public method, that does nothing but call the private one. Like this:
class Something
def initialize(param)
@param = param
end
def call
dosomething
end
private
def dosomething
# whatever
end
end
I'm bit confused on what exactly does this achieve?
CodePudding user response:
If public method is only used to call private this is indeed bad code style. But there plenty of situations, where such usage have rights to be used.
If your class is parent-class, children class can mutate public method, without disrupting private-method, that may be used elsewhere.
class Some < Something
def call
foo()
end
end
class Thing < Something
def call
foo()
super
end
end
Or you have not related Classes, that need to be called from one place, so they need to have same interface.
class Sometime
def call
foo()
end
end
class Something
def call
bar()
end
end
a = Sometime.new
b = Something.new
c = rand(2) == 1 ? a : b
c.call
CodePudding user response:
Public vs. Private Methods Generally Reduce Cascading Changes
This question might be a better fit on Software Engineering, but the most general use case is to keep the public interface of the class small and simple, hiding the internals of the implementation from callers and collaborator objects. Data hiding, separating public interfaces from internal implementation details, and drawing a distinction between public and private interfaces are basic principles of object-oriented programming.
This certainly matters more in languages that don't allow you to easily bypass protected and private method definitions, which is pretty trivial to do in Ruby with Object#send. Still, marking a method as private in Ruby at least communicates intent, and creates a demarcation between the public interface and any internals or data hiding that shouldn't be visible to, relied upon, or otherwise directly manipulated by collaborators.
As an admittedly contrived example, consider the following class that implements a public #calculate_value method and a private #calculate_value! method that is invoked by the public method.
class Foo
# Declare a public interface; the collaborator doesn't
# need to know how the value is calculated. If the way
# the calculation is performed changes, the inner
# details are not exposed in the public method so the
# caller shouldn't care as long as the result returned
# is what's needed or expected.
#
# @param x [Integer]
# @param y [Integer]
# @return [Integer] value calculated from _x_ and _y_
def calcuate_value x, y
calculate_value! x, y
end
private
# This method is private, so it doesn't need to expose
# how it works. The method could be modified, refactored,
# redesigned, or call 27 other methods to do its work,
# but those details should be a "don't care" when calling
# the public method #calculate_value.
#
# @param x [Integer]
# @param y [Integer]
# @return [Integer] a complex set of calculations using
# the _x_ and _y_ values passed to the public interface
def calculate_value! x, y
embiggen x, y
ensmallen x
triplicate y
[x, y, y].sum
end
end
In other words, #calculate_value is defined as part of the public interface for instances of the class, and should rarely change. Meanwhile, the implementation of the public method is really being handled by the private method #calculate_value! and declaring it private
means (pragmatically speaking) that programmers and collaborator objects should generally interact with the public method and leave the private method alone.
This allows the public interface to stay the same even if the private implementation changes. Whether or not changing the implementation should change the behavior of the class or the value of the calculation is the difference between refactoring (where the implementation changes but the behavior remains the same) and where changes to the behavior are desirable. In either case, the public interface remains the same, which generally reduces the need to change code in the caller every time some detail of the underlying implementation is modified.