Moving Toward Object-Oriented
Programming and Patterns

Joseph Bergin
Pace University
jbergin@pace.edu

This paper will help you see the nature of object-oriented programming by example. We will start with a simple example and develop a simple solution that is not object oriented and then move it toward one that is, and that uses some simple design patterns as well. The purpose is to both see the difference in styles and to see the advantages of object-orientation. We will use Java for our language of expression.

The problem is to model a Person, who can be either male or female. The assumption here is that in certain circumstances a male person will BEHAVE differently from a female person. We will attempt to avoid sexist assumptions here and state up front that this assumption may be entirely false. This set of assumptions is just an illustration of the main idea that you have more than one kind of thing. These things are similar, but not exactly the same. They differ in their behavior. So, for purposes of the illustration, we assume that men and women eat differently and they talk differently.

A First Procedural Program

We will define our different behaviors for males and females using a Java interface. We need a method eat and another talk. This interface will also define two constants that we can use to specify a male person and a female person. For this purpose we just "overload" the meaning of the built in primitive type boolean, with true a value representing male and false representing female.

public interface Gender
{	public void eat();
	public void talk();
	public String sex();

	public static final boolean MALE = true;
	public static final boolean FEMALE = !MALE;
}	

Any class that implements this interface must implement the two methods and will have access to the two constants. Here is a class that does this. We can then create objects of type person by giving a name and the appropriate value to determine whether the new object is a male or a female. The new object remembers both and can later do tests to determine which it is. This is shown in the implementations of the eat and talk methods. Since this is just an illustration we will only print out messages for the various actions, but in general these actions could be arbitrarily complex.

class Person implements Gender
{	private boolean isMale; // true means male, false means female.
	private String name;
	
	public Person (String name, boolean genderFlag) 
	{   isMale = genderFlag;
		this.name = name;
	}

	public String sex () 
	{   return isMale? "male": "female";
	}
	
	public String toString ()
	{ return "This is " + name + " and I'm a " + sex();
	}
	
	public void eat()
	{	if(isMale)
		{	System.out.println("Eatin' like a boy.");
		}
		else
		{	System.out.println("Eating like a girl.");
		}
	}
	
	public void talk()
	{	if(isMale)
		{	System.out.println("Talkin' like a boy.");
		}
		else
		{	System.out.println("Talking like a girl.");
		}
	}
	

The above will work for the narrow purpose described in the problem statement as shown in the test code below. We have put this test code into the above class.

	public static void main(final String [] args)
	{	Person Bill = new Person("Bill", Gender.MALE);
		Person Monica = new Person("Monica", Gender.FEMALE);
		System.out.println(Bill);
		Bill.talk();
		Bill.eat();
		System.out.println(Monica);
		Monica.talk();
		Monica.eat();
	}
}

However, there are two aspects of this code that stand out. First is that it is very unnatural. A real person doesn't test to see whether he or she is male or female before eating or talking. If the assumption were true, we would just do what we do according to our gender without thinking about it and especially without a test. Second is what will happen when we try to use the objects of this class for things not envisaged by the designers. Suppose, for example that we decide that males and females like different kinds of music and when asked to choose a concert to attend will choose differently. If this seems to be important functionality we can include it in the interface and in the class in the same way that we have included eat and talk. However, one likes to leave tested code alone so we might like to implement this functionality outside the class. This would be especially true if we didn't consider music preference "fundamental" and just needed this distinction to be made at one place in a program that otherwise used the built-in functionality of the existing classes.

The code, outside the class, could not use the private variable isMale, so would need to depend on public methods. We could write something like this.

if(Bill.sex().equals("male"))
{	System.out.println("Going to see Bob Dylan.");
}
else
{	System.out.println("Going to see Mick Jagger.");
}

Again, this would work, but requires explicit testing of the gender of the object before we can be sure of "doing the right thing." This explicit testing to determine what to do is called ad-hoc polymorphism and object-oriented languages are designed to avoid it. That is why we called this a procedural solution even though we clearly have objects and even send them messages like eat and talk.

If we need to do different things for males and females elsewhere in the program we will need to repeat this structure each time*.

A First Object-Oriented Program

Now we show a more object-oriented program to do the same thing. We again define Gender using an interface, but this time we don't need the constants. We will define two classes, each implementing this interface, one for male persons and one for female. Each of these classes and interfaces should appear in its own file, of course.

public interface Gender
{	public void eat();
	public void talk();
	public String sex();
}	

class Male implements Gender
{	public Male (String name) 
	{   this.name = name;
	}

	public String sex () 
	{   return "male";
	}
	
	public String toString ()
	{ return "This is " + name + " and I'm a male" ;
	}
	
	public void eat()
	{	System.out.println("Eatin' like a boy.");
	}
	
	public void talk()
	{	System.out.println("Talkin' like a boy.");
	}

	private String name;
}

class Female implements Gender
{	public Female (String name) 
	{   this.name = name;
	}

	public String sex () 
	{   return "female";
	}
	
	public String toString ()
	{ return "This is " + name + " and I'm a female";
	}
	
	public void eat()
	{	System.out.println("Eating like a girl.");
	}
	
	public void talk()
	{	System.out.println("Talking like a girl.");
	}

	private String name;
}

The above code is much more natural. The objects in these classes don't have to query themselves about whether they are male or female, they just ARE male or female and BEHAVE accordingly. We can provide a similar test of the code as follows.

class main
{	public static void main(final String [] args)
	{	Gender Bill = new Male("Bill");
		Gender Monica = new Female("Monica");
		System.out.println(Bill);
		Bill.talk();
		Bill.eat();
		System.out.println(Monica);
		Monica.talk();
		Monica.eat();
	}
}

We have been able to achiever a better form of polymorphism (behaving differently) because we don't need to test which action to take. Each object just does what it was designed to do and different objects were designed differently, so they behave differently, even thought they implement the same interface. This is called dynamic polymorphism.

However, we still don't have a very good solution, or even a very object-oriented solution. If we need new functionality that is different for males and females we are again faced with the choice of modifying the existing structure or building the new functionality outside what exists. If we choose the former method we will again take advantage of dynamic polymorphism, but at the cost of modifying existing code. There are a number of reasons for not modifying existing code, chief among which is the possibility of introducing errors into tested code used by clients.

However, if we choose to do this outside the existing interface and classes we will again be forced to use either inheritance or ad-hoc polymorphism as before. If we chose inheritance, we will be building subclasses of the Gender classes and so will have classes like ConcertGoingMale and ConcertGoingFemale. If there were a lot of these and they needed to be combined we would find ourselves with a combinatorial explosion of classes. Again, this is not desirable.

If we choose to leave the classes as they are and just implement the new functionality outside the abstraction boundary we will need to say (exactly as before):

if(Bill.sex().equals("male"))
{	System.out.println("Going to see Bob Dylan.");
}
else
{	System.out.println("Going to see Mick Jagger.");
}

Which again uses ad-hoc polymorphism.

Before we solve this problem and permit dynamic polymorphism to be used outside the class as well as in, we are going to take a side trip.

More Flexibility--The State Pattern

Suppose that we have been using one or the other of the above programs for a while. One of the constants in the software world is that problems change and the programs we use to solve them must change also. Suppose that we learn from the people we have built the program for (the customer) that we must now permit a person to change his or her gender. In other words, we need to permit a sexChange to be performed, after which a person BEHAVES according to the new gender.

Note that this is very easy to do in the first program. We just have the sexChange method set the private isMale field to be its opposite:

public void sexChange(){isMale = ! isMale;}

While we liked the second solution much better for permitting more dynamic polymorphism, this is a development that we cannot implement easily there. The problem is that male and female are associated with the class of the object itself and an object can't change its class. But, we can make an object appear to change its class, because it changes its behavior and class defines behavior. We do this using a design pattern called State. The key to the State pattern is to delegate the behavior to another object that represents the apparent class of the object whose class seems to change. This will permit us the advantages of both the above solutions. We will be able to change the behavior of an existing object easily and we will avoid ad-hoc polymorphism within the class.

We are also going to use another advanced technique, sometimes called typed enumerations. In the first program we just used booleans to determine the gender of a person. That is dangerous if we have lots of other booleans in the program. It is especially dangerous if we are building large programs and write methods that have more than one boolean argument. It becomes very easy to forget whether the first or the second is the "gender" flag and get the program wrong. For example, if our Person objects also needed to be tagged based on whether they were "employed", and we use booleans for both gender and employment status in the constructor then we might forget which order we used when we defined the parameters and get it backwards. These kind of errors are difficult to find. If we use a new type for each, then the compiler won't let us get them reversed. This is even more important for ints than for booleans, since ints are used for many things and so the likelihood is high that if we use ints then we will have many int parameters and may then easily confuse them. See Elliotte Harold's article on Overloading Int Considered Harmful for more on this topic.

Here we define an interface as before and constants like we did in the first program, but the constant values won't be booleans but objects. There are two advantages to this. First, as mentioned in the previous paragraph, these objects have distinct types, so the compiler won't confuse them with booleans used for other purposes, or with other types. The more important reason, however, is that these objects can have their own behavior. In particular they can implement the male and female eat and talk behavior. The classes of these objects will be defined within the interface itself, as inner classes. We will make them static and final since we only need one object of each kind and want to prohibit subclasses, which might change the behavior. Additionally, we want these two classes to help us with the gender change problem, so we extend the Gender interface with another interface (defined inside the Gender interface itself) called Changeable. From outside the Gender interface the inner one is known as Gender.Changeable. The inner classes for male and female are known as Gender.Male and Gender.Female. We could, of course, simply have added the new method to the Gender class and avoided the Changeable interface altogether. We did it this way to show that changing an existing structure isn't necessary to achieve radically new functionality. If this is not necessary or desirable, by all means, just use a richer Gender interface.

Note that there is no ad-hoc polymorphism in these classes. A male talks and eats like a male. Note that we have two "prototype" objects, one for male and one for female, called MALE and FEMALE. Again, outside this interface their full names are Gender.MALE and Gender.FEMALE.

The classes here are very much like our Male and Female classes of the second program. However, these classes don't define Person. Instead, a Person object will delegate its gender behavior to one of these objects.

public interface Gender 
{	public void eat();
	public void talk();
	public String sex();
	
	// Typed enumeration. 
	public static final Gender.Changeable MALE = new Male();  
	public static final Gender.Changeable FEMALE = new Female(); 
	
	public interface Changeable extends Gender, java.io.Serializable
	{	public Changeable swap();
	}

	final static class Male implements Changeable, java.io.Serializable
	{	public String toString(){return "male";}
		private Male(){}
		public void eat(){System.out.println("Eatin' like a boy.");}
		public void talk(){System.out.println("Talkin' like a boy.");}
		public Changeable swap(){return FEMALE;}
		public String sex(){return "male";}
		public boolean equals(Object o){return o instanceof Male;}
		public int hashCode(){return 999;}
	}
      
	final static class Female implements Changeable, java.io.Serializable
	{	public String toString(){return "female";}
		private Female(){}
		public void eat(){System.out.println("Eating like a girl.");}
		public void talk(){System.out.println("Talking like a girl.");}
		public Changeable swap(){return MALE;}
		public String sex(){return "female";}
		public boolean equals(Object o){return o instanceof Female;}
		public int hashCode(){return 979;}
	}	
}

Next we define the Person class to take advantage of the above. Again, a Person implements the Gender interface, and, like our first program, it has a variable to determine its Gender. The difference here, however, is that this Gender (Gender.Changeable) object has behavior, unlike a simple boolean variable. The key to the State pattern is that we can delegate the gender behavior to this other object. So when we ask a Person to talk, it just passes the message to its Gender.Changeable object, which talks according to its own defined behavior, either Male behavior or Female behavior.

class Person implements Gender, java.io.Serializable
{	Person (String name, Gender.Changeable sex)
	{	this.name = name;
		this.sex = sex;
	}
	public String toString ()
	{ return "This is " + name + " and I'm a " + sex;
	}
	public String sex(){return sex.sex();}
	public void talk(){sex.talk();}
	public void eat(){sex.eat();}
	public void sexChange(){sex = sex.swap(); }
	String name;
	Gender.Changeable sex;
}

But, since we use a variable to determine the gender, we can change it, so a sexChange operation is easy to perform. Notice again that there is NO ad-hoc polymorphism here anywhere. We again provide test code, including a test of the sexChange operation.

class main
{	public static void main(final String [] args)
	{	Person Bill = new Person("Bill", Gender.MALE);
		Person Monica = new Person("Monica", Gender.FEMALE);
		System.out.println(Bill);
		Bill.talk();
		Bill.eat();
		System.out.println(Monica);
		Monica.talk();
		Monica.eat();
		Monica.sexChange();
		System.out.println(Monica);
		Monica.talk();
		Monica.eat();
	}
}

The conclusion here is that the state pattern, deferring behavior to another object, can solve the problem of having an object change its apparent class.

However, we haven't attacked the problem of avoiding ad-hoc polymorphism outside the class. We do that next.

Final Solution--The Strategy Pattern

Here we will simply add to the above solution. The problem we address is fundamental. When you design a class it is usually unlikely that you will foresee all of its possible uses. The more flexible you can make it, the more useful it will be to others later. Ideally we would like to build a class so that it can be used in unforeseen ways without changing it in any way. In effect we would like to be able to add behavior that is defined by a user without changing the code of the class.

The essence of the strategy pattern is to allow the selection of an algorithm at runtime, rather than when the program is compiled. Normally, a strategy provides an action for only one class. Our use here is somewhat extended as we will provide a strategy for both the male and female objects since we want the actions coordinated. As such, this is not the simplest application of this pattern. Better (simpler) examples appear in the paper: http://csis.pace.edu/~bergin/patterns/strategydecorator.html

To do this requires that we be able to pass the behavior in and have it performed, rather than building it in initially. Therefore we must build in a way that we can accept new behaviors. We will first define what we mean by a strategy using a new interface. The Strategy interface defines different behaviors for male and female objects. A given object will only ever execute one of these, since it only has one gender at a time. The two actions defined each take a Person object as a parameter so that the action will have access to the information about the particular person on whose behalf it is acting, such as the name. We also pass in another object whose use is not determined by the conventions here, but can be used to package up arbitrary information and provide it as extra data to be used in performing the action. This interface is called the Strategy interface and will permit arbitrary actions to be defined outside the Person class as we shall see.

interface Strategy
{	public void maleAct(Person obj, Object helper);
	public void femaleAct(Person obj, Object helper);
}

Our Gender interface is modified by adding a new member to the inner Changeable interface. This new action permits an object implementing the interface to accept a strategy and execute it. The accept member has as additional parameters, the Person and Object that will be passed to the methods of the Strategy object later. Getting confused? It is getting a bit sticky and requires a bit of concentration. We will next see how this is used, which should make it a bit clearer.

public interface Gender 
{	public void eat();
	public void talk();
	public String sex();
	
	public static final Gender.Changeable MALE = new Male(); 
	public static final Gender.Changeable FEMALE = new Female(); 
	
	public interface Changeable extends Gender, java.io.Serializable
	{	public Changeable swap();
		public void execute(Strategy act, Person p, Object o);
	}

Since the inner classes implement this interface, they must also implement the new accept member. The Male object will execute the maleAct only and the Female object will execute only the femaleAct. This is where the polymorphism comes in. Note that we don't need to test to achieve it, so this is dynamic polymorphism also.

	final static class Male implements Changeable, java.io.Serializable
	{	public String toString(){return "male";}
		private Male(){}
		public void eat(){System.out.println("Eatin' like a boy.");}
		public void talk(){System.out.println("Talkin' like a boy.");}
		public Changeable swap(){return FEMALE;}
		public String sex(){return "male";}
		public void execute(Strategy perform, Person p, Object o){perform.maleAct(p, o);}
		public boolean equals(Object o){return o instanceof Male;}
		public int hashCode(){return 999;}
	}
      
	final static class Female implements Changeable, java.io.Serializable
	{	public String toString(){return "female";}
		private Female(){}
		public void eat(){System.out.println("Eating like a girl.");}
		public void talk(){System.out.println("Talking like a girl.");}
		public Changeable swap(){return MALE;}
		public String sex(){return "female";}
		public void execute(Strategy perform, Person p, Object o){perform.femaleAct(p, o);}
		public boolean equals(Object o){return o instanceof Female;}
		public int hashCode(){return 979;}
	}	
}

We are now in a position to define the Person class. Again, we give it an execute method so that it can accept a Strategy. It doesn't need to have the same interface as the ones above, since Person doesn't implement the Gender.Changeable interface, only the Gender interface. We give it the same name, however, since it has the same purpose. Again we delegate the execute message to the sex object defining the gender. We pass in this as the extra argument so that the action method will know which object it is acting for.

class Person implements Gender, java.io.Serializable
{	Person (String name, Gender.Changeable sex)
	{	this.name = name;
		this.sex = sex;
	}
	public String toString ()
	{ return "This is " + name + " and I'm a " + sex;
	}
	
	public void talk(){sex.talk();}
	public void eat(){sex.eat();}
	public void sexChange(){sex = sex.swap(); }
	public String sex(){return sex.sex();}
	public void execute(Strategy perform, Object o)
	{	sex.execute(perform, this, o);
	}
	String name;
	Gender.Changeable sex;
}

Now we can test the above. To test the new functionality requires that we define a new class implementing the Strategy interface and define the male and female actions in this class. Notice that we are adding functionality without changing the Person class or the interfaces or classes on which it depends AND we are avoiding ad-hoc polymorphism.

In this example, we don't need any additional information for our strategy, so we just pass null. Note that the programmer needs to know what actual kind of information is required, or that none is, as is the case here.

class main
{	public static void main(final String [] args)
	{	
		class ConcertGoing implements Strategy
		{	public void maleAct(Person p, Object o){System.out.println("Going to see Bob Dylan.");}
			public void femaleAct(Person p, Object o){System.out.println("Going to see Mick Jagger.");}
		}
		
		Person Bill = new Person("Bill", Gender.MALE);
		Person Monica = new Person("Monica", Gender.FEMALE);
		System.out.println(Bill);
		Bill.talk();
		Bill.eat();
		System.out.println(Monica);
		Monica.talk();
		Monica.eat();
		Monica.execute(new ConcertGoing(), null);
		Monica.sexChange();
		System.out.println(Monica);
		Monica.talk();
		Monica.eat();
		Monica.execute(new ConcertGoing(), null);
	}
}

The overall conclusion we hope you draw from all of this, is that ad-hoc polymorphism can be avoided. The reason for doing so is discussed elsewhere, but generally, it makes our programs more maintainable. There are various, sometimes simple, design patterns that help us achieve this.

While the example we have chosen is somewhat frivolous, the problem it describes appears frequently in programming.

Notes

This code was inspired by notes from Dung Nguyen of Rice University and from Duane Buck of Otterbein. Jaime Nino of the University of New Orleans suggested some clarification, which I have tried to make. Eugene Wallingford of the University of Northern Iowa suggests that it might be better to label the pattern used for the Gender implementations Role Object rather than State. However, I've used it here to change the apparent class of a person, rather to add a role. Role Object is intended to let you add lots of roles, but probably not both Male and Female to the same person. This page arose out of discussions carried on in the Object Technology in Computer Science Education list serve.

State and Strategy are discussed in Design Patterns by Gamma, Helm, Johnson, and Vlissides (Addison-Wesley, 1995). This is the now famous "Gang of Four" or GOF book. There is some question whether State and Strategy are one pattern or two, however. One of the views of Patterns (that held by C. Alexander who invented the idea) is that Patterns are geometric. This is not widely understood in the software patterns community (not even thoroughly understood by myself, admittedly). The State and Strategy pattern have identical structure (geometry), as shown in the GOF book. This might imply that they are one pattern and not two.

While object oriented programmers try to avoid ad-hoc polymorphism it isn't always possible. The hard-to-impossible cases are when dealing with primitive (non-object) data in hybrid languages like Java, parsing input, and when creating new objects. The creational problem can be solved in general through the use of reflection (or the Factory Pattern), such as the Java Reflection API. The other situations are less tractable.

We have made the Person objects Serializable to permit them to be written to ObjectStreams. To make this possible requires that we make all of their parts Serializable as well. However, when we do this for the Gender.Changeable objects in the last two programs we can no longer guarantee the uniqueness of the objects even though we have made only private constructors. While the usual case is to write out serializable objects in one running of a program and read them in in another program or at least another run, nothing requires this. So, a program could serialize some Person object, which would serialize its fields, and then deserialize the lot, giving copies of the fields. We guarantee that the copies will be considered "equals" to the originals by the definitions of our equals and hashCode methods here. In effect, every Gender.Male object is equal to every other and similarly for Gender.Female objects. We haven't taken the same care about equals for Person objects, however, and so the copies would be considered different Persons.

If you are a professor, you are wondering (I hope) how you should use this in your teaching. If I were teaching a first course in computer science, I wouldn't show the first program at all, as it isn't object oriented and might reinforce a style I wouldn't want students using. I'd start with the second. The third program is probably too advanced as is the idea of an object changing its apparent class. However, the strategy is a really good idea and is not too difficult in itself, so I'd be likely to show something like the last program, but simplified so that it emphasized only the strategy part. There are other examples that make the strategy pattern more accessible, actually. For example, a linked list with a strategy interface is a pretty rich source of exercises for students. In such a case, the strategy is usually a somewhat richer pattern called a Visitor. Certainly, when you create a container like a linked list, you can't anticipate all the algorithms that a user might want to apply to it. In fact the form of strategy we used here is very much like a visitor. Visitor is also discussed in GOF.

For more on ad-hoc polymorphism, see Bergin's Selection Patterns.
For more on dynamic polymorphism, see Bergin's Polymorphism Patterns.
For more on how the object oriented programmer thinks, see Bergin's Object Patterns.


Note: For a discussion on why replicated code, such as that in the if structure testing for males and females, is bad see Kent Beck's discussion on OnceAndOnlyOnce on the Wiki Wiki Web.

 

Last Updated: July 18, 2010