
-----------------------------------
wtd
Mon Jul 11, 2005 5:41 pm

Reflections on OOP
-----------------------------------
What is object-oriented programming?  That's a terribly complex question, and one for which you will get no shortage of unique answers.

Perhaps rather we should ask: why use object-oriented techniques?

Some people use OOP because they've been told they have to to be cool, or because their boss tells them to use the "class" keyword or find a new job.

The good reason is something different.  Object-oriented programming offers us a pretty darn good way to think about programming, and one that's really fairly natural.

When you look around the world, you see things.  When you interact with things, you rarely know how they actually work, and even less frequently do you need to know.

For instance, let's look at creating a window and making it visible.

w = Window()
w.set_title("hello world")
w.show()

Notice how we never cared about the internal state of the window.  There was no changing of variables directly.  We told the window what do do, and it did it.

Of course, we can't be so nonchalant about such things when we decide to create our own classes of objects.  Then we have to worry about the internal state and the ways in which that state can be modified and accessed.

That said, the state that you use should be one of the last things you decide on.  First you should decide on how your object will look to the outside world.  In this case, we'll want to give the user the opportunity to construct the object itself using certain pieces of data.  A first and last name will suffice.

Then we want to give the user the ability to get the first and last name, but not modify them.  And lastly, we want the ability to get the full name as a single entity.

Now that we have that down, let's think about the state.  

We could store a single string, with the first and last name separated by a space.  Then when we want the first or last name, simply split the string internally on that space and return the relevant piece.  

But really, that's overly complex.  Instead, let's store the individual names as separate variables and only combine them when necessary.

In a number of programming languages:

class Name
   attr_reader :first, :last
 
   def initialize(first, last)
      @first, @last = first, last
   end

   def full_name
      "#{@first} #{@last}"
   end
end

class Name
{
   private:
      std::string first_name, last_name;
   public:
      Name(std::string f, std::string l)
      : first_name(f), last_name(l)
      { }

      std::string first() const
      {
         return first_name;
      }

      std::string last() const
      {
         return last_name;
      }

      std::string full_name() const
      {
         return first() + " " + last();
      }
};

class Name
{
   private String firstName, lastName;

   public Name(String f, String l)
   {
      firstName = f;
      lastName = l;
   }

   public String first()
   {
      return firstName;
   }

   public String last()
   {
      return lastName;
   }

   public String fullName()
   {
      return first() + " " + last();
   }
}

class Name
{
   private string firstName, lastName;

   public Name(string f, string l)
   {
      firstName = f;
      lastName = l;
   }

   public string First
   {
      get { return firstName; }
   }

   public string Last
   {
      get { return lastName; }
   }

   public string FullName
   {
      get { return this.First() + " " + this.Last(); }
   }
}

Now, let's look at the ease with which we can create Name objects, and get their various methods "for free".

bobs_name = Name.new("Bob", "Smith")
puts bobs_name.full_name

Name bobs_name("Bob", "Smith");
std::cout 