Open Closed Principle in Action


Ivar Jacobson stated that all software entities change during their life cycle and this must be borne in mind when developing systems which are expected to last longer than the first version. A design principle which helps you with long lasting software is OCP (Open Closed Principle).

Open Closed Principle was coined by Bertrand Meyer. It states that “Software entities should be open for extension but closed for modification”.

When a single change to a program causes a cascade of changes to dependent modules  this is what we call as code smell or bad software design. The Open closed principle attacks this in a straight forward way. It states that you should design modules that should never change. However, when requirements change, our first reaction is to add or modify code. Right?

This seems odd because new application requirements warrants code changes in modules. It seems bizarre how these seemingly opposite attributes can be made to work together.

Figure 1 shows a simple design that does not confirm to “open closed principle”. Both Client and server classes are concrete. The client class uses the server class. If tomorrow, there is a need for the client class to use a different server class then the Client class must be changed to use the new Server class. This smells of tight coupling.

Figure 1

Figure 2 on the other hand shows us the corresponding design that conforms to the open closed principle. In this case AbstractServer is an abstract class and the client uses this abstraction. Now the Client class will use derived classes of the AbstractServer class. If we really want Client to use a different Server class, then a new derivative of the AbstractServer class can be created. The Client remains unchanged.

Figure 2

Recently while pairing we found a piece of code violating the open closed principle. The Class in question was CEPJMSBridgeImpl. It’s behavior was to retrieve JMS message from the Queue and generate different type of Complex Processing Events for the Application.

We found that we used to generate two events like news event and score event based on the message retrieved from the Jms Queue. We also had an ugly If construct to generate different events based on the message.

Now, as the application was growing, it was required to generate a third kind of event, then a fourth and then a fifth. It meant that everytime, we will have to add another check in the if construct to make it work. We immediately realised that this piece of code is a perfect place to apply open closed principle. Let’s look at the code listing.

public class CEPJMSBridgeImpl implements CEPJMSBridge {
	......
	private CompanyInputEvent generateEventFromMessage(TextMessage textMessage) {
		CompanyInputEvent event = null;

		StringTokenizer tokenizer = new StringTokenizer(textMessage.getText(), ",");
		String messageType = tokenizer.nextToken();

		if(messageType.equals(CEPConstants.NEWS_MESSAGE_TYPE)) {
			event = new CompanyNewsInputEvent(Long.valueOf(tokenizer.nextToken()), NewsElementType.valueOf(tokenizer.nextToken()), tokenizer.nextToken());
		}
		if(messageType.equals(CEPConstants.SCORE_MESSAGE_TYPE)) {
			event = new CompanyScoreInputEvent(Long.valueOf(tokenizer.nextToken()), ScoreElementType.valueOf(tokenizer.nextToken()), Double.valueOf(tokenizer.nextToken()));
		}
if(messageType.equals(CEPConstants.FooOne)) {
			event = new FooOneEvent(Long.valueOf(tokenizer.nextToken()), ScoreElementType.valueOf(tokenizer.nextToken()), Double.valueOf(tokenizer.nextToken()));
		}
...
...

		return event;
	}

	......
}

We decided to apply open closed principle by using abstractions.

Our solution was to create a hierarchy of event generators and pass that as a collection to the CEPJmsBridgeImpl. Each event generator would be responsible to generate an event if the passed message is valid for the generator.

As you would decipher from the code and the class diagram above, the CEPJmsBridgeImpl class will contain a List of EventGenerators. If you look closely, you would be able to map the combination of EventGenerator Interface and the BaseEventGenerator abstract class to the AbstractServerClass in Figure 2. The generateMessage method will loop through the EventGenerators to generate the required event. The behavior of EventGenerator is then to decide whether it can generate the event based on Jms message.

The net effect being that CEPBridgeImpl class will remain unchanged even if we add more events to the application. The problem got reduced to define a Collection of Event generators in CEPBridgeImpl class and provide the list of generators using Spring context file. Here is the Listing

<beans>
<bean id="cepJMSBridge" class="com.inphina.cep.CEPJMSBridgeImpl">
		<property name="eventGenerators">
			<list>
				<ref bean="newsEventGenerator" />
				<ref bean="scoreEventGenerator" />
			</list>
		</property>
	</bean>

	<bean id="newsEventGenerator" class="com.inphina.cep.NewsEventGenerator" />
	<bean id="scoreEventGenerator" class="com.inphina.cep.ScoreEventGenerator" />

</beans>

And now the class CEPBridgeImpl looks like this after the discussed changes

public class CEPJMSBridgeImpl implements CEPJMSBridge {
	@Resource
	private Collection<EventGenerator> eventGenerators;

	......

	private CompanyInputEvent generateEventFromMessage(TextMessage textMessage) {
		for (EventGenerator eventGenerator : eventGenerators) {
			event = eventGenerator.generateEventFromMessage(textMessage);
		}
		return event;

	......
}

Its all done! After application of open closed principle we can see the benefits.

Our CEPJMSBridgeImpl does not require to change even if we have to generate more events. Therefore it is closed for modification. Adding more events is then reduced to adding more event generators. The BaseEventGenerator abstract class is now open to abstraction and we can continue to add more derived concrete classes to handle new events.

Advertisements
This entry was posted in Architecture, Java and tagged , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s