Encapsulation is the ability for an object to have attributes and methods exposed either publicly, to other objects of the same class, or kept private to itself. A more technical definition would define it as: “the ability of objects to hide their constituent data behind an abstracted interface.”
When you are designing a class the idea is to make as few methods available from your class as possible. You do this is for greater flexibility to later change the way things work inside your class with less risk of upsetting external users of the object in question. So keep a lot of functionality inside your class, but only offer a few ways the outside world can manipulate your object’s data.
Public vs Private
By default all methods in a class are public, unless you use a keyword to declare them otherwise. The keywords can be public, private or protected (explained later). Any methods following the keyword fall under that form of encapsulation.
class Employee
def initialize(name)
set_name(name)
end
def name
"#{@first_name} #{@last_name}"
end
private
def set_name(name)
first_name, last_name = name.split(/\s+/)
set_first_name(first_name)
set_last_name(last_name)
end
def set_first_name(name)
@first_name = name
end
def set_last_name(name)
@last_name = name
end
end
In the above class you can initialize Employee by providing a name and you can retrieve the name. You cannot however directly access the setters for the names themselves. This is a very simple example, and perhaps not the best, but you hopefully get the idea.
For example you can call name:
emp = Employee.new("Nick Cancelliere")
puts emp.name
=> Nick Cancelliere
You cannot however call set_first_name:
emp = Employee.new("Nick Cancelliere")
puts emp.set_first_name("William")
=> NoMethodError: private method ‘set_first_name’ called for
#<Employee:0x1d18c @first_name="Nick", @last_name="Cancelliere">
Protected
There is a third type of encapsulation that uses the keyword protected. Protected works similar to private, but rather than being only accessible to the object itself, it’s accessible to any member of the object’s class. Below is an example method, imagine it inside our Employee class calling on attribute bonus_rate :
def bonus_rate_difference_with(other_employee)
(self.bonus_rate - other_employee.bonus_rate)
end
If this method were private it would fail. You wouldn’t be able to access the bonus_rate attribute of the other employee. However, if you had it protected, since both objects belong to the Employee class you would be able to run this method.
Another Way in Ruby
Ruby has another way to express encapsulation. Instead of using keywords preceding the methods, you can declare them using the method name’s symbol along side the keyword.
private :set_name, :set_first_name, :set_last_name
protected :bonus_rate_difference_with