Flyweight is utilized when there is a requirement to develop a larger number of objects of the same nature. Since a large number of objects tend to use more memory therefore flyweight design pattern offers an alternative through which the memory load is decreased through sharing of objects. Flyweight segregates the object properties into two different kinds where one is intrinsic and the other one is extrinsic.
When Outsource Java development should use Flyweight Design Pattern
A number of factors need to be considered to exactly when the outsource Java development team should used flyweight design pattern and some of these parameters include:
When Java development team finds a need for creating large number of objects
When memory cost becomes a constraint due to the large number of objects
When it is possible to make the different object attributes external and shared
The application should not mandate unique objects since after the implementation some objects are used on a repeated basis
When the extrinsic state can be computed instead of being stored
How Outsource Java Development team can apply flyweight?
It is important to analyze before creating the object in large number and making it undergo the flyweight process. The basic aim is to develop less number of objects through the reuse of the same objects. It is beneficial to develop smaller group of objects so that they can be reused through sharing. It is important to closely observe the object properties as they can be divided into intrinsic and extrinsic.
Intrinsic and Extrinsic State
It is important that Java developers create only 26 objects so that it is able to map every unique character. The character of the 26 objects will be the intrinsic state, which means that the object 'a' will possess state as character 'a'. The color, font and size will form the extrinsic state and will need to be passed by client code. Therefore 26 objects will be stored; the client code will get the required character and pass the extrinsic state to it in regard to this particular context.
How Java Development team can implement Flyweight?
When the object is in intrinsic state it is called flyweight object. When flyweight is implemented it creates concrete objects and also possesses the intrinsic state that is stored within it. To make the concrete objects outsource Java development team need to have factory, which will be called Flyweight factory? This factory is responsible for ensuring that the objects are shared and prevent duplication.
For example, different geometrical shapes such as rectangles and ovals have to be drawn in large numbers. Every shape can vary in size, color and font and the Java development team can ensure that every shape also features a label that directly maps it with a shape. This means that all the rectangles will be labeled as 'R' and all the ovals will be labeled as 'O'.
The flyweight will possess intrinsic state as label only and hence there will be only two flyweight objects. The other properties that tend to vary such as color, font and size will be regarded as extrinsic. The flyweight factory will control the two flyweight objects and ensure it distributed to clients accordingly. There will also exist an interface that would help outsource Java developers to implement so that there is also a common blueprint. The client code can utilize random number generators to develop extrinsic properties.
This design pattern is used for controlling the number of instances of a class (to one in general). This is maybe the first, the most used and the easiest design pattern out there.
Starting Java 1.5, one can use enums for singleton implementations. This method is easier and straight forward, taking off the burden of synchronization from the developer.
If you still use prior to Java 1.5 code, read further.
Beware that this control ( controlling the number of instances of a class ) is available per classloader, and not for JVM, not to say more when thinking at distributed topologies. This is because the final static instance variable - being static is per class basis. As you know now, in a JVM you can have more than one classloader - meaning you can load the same Singleton implementing class more than once (once per classloader). Loading more than once the Singleton implementing class results in the possibility of having n instances controlled by the singleton per JVM, where n represents the number of the loads of the Singleton implementing class, so will need at least n classloaders.
In a multiple JVM topology ( cluster deployed application ) special algorithms must be taken into consideration for controlling the number of instances of a class. These can be fine-tuned depending on the needs of the application requirements.
From the point of view of the memory and processor usage that can be impacted depending from one implementation to the other, I would categorize them into the following:
• standard form - the memory savvy version: I consider it a memory savvy version because the instance is created only on a per-need basis, which is trivial. No one needs it, no instance is created: save memory.
class Singleton {
private static Singleton INSTANCE;
private Singleton()
{
//do complicated initialization stuff
}
public static Singleton getInstance()
{
if (INSTANCE == null)
INSTANCE = new Singleton();
return INSTANCE;
}
}
• less standard form - the processor savvy version: Well this version will initialize the instance of the Singleton implementing class regardless someone needs it or not! It will be created at the primordial moment of loading the Singleton class by the classloader into the JVM memory.
Why would you use this? If you have some large quantity processor killing initialization tasks and you don't want the first time an instance is needed to put the rest of the application and the user on hold until this completes, you create it at the very most starting point of the application, such that, when a user triggers the need of this singleton she/he would not have to wait. Think at the compile time for jsp's - it's something similar. Beam me out!
class Singleton{
private static final Singleton INSTANCE = new Singleton();
private Singleton()
{
//do complicated initialization stuff
}
public static Singleton getInstance()
{
return INSTANCE;
}
}
some notes have to be added here:
- notice the final modifier has appeared - that's because the initialization is made before the statics are finished loading into the memory and now we actually can make use of it! (Theory says that any final has to be initialized before the constructor finishes - that's for non-statics - aaand - for statics is before the attributes are loaded into the memory - in other words, before the classloader finishes loading the class). Proof? Try initing the static final variable on a different line than the declaration like - take for example in a static field =>compiles; delete the static field =>fail. Conclusion: having a final in the memory savvy version would yield a compile time error because the "The blank final field s may not have been initialized" - which makes sense since if it wouldn't you maybe forgot about it and then it should be automatically assigned - and then, when calling the getInstance you would choke with a runtime error since a final cannot be changed!
- This version can also be used when you wouldn't want to miss with the synchronized version coming up next, but you would still want to have a thread-safe Singleton implementation. Explanations right after the break in the least standard form.
• least standard form - the synchronized version:
class Singleton{
private static final Singleton INSTANCE;
private Singleton()
{
//do complicated initialization stuff
}
public static Singleton getInstance()
{
if (INSTANCE == null)
{
synchronized(Singleton.class) {
if (INSTANCE == null)
INSTANCE = new Singleton();
}
}
return instance;
}
}
Notice the getInstance() method alters the value of the instance variable - this is highly sensitive when in a multithreaded environment because we could hit the fan while in the if(instance==null) line. Two or more threads could enter this if scope and then manage their way to the sweet initialization block - hence more than wanted (in this case more than 1) instances will be created.
For this issue, we add an additional if(instance==null) which we synchronize access to in order to lock the access to the assignment line.
Some of us might ask ourselves why there are 2(two) if's? That's because if we remove the 1st if(the unsynchronized one) we'll introduce unneeded interlocking processes using directly the synchronized block.
Considering the fact that the synchronized block is need only ONE TIME (in this case, or a finite times in other cases when we need more than one controlled instance) and that's when the initialization is made, putting the first if in the code(the unsynchronized one) eliminates the interlocking mechanisms after the initialization block is finished - in other words, once the instance variable is set, any number of threads accessing the if(instance!= null) will get false and they'll not get further to the synchronized interlocking after the initialization.
If you hate synchronization you can pick the processor savvy version and initialize the instance variable in the static context directly and avoid the multithreaded headache. You should still think at the architecture of your solution and ponder if that's better or not to save memory or processor.
Book Summary of Design Patterns
Four brilliant designers have written this guide, which can be used for solving design problems related to object-oriented software. Developers, architects, and object oriented designers can find the book useful. Design Patterns: Elements Of Reusable Object-Oriented Software also aims to help programmers who are looking forward to upgrade the quality of their designs.
Summary Of The Book
Whether an individual is an object oriented designer, an architect, a developer or a simple programmer, there are a few design problems that are universal, and for anyone serious about their work, such hindrances can be quite a downer.
Design Patterns: Elements Of Reusable Object-Oriented Software is a guide that teaches readers how to make use of standard design patterns for finding effective solutions to design problems encountered on a daily basis.
The book contains around 23 patterns, all explained methodically and in detail, to create designs, which are not only reusable but also quite flexible. Also, these improved designs do not require the author to go back to the design solution each time.
First, the authors explain and discuss what “patterns” are and how they come to play in object-oriented design. Next, they move to designs that frequently occur in object-oriented design processes and then name, explain, and study them.
From this book, the readers can understand how these patterns contribute to the development of software patterns and how they can be used to solve any design problems that may occur.
Every pattern description comes with an explanation that details when certain patterns can be used, how they work with larger design, and when the other patterns appear limited. All patterns come with codes so that they may be applied to object-oriented programming languages and they are based on tried and tested examples and are set up using real systems.
Published on November 10, 1994, this book has sold exceptionally and is considered a milestone text in object-oriented design. The authors have attempted to provide timeless and highly effective solutions in the book.
About The Authors
John Vlissides studied electrical engineering at Stanford and was a renowned software scientist. He worked at Stanford as researcher, consultant, etc. and later at IBM T.J. Watson Research Center in New York. He died of a brain tumour at the age of 44.
He has also authored Pattern Hatching: Design Patterns Applied.
Erich Gamma is a Swiss computer scientist who is part of Microsoft Visual Studio since 2011. He pursued his PhD in computer science from the University of Zurich.
Gamma also co-authored Contributing to Eclipse: Principles, Patterns, and Plug-Ins.
Ralph Johnson works at the University of Illinois as an associate professor of research in the department of computer science.
Richard Helm has a PhD degree from the University of Melbourne, Australia, in computer science. He worked at IBM in the software technology department and then for DMR group as a technology consultant, after which he rejoined IBM.
Design Patterns: Elements Of Reusable Object-Oriented Software is comprehensive, well packed with real-life examples and effective solutions for design-related problems. Every single aspect of the patterns as well as their implementation is explained in great detail.