Posts Tagged ‘oo design’

Polymorphism Explained

March 1st, 2009

Polymorphism is the idea in oo programming that code can work with multiple types of objects and classes at once.  One of the easiest examples to think about this is the .to_s (to String) method.  This method is available on a variety of classes including Array, Date, Fixnum, etc.  Below is an elementary example of polymorphism (using a method called color):

class Fruit
  attr_accessor :price

  def initialize(name)
    @price = price.to_f
  end
end

class Apple < Fruit
  def color
    "red"
  end
end

class Pear < Fruit
  def color
    "yellow"
  end
end

class Orange < Fruit
  def color
    "orange"
  end
end

fruits = [Apple.new("1.29"), Pear.new("1.30"), Orange.new("1.48")]
fruits.each { |fruit| puts fruit.color }
=>
red
yellow
orange

Encapsulation Explained

February 28th, 2009

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