The authors of book "Design patterns" are known as "Gang of Four" :
Showing posts with label Design patterns. Show all posts
Showing posts with label Design patterns. Show all posts
Saturday, 25 June 2016
What is GoF (Gang of Four) ?
The authors of book "Design patterns" are known as "Gang of Four" :
Sunday, 24 April 2016
What are the best Singleton implementations in multithreaded environment ?
IMPLEMENTATION 1. For Single thread
Typical singleton implementation works fine in Single-threaded environment, but may not in multi-threaded environment.
private static Singleton singleton;
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
IMPLEMENTATION 2. Synchronization with Double null checks
To be able to use it in Multi-threaded environment , use synchronized block with double null checks :
private static Singleton singleton;
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
IMPLEMENTATION 3. Using volatile
When the statement runs : singleton = new Singleton();
- It allocates memory
- Assign memory reference to reference variable
- Constructor is invoked
Here, if thread2 preempt thread1 just before invoking constructor and just after memory is allocated, it may give unpredictable results.
It may be avoided by using volatile keyword, which will ensure that each thread will get the correct value of singleton reference.
private static volatile Singleton singleton;
IMPLEMENTATION 4. Lazy initialization using static inner class
Using volatile might be slower than synchronization, so below final solution is thread-safe and does not uses either ‘volatile’ or ‘synchronization’.
private static Singleton singleton;
// Static inner class
private static class SingletonHolder {
private final static Singleton singleton = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.singleton;
}
SingletonHolder is loaded on the first execution of getInstance() method - Lazy Initialization
Saturday, 23 April 2016
What are SOLID principles ?
Single responsibility
A class should have only a single responsibility.
Open/closed principle
Software entities like, classes should be open for extension, but closed for modification.
Liskov substitution
Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.
Interface segregation
Many client-specific interfaces are better than one general-purpose interface.
Dependency inversion
One should "Depend upon Abstractions. Do not depend upon concretions"
---------------------------------------------------------------------------------------------------------------------
S : Write code to fetch some data from DB with good logs created.
You can create different classes instead of writing all the code in one place :
class 1. For creating DB coonection and closing it
class 2. For fetching data from DB
class 3. Logging (specific module)
O : Write code to choose the increment percentage based on user type.
Instead of writing conditions and logic based on values at one place, you can implement specific logic in different classes with different user types.
Class. User has different logic sections according to different user types
Class 1. Partner has logic section 1
Class 2. Customer has logic section 2
Use factory pattern to call specific logic and method
L : Write classes which can be substitute with a generic type.
List <- ArrayList and List <- LinkedList implements this rule.
List <- ArrayList and List <- UnModifiableList violates this rule. (As per need)
I : Segregate the interfaces with different definitions, so that the functions should not be required to be overridden with useless or null implementation.
instead of having single class :
Shape with methods : getArea(), getVolume(), getPerimeter()
Use :
Class base : Shape with getArea()
Class 1. Shape2D extends Shape with getPerimeter()
Class 2. Shape3D extends Shape with getVolume()
D : IoC is a concept and DI is the implementation method.
Define the class and its dependency on other classes.
---------------------------------------------------------------------------------------------------------------------
S : Write code to fetch some data from DB with good logs created.
You can create different classes instead of writing all the code in one place :
class 1. For creating DB coonection and closing it
class 2. For fetching data from DB
class 3. Logging (specific module)
O : Write code to choose the increment percentage based on user type.
Instead of writing conditions and logic based on values at one place, you can implement specific logic in different classes with different user types.
Class. User has different logic sections according to different user types
Class 1. Partner has logic section 1
Class 2. Customer has logic section 2
Use factory pattern to call specific logic and method
L : Write classes which can be substitute with a generic type.
List <- ArrayList and List <- LinkedList implements this rule.
List <- ArrayList and List <- UnModifiableList violates this rule. (As per need)
I : Segregate the interfaces with different definitions, so that the functions should not be required to be overridden with useless or null implementation.
instead of having single class :
Shape with methods : getArea(), getVolume(), getPerimeter()
Use :
Class base : Shape with getArea()
Class 1. Shape2D extends Shape with getPerimeter()
Class 2. Shape3D extends Shape with getVolume()
D : IoC is a concept and DI is the implementation method.
Define the class and its dependency on other classes.
Friday, 22 April 2016
What may be loopholes in Singleton implementation ?
Problem 1 : Multiple Singletons simultaneously loaded by different Class loaders.
Solution : Make sure that Singleton object is loaded by only one class loader peeking through code.
Problem 2 : If you serialize your class and deserialize it again, there will be multiple instances of Singleton class
Solution : If we use readResolve() method, in order to return the Singleton object read, it will make sure only one instance is returned back.
public class Singleton implements Serializable
{
// Code for singleton here
// This method is called immediately after an object of this class is deserialized.
// This method returns the singleton instance.
protected Object readResolve() {
return getInstance();
}
}
Problem 3 : Multiple Singletons arising when someone has sub classed your Singleton.
Solution : This can be avoided at compile time if you make your Constructor Private.
Problem 4 : Two instances can be created when two threads are calling the getInstance() method at the same time (At the very first time)
If one thread entered the method just after the other, you can find calling the constructor twice and returning different values.
Solution : Use synchronized method or block :
public static synchronized Singleton getInstance() {
.......
}
Optimize the code using synchronized block.
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
Problem 5 : Clone the singleton object to get another object
Object obj = Singleton.getInstance(); // Get a singleton Singleton
Singleton clone = (Singleton) obj.clone(); // Let's clone the object
Here, clone() method is provided by in the java.lang.Object class.
Solution : Add a clone() method of our own, and throw a CloneNotSupportedException
public class Singleton implements Cloneable {
// Singleton implementation here
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
}
When the Race condition occurs in Lazy initialization ?
Example : Lazy initialization in case of singleton implementation
public class Sample {
private MyClass instance = null;
private MyClass instance = null;
public MyClass getInstance() {
if (instance == null) {
instance = new MyClass();
}
return instance;
}
}
}
Suppose, Threads A and B execute getInstance at the same time.
A sees that instance is null and instantiates a new object.
B also checks if instance is null and the result depends on perfect timing including time for instantiation and assignment.
Ideally, getInstance supposed to return the same object every time.
But it may be possible to create two different object using new operator, which is a Race condition.
- similar to counter increment
Tuesday, 19 April 2016
State pattern - Example
To show the concept of State pattern, we use a simple command line program.
If a GUI program is used, a mediator pattern or a flyweight pattern may be applied on it.
Users connect to a database to do some jobs. Users from Management department may focus on management.Users from Sales department may focus on sales information.
Every connection has to perform similar functions like open, log and close. Suppose we have an abstract Connection class and have these functions listed.
Thus, every subclass of Connection must implement these functions. We list three subclasses Management, Sales and Accounting for example, just to show the State pattern concept.
The Controller class contains each state of connection. Its behavior is decided by another object, which is a Test class.
All the details have been hidden from the Test class.
Suppose we have a server which is a singleton.
Which connection is made depends on the user.
We use a Test class which makes a trigger from command line. In the real program, the trigger should be made by the user.
abstract class Connection {
public abstract void open();
public abstract void close();
public abstract void log();
}
class Accounting extends Connection {
public void open() {
System.out.println("open database for accounting");
}
public void close() {
System.out.println("close the database");
}
public void log() {
System.out.println("log activities");
}
//...
}
class Sales extends Connection {
public void open() {
System.out.println("open database for sales");
}
public void close() {
System.out.println("close the database");
}
public void log() {
System.out.println("log activities");
}
public void update() {
//...
}
}
class Management extends Connection {
public void open() {
System.out.println("open database for management");
}
public void close() {
System.out.println("close the database");
}
public void log() {
System.out.println("log activities");
}
//...
}
class Controller {
public static Accounting acct;
public static Sales sales;
public static Management manage;
private static Connection current;
Controller() {
acct = new Accounting();
sales = new Sales();
manage = new Management();
}
public void makeAccountingConnection() {
current = acct;
}
public void makeSalesConnection() {
current = sales;
}
public void makeManagementConnection() {
current = manage;
}
public void open() {
current.open();
}
public void close() {
current.close();
}
public void log() {
current.log();
}
}
// ______________ USE ______________
if(con.equalsIgnoreCase("management"))
controller.makeManagementConnection();
if(con.equalsIgnoreCase("sales"))
controller.makeSalesConnection();
if(con.equalsIgnoreCase("accounting"))
controller.makeAccountingConnection();
controller.open();
controller.log();
controller.close();
Subscribe to:
Posts (Atom)