Hello Guys!!! Hope you all are doing well.
Today I am going to discuss some famous Design Pattern in Java and Android.
First start with What is Design Pattern ?
In software engineering, a design pattern is a general repeatable solution to a commonly occurring problem in software design. A design pattern isn't a finished design that can be transformed directly into code. It is a description or template for how to solve a problem that can be used in many different situations.
Some of the benefits of using design patterns are:
Structural patterns: how you compose objects.
Behavioral patterns: how you coordinate object interactions.
Design Pattern used in Android
Top 10 design pattern example
Here We discuss two variant:-
When to use Factory design pattern
....continue....
Today I am going to discuss some famous Design Pattern in Java and Android.
First start with What is Design Pattern ?
In software engineering, a design pattern is a general repeatable solution to a commonly occurring problem in software design. A design pattern isn't a finished design that can be transformed directly into code. It is a description or template for how to solve a problem that can be used in many different situations.
Some of the benefits of using design patterns are:
- Design Patterns are already defined and provides industry standard approach to solve a recurring problem, so it saves time if we sensibly use the design pattern. There are many java design patterns that we can use in our java/Android based projects.
- Using design patterns promotes reusability that leads to more robust and highly maintainable code. It helps in reducing total cost of ownership (TCO) of the software product.
- Since design patterns are already defined, it makes our code easy to understand and debug. It leads to faster development and new members of team understand it easily.
- Creational,
- Structural, and
- Behavioral
Creational Design Pattern
- This is all about the class instantiation
- Uses class creation pattern and object creation pattern
- Class creation pattern uses inheritance effectively
- Object cation pattern uses delegation to get the job done
Structural Design Pattern
Describe how object and classes can be combined to form larger structures
Behavioral Design Pattern
In Short we can say :-
Creational patterns: how you create objects.Structural patterns: how you compose objects.
Behavioral patterns: how you coordinate object interactions.
Design Pattern used in Android
Android functionality or API | Used Design Pattern |
Adapter | Adapter Design Pattern |
Notification | Builder Design Pattern |
Broadcast Receiver | Observer Pattern |
Intent | Factory Design Pattern |
View Holder | Singleton Design Pattern |
View and View Group | Composite Design Pattern |
Media Framework | Facade Pattern |
Remote Service invocation | Proxy Pattern |
Top 10 design pattern example
- Singleton
- Proxy
- Factory Method
- Abstract Factory
- Adapter
- Decorator
- Builder
- Observer
Singleton pattern
Approaches:-
1. Eager initialization
In eager initialization, the instance of Singleton Class is created at the time of class loading, this is the easiest method to create a singleton class but it has a drawback that instance is created even though client application might not be using it.
it restricts the creation of instance until requested first time. Lets see in code:
Suppose there are two threads T1 and T2. Both comes to create instance and execute “instance==null”, now both threads have identified instance variable to null thus assume they must create an instance. They sequentially goes to synchronized block and create the instances. At the end, we have two instances in our application.
This error can be solved using double-checked locking. This principle tells us to recheck the instance variable again in synchronized block in given below way:
Bill pugh was main force behind java memory model changes. He suggested to use static inner class.
- Comes in the Creational Design Pattern category
- Restricts the instantiation of a class and ensures that only one instance of the class exists in the java virtual machine
- it seems to be a very simple design pattern but when it comes to implementation, it comes with a lot of implementation concerns
- The implementation of Java Singleton pattern has always been a controversial topic among developers
Approaches:-
1. Eager initialization
In eager initialization, the instance of Singleton Class is created at the time of class loading, this is the easiest method to create a singleton class but it has a drawback that instance is created even though client application might not be using it.
package com.sks.singleton.example;
public class EagerInitializedSingleton {
private static final EagerInitializedSingleton instance = new EagerInitializedSingleton();
// private constructor to avoid client applications to use constructor
private EagerInitializedSingleton() {
}
public static EagerInitializedSingleton getInstance() {
return instance;
}
}
2. Lazy initializationit restricts the creation of instance until requested first time. Lets see in code:
package com.sks.singleton.example;
public class LazySingleton {
/*
*Please ensure to use “volatile” keyword with instance variable
*otherwise you can run into out of order write error scenario,
*where reference of instance is returned before actually the object is constructed
*i.e. JVM has only allocated the memory and constructor code is still not executed.
*In this case, your other thread, which refer to uninitialized object may throw null pointer exception
* and can even crash the whole application
*/
private static volatile LazySingleton instance = null;
// private constructor
private LazySingleton() {
}
public static LazySingleton getInstance() {
if (instance == null) {
synchronized (LazySingleton.class) {
instance = new LazySingleton();
}
}
return instance;
}
}
But, this method also has its own drawbacks. Lets see how.Suppose there are two threads T1 and T2. Both comes to create instance and execute “instance==null”, now both threads have identified instance variable to null thus assume they must create an instance. They sequentially goes to synchronized block and create the instances. At the end, we have two instances in our application.
This error can be solved using double-checked locking. This principle tells us to recheck the instance variable again in synchronized block in given below way:
//Double lock checking...
public static LazySingleton getInstance() {
if (instance == null) {
synchronized (LazySingleton.class) {
// Double check
if (instance == null) {
instance = new LazySingleton();
}
}
}
return instance;
}
3. Bill pugh solutionBill pugh was main force behind java memory model changes. He suggested to use static inner class.
package com.sks.singleton.example;
public class BillPughSingleton {
private BillPughSingleton() {
}
private static class LazyHolder {
private static final BillPughSingleton INSTANCE = new BillPughSingleton();
}
public static BillPughSingleton getInstance() {
return LazyHolder.INSTANCE;
}
}
As you can see, until we need an instance, the LazyHolder class will not be initialized until required and you can still use other static members of BillPughSingleton class.
This is the solution, I will recommend to use. I also use it in my all projects.
4. Adding readResolve()
- By Seeing above example, hopefully you have taken your decision that how you would like to implement your singleton.
- Now lets see other problems that may arise due to serialization and de-serialization (always creates a new instance).
- To solve this issue, we need to include readResolve() method in our DemoSingleton class. This method will be invoked when you will de-serialize the object.
- Inside this method, you must return the existing instance to ensure single instance application wide.
package com.sks.singleton.example;
import java.io.Serializable;
public class DemoSingleton implements Serializable {
private static final long serialVersionUID = 1L;
private DemoSingleton() {
// private constructor
}
private static class DemoSingletonHolder {
public static final DemoSingleton INSTANCE = new DemoSingleton();
}
public static DemoSingleton getInstance() {
return DemoSingletonHolder.INSTANCE;
}
protected Object readResolve() {
return getInstance();
}
}
2. Proxy Design Pattern
Provide a surrogate or placeholder for another object to control access to it.
Proxy is applicable whenever there is a need for a more versatile or sophisticated reference to an object than a simple pointer.
common situations in which the Proxy pattern is applicable :-- Remote proxy provides a local representative for an object in a different address space.
- Virtual proxy creates expensive objects on demand.
- Protection proxy controls access to the original object. Protection proxies are useful when objects should have different access rights.
Typical Use Case
- Control access to another object
- Lazy initialization
- Implement logging
- Facilitate network connection
- Count references to an object
3. Factory Method
The Factory Design Pattern is probably the most used design pattern in modern programming languages. Factory Design pattern is based on Encapsulation object oriented concept. There are different variants and implementations.Here We discuss two variant:-
- Factory Method and
- Abstract Factory
package com.sks.factory.example; public interface Coffee { String getCoffeeVariant(); }
package com.sks.factory.example;
public class Cappuccino implements Coffee{
@Override
public String getCoffeeVariant() {
return "Cappuccino...";
}
}
package com.sks.factory.example;
public class FreshCoffee implements Coffee{
@Override
public String getCoffeeVariant() {
return "Fresh Coffee";
}
}
package com.sks.factory.example;
public class VienneseCoffee implements Coffee{
@Override
public String getCoffeeVariant() {
return "Viennese Coffee...";
}
}
package com.sks.factory.example;
public class CoffeeFactory {
public static Coffee getCoffeeVariant(String Coffee) {
if (Coffee.equalsIgnoreCase ("Fresh")){
return new FreshCoffee();
}else if(Coffee.equalsIgnoreCase ("Cappuccino")){
return new Cappuccino();
}else if(Coffee.equalsIgnoreCase ("Viennese")){
return new VienneseCoffee();
}
throw new IllegalArgumentException("No such Coffee");
}
}
package com.sks.factory.example;
import java.util.Scanner;
public class Factoryclient {
public static void main(String[] args) {
String coffee = "test";
System.out.println("Enter Coffee name.\n");
Scanner mscan = new Scanner(System.in);
try {
coffee = mscan.nextLine();
} catch (NumberFormatException e) {
e.printStackTrace();
}
mscan.close();
Coffee mCoffee = CoffeeFactory.getCoffeeVariant(coffee);
System.out.println(mCoffee.getCoffeeVariant());
}
}
- Static Factory methods are common in frameworks where library code needs to create objects of types which may be sub classed by applications using the framework.
- Some or all concrete products can be created in multiple ways, or we want to leave open the option that in the future there may be new ways to create the concrete product.
- Factory method is used when Products don't need to know how they are created.
- We can use factory pattern where we have to create an object of any one of sub-classes depending on the data provided
4. Abstract Factory Pattern
Define an interface or abstract class for creating families of related (or dependent) objects but without specifying their concrete sub-classes.
That means Abstract Factory lets a class returns a factory of classes. This is why? Abstract Factory Pattern is one level higher than the Factory Pattern.
An Abstract Factory Pattern is also known as Kit.
Advantage
Definition:-
An adapter pattern helps two incompatible interfaces to work together.
The adapter design pattern is used when you want two different classes with incompatible interfaces to work together.
Define an interface or abstract class for creating families of related (or dependent) objects but without specifying their concrete sub-classes.
That means Abstract Factory lets a class returns a factory of classes. This is why? Abstract Factory Pattern is one level higher than the Factory Pattern.
An Abstract Factory Pattern is also known as Kit.
Advantage
- Isolates the client code from concrete (implementation) classes.
- It eases the exchanging of object families.
- It promotes consistency among objects.
- when System needs to be independent of how its object are created, composed, and represented.
- When the family of related objects has to be used together, then this constraint needs to be enforced.
- When you want to provide a library of objects that does not show implementations and only reveals interfaces.
- When the system needs to be configured with one of a multiple family of objects.
package com.sks.abstractfactory.example;
public interface Fruits {
public String getFruitsName();
public String getFruitType();
}
package com.sks.abstractfactory.example;
public interface FruitsFactory {
public Fruits getFruitDetail();
}
package com.sks.abstractfactory.example;
public class ConsumeFruitFactory {
public ConsumeFruitFactory(FruitsFactory fruitFactory) {
if(fruitFactory != null) {
Fruits mfruit = fruitFactory.getFruitDetail();
System.out.println(mfruit.getFruitsName());
System.out.println(mfruit.getFruitType());
}else {
System.out.println("No such a Fruit. Please add it.");
}
}
}
package com.sks.abstractfactory.example;
public class AbstractFactoryClient {
public static void main(String[] args) {
new ConsumeFruitFactory(getFruitDetail("Orange"));
}
public static FruitsFactory getFruitDetail(String type) {
if("Orange".equalsIgnoreCase(type)) {
return new OrangeFactory();
}else if("Mango".equalsIgnoreCase(type)) {
return new MangoFactory();
}else if("Apple".equalsIgnoreCase(type)) {
return new AppleFactory();
}else {
return null;
}
}
}
package com.sks.abstractfactory.example;
public class Apple implements Fruits {
@Override
public String getFruitsName() {
return "Apple";
}
@Override
public String getFruitType() {
return "An apple a day";
}
}
5. AdapterDefinition:-
An adapter pattern helps two incompatible interfaces to work together.
The Adapter Pattern is also known as Wrapper.
Advantage
Advantage
- By using Adapter design pattern two or more previously incompatible objects to interact.
- Adapter design pattern allows reusability of existing functionality.
Implementation
Adapter design pattern can be implemented in two ways.
- using the inheritance method and
- using the composition method
Just the implementation methodology is different but the purpose and solution is same.
package com.sks.adapter.example;
public interface Flower {
// Flowers implement Flower interface that allows
// them to blossom and to spread Aroma in adaptee interface
public void blossom();
public void aroma();
}
package com.sks.adapter.example;
public class FlowerAdapter implements ToyFlower{
// You need to implement the interface your
// client expects to use.
Flower flower;
public FlowerAdapter(Flower flower){
this.flower = flower;
}
@Override
public void beautiful() {
System.out.println("Real Flower Beautiful via Adapter");
}
}
package com.sks.adapter.example;
public interface ToyFlower {
// target interface
// ToyFlower don't blossom and have no aroma they just
// look beautiful like real flower.
public void beautiful();
}
6.Decorator
- Decorator design pattern is used to enhance the functionality of a particular object at run-time or dynamically.
- At the same time other instance of same class will not be affected by this so individual object gets the new behavior.
- Basically we wrap the original object through decorator object.
- Decorator design pattern is based on abstract classes and we derive concrete implementation from that classes,
- It’s a structural design pattern and most widely used.
package com.sks.decorator.example;
public interface Food {
public String prepareFood();
public double foodPrice();
}
package com.sks.decorator.example;
/*
* FoodDecorator abstract class implements the Food interface and override it's all methods
* and it has the ability to decorate some more foods.*/
public abstract class FoodDecorator implements Food {
private Food newFood;
public FoodDecorator(Food newFood) {
this.newFood = newFood;
}
@Override
public String prepareFood() {
return newFood.prepareFood();
}
public double foodPrice() {
return newFood.foodPrice();
}
}
package com.sks.decorator.example;
public class VegFood implements Food{
@Override
public String prepareFood() {
return "Veg Food";
}
@Override
public double foodPrice() {
return 50.0;
}
}
package com.sks.decorator.example;
/*
* NonVegFood concrete class that will extend the FoodDecorator class and override it's all methods
*/
public class NonVegFood extends FoodDecorator {
public NonVegFood(Food newFood) {
super(newFood);
}
public String prepareFood() {
return super.prepareFood() + " With Roasted Chiken and Chiken Curry ";
}
public double foodPrice() {
return super.foodPrice() + 150.0;
}
package com.sks.decorator.example;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class DecoratorPatternClient {
private static int choice;
public static void main(String[] args) throws NumberFormatException, IOException {
do {
System.out.print("========= Food Menu ============ \n");
System.out.print(" 1. Vegetarian Food. \n");
System.out.print(" 2. Non-Vegetarian Food.\n");
System.out.print(" 3. Chineese Food. \n");
System.out.print(" 4. Exit \n");
System.out.print("Enter your choice: ");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
choice = Integer.parseInt(br.readLine());
switch (choice) {
case 1: {
VegFood vf = new VegFood();
System.out.println(vf.prepareFood());
System.out.println(vf.foodPrice());
}
break;
case 2: {
Food f1 = new NonVegFood((Food) new VegFood());
System.out.println(f1.prepareFood());
System.out.println(f1.foodPrice());
}
break;
case 3: {
Food f2 = new ChineeseFood((Food) new VegFood());
System.out.println(f2.prepareFood());
System.out.println(f2.foodPrice());
}
break;
default: {
System.out.println("Other than these no food available");
}
return;
}// end of switch
} while (choice != 4);
}
}
7. Builder Design Pattern ....continue....
0 komentar:
Posting Komentar