1 Tojakora

Case Study Design Patterns Java

The majority of developers have already heard about design patterns, GOF(Gang Of Four) patterns are the most popularized, and each developer has his way to learn them , we can enumerate:

  • Reading a book or a magazine.
  • From web sites.
  • From a collegue.
  • Doing a training.


Regardless of the method chosen, we can learn by heart the patterns and spent hours to memorize their UML diagrams, but sometimes when we need to use them in a real project, it becomes more problematic.

What’s very important is not to know exactly pattern names and how to implement them as described in the documentation, but what’s more relevant is the motivations behind each pattern, because it’s from motivations that we invent the patterns.

And to master better pattern motivations, the interesting way is to study them from a real project. It’s the goal of this article; we will try to discover an open source project using them heavily.

In his this first part the goal is to discover the creational patterns used by JBoss.

Analysis of JBoss

JBoss Application Server (JBoss AS, or simply JBoss) is an application server that implements the Java Platform, Enterprise Edition (Java EE).

JBoss is a big project with many modules, packages and classes, and to go deep inside its internal design we need a tool to facilitate the analysis, for this purpose we used JArchitect to analyze it, and CQLinq will help us to query code base.

After the analysis here’s a dependency graph of some JBoss modules

Here we go to discover creational patterns used by JBoss:

Singleton

The singleton is the most popular and the most used one. There are many variant of this pattern, let’s search with CQLinq the most documented one which has the following characteristics:
– Not an abstract type.
– Having a private constructor.
– Having an unique static field with the same type as the parent class.


from t in Application.Types
where !t.IsAbstract && t.IsClass

// All ctors of a singleton are private
where t.Constructors.Where(ctor => !ctor.IsPrivate).Count() == 0

// A singleton contains one static field of its parent type, to reference the unique instance
let staticFieldInstances = t.StaticFields.WithFieldType(t)
where staticFieldInstances.Count() == 1
select new { t, staticFieldInstance = staticFieldInstances.First() }

And here’s the result of the query

Motivation

The motivation of the singleton pattern is very simple: “Create one class instance“.
However using this pattern became controversial, and not all architects and designers recommend it, here’s an article talking about the singleton controversy.

Factory Method

There is no mystery about factories, their goal is very clear: Create instances, and a simple factory containing a CreateInstance method could achieve this goal, however JBoss use mainly “Factory Method” pattern for all its factories.

Here’s all factories used by JBoss:

Motivation

To understand better this pattern let’s describe a scenario where JBoss use this pattern:

JBoss define a ScopedClassPoolFactory interface which is implemented by many concrete factory classes

The ScopedClassPoolRepositoryImpl need a factory to create ScopedClassPool instances, for that it’s assigned with setClassPoolFactory method.

And after the selected factory is used to create the concrete ScopedClassPool.

The most important motivation is the low coupling, indeed ScopedClassPoolRepositoryImpl need to instantiate ScopedClassPool, and it reference only this one and doesn’t know anything about concrete classes. And if ScopedClassPoolRepositoryImpl need to works with another concrete class implementing ScopedClassPool, we have just to add another factory implementing ScopedClassPoolFactory.

Using a simple factory is interesting to isolate the instantiation logic, but using “Factory Method” is more suitable to enforce low coupling.

Builder

The Builder pattern permits to create an object in a step-by-step fashion. The construction process can create different object representations and provides a high level of control over the assembly of the objects.

Motivation

JBoss need to create metadata for beans, the metadata could contain many sections, and each bean could include only some of them.

The BeanMetaDataBuilder contains many methods to add sections in the metadata:

And we can construct a metadata by invoking these methods to add needed sections

Using builder brings more flexibility when creating complex objects. This pattern is used when we need to assemble an object using multiple parts.

Prototype

Prototype Design Pattern is also a pattern we use to receive an object instance for a particular class, such as builder and factory pattern. Instead of having a new fresh object every time, we can make a copy of an existed object instantly and start using it. In that way, we do not have to repeat the building process for the object we are trying to use. The new copy object is totally independent with the original prototype object, and can be used for any purpose that will not affect the original. There is no limit for copying the existing objects, any existing object can be copied.

Let’s search for types implementing clone() method.


from t in Types where t.Methods.Where(a=>a.SimpleName==”clone”).Count()>0
&& !t.IsThirdParty && t.IsClass
select t

Motivation

When creating an object is time consuming and a costly affair and you already have a most similar object instance in hand, then you go for prototype pattern. Instead of going through a time consuming process to create a complex object, just copy the existing similar object and modify it according to your needs.

Lazy Initialization

Lazy initialization is the tactic of delaying the creation of an object, the calculation of a value, or some other expensive process until the first time it is needed.

We can identify some classes using this pattern, by searching classes having init method but not invoked from the constructor.


from t in Types where t.Methods.Where(a=>a.SimpleName==”init” && a.MethodsCallingMe.Where(b=>b.IsConstructor).Count()==0).Count()>0
&& !t.IsThirdParty && t.IsClass
select t

Motivation

Like prototype pattern, Lazy Initialization is one of the performance tuning techniques.

Conclusion

Using design patterns has many advantages, but without understanding their motivations is very difficult to implement them, fortunately the motivation of creational patterns are very clear, and they are widely used, in the next article we will discover structural patterns used by JBoss.

Like this:

LikeLoading...

Related

Categories: CodeProject

I had a job to check our project code quality. And have to report it back to my team leader for any obstacle that i found in the project.  I found a lot of leaks and i think would be good to be discussed on the blog. Not to mock the author, but to learn and improve ourselves together.

Like this code, this is the part that i found in our code.

public ContactInfoBean(final Reseller resellerInfo) { switch(resellerInfo.getType()) { case PROGRAM_CONTACT: readExecutiveInfo(resellerInfo); break; case FILE_CONTACT: readOperationalInfo(resellerInfo); break; default: break; } }

The code works fine, and do its job pretty well. But some problem will appear by using this code-style. This class will grow tailing the biz changes, as usual, the bigger one class, the “merrier” to maintain it is. And most likely this class, will be having more than one purpose, can be called low-cohesion.

Better OOP Approach

Well the better approach for the case above would be using the Factory Design Pattern.  We can let the factory of  READER to generate every single instance according to their type. It would be easier to grow the instance type, since we just need to create a new class and do a little modification in the Factory class. The caller class, wont grow and will stand still at its current shape.

public interface InfoReader { public void readInfo(); } public class ExecutiveReader implements InfoReader { public void readInfo() { // override } } public class OperationalReader implements InfoReader { public void readInfo() { // override } }

And The Factory

public class InfoReaderFactory { private static final int PROGRAM_CONTACT = 1; private static final int FILE_CONTACT = 2; public static InfoReader getInstance(Reseller resellerInfo) { InfoReader instance = null; switch (resellerInfo.getType()) { case PROGRAM_CONTACT: instance = new ExecutiveReader(); break; case FILE_CONTACT: instance = new OperationalReader(); break; default: throw new IllegalArgumentException("Unknown Reseller"); } return instance; } }

And now The Caller

InfoReader reader = InfoReaderFactory.getInstance(resellerInfo); reader.readInfo();

The Benefits

With the Factory Design Pattern to handle this case, we can achieve some benefits,

  • Specifying a class for one task, means, easier to maintain since one class is for one purpose only (modularity/High Cohesion). i.e: Operational Reader is only to read data for Operational only, no other purpose. Just in case, one day in the future we need another Reader (say: NonOperationalReader). We just need create a new Class that extends (or implements) the InfoReader class and then we can override our own readInfo() function. This Caller class will have no impact. We just need to do some modification in the Factory code.public class InfoReaderFactory { private static final int PROGRAM_CONTACT = 1; private static final int FILE_CONTACT = 2; private static final int NEW_READER = 3; public static InfoReader getInstance(ResellerInfo resellerInfo) { InfoReader instance = null; switch (resellerInfo.getType()) { case PROGRAM_CONTACT: instance = new ExecutiveReader(); break; case FILE_CONTACT: instance = new OperationalReader(); break; case NEW_READER: instance = new NonOperationalReader(); break; default: throw new IllegalArgumentException("Unknown Reseller"); } return instance; } }

 

  • Higher Reusability of Parent’s Component (Inheritance): Since we have parent class (InfoReader), we can put common functions and thingies inside this InfoReader class, and later all of the derivative classes (ExecutiveReader and OperationalReader) can reuse the common components from InfoReader . Avoid code redundancy and can minimize coding time. Eventhough this one depends on how you do the code and cant be guaranteed

But, It’s Run Perfectly, Should We Change It?

Obviously the answer is big NO. This is only the case study and for your further experience and knowledge. OOP is good, do it anywhere it’s applicable. But the most important thing is, if it’s running, dont change it. It would be ridiculous if you ruin the entire working code just to pursue some OOP approach. Dont be naive also, no one can achieve the perfect code. The most important is we know what is the better approach.

 

 

 

Leave a Comment

(0 Comments)

Your email address will not be published. Required fields are marked *