Skip to content

This project contains some design pattern which will be useful for android developers as it has advantages such as reusability, mutability, transparency.

Notifications You must be signed in to change notification settings

Muntasir89/Design_Pattern_Java

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 

Repository files navigation

Design-Pattern

This project contains some design pattern which will be useful for android developers, Java Developer as it has advantages such as reusability, mutability, transparency.

Creational Design Pattern

Creational design patterns are concerned with the way of creating objects. These design patterns are used when a decision must be made at the time of instantiation of a class.

Singleton Design Pattern

This pattern is used for allowing users to use only one instance of a class. Single Design Pattern has two instantiation i) Early instantiation ii) Lazy instantiation

Early instantiation

The Singleton class creates an object initialy by using new keyword. Whether the user calls the getInstance() method or not Singleton class creates an object in the memory.

    static Singleton instance = new Singleton();
    private Singleton(){};
    public static Singleton getInstance()
    {
        return instance;
    }

Lazy instantiation

In this instantiation, the Singleton classes object is only created when user need it by checking whether it is NULL or not.

    static Singleton instance;
    private Singleton(){};
    public static Singleton getInstance()
    {
        if(instance == null)
            instance = new Singleton();
        return instance;
    }

Builder

Why used--
 1) It is used when we have too many arguments to send in constructor & it's hard to maintain the order
 2) When we don't want to send all parameters in object initialization (Generally we send optional parameters as NULL)
It has a static nested class which contains all arguments of outer class and named using nameing convention 'ClassaNmeBuilder'. This class has a build method that will return the final Object.

Factory

Why used--
  1) Used when we have multiple sub-classes of a Super class & based on input we want to return one class instance

    public static FVehicle getInstance(String type, int wheel){
        if(type == "car")
            return new Car(wheel);
        else if(type == "bike")
            return new Bike(wheel);

        return null;
    }

  2) It provides abstraction between implementation & user classes
Super class can be interface or abstract class or basic class.

    abstract public class FVehicle {
    public abstract int getWheel();

    public String toString(){
        return "Wheel: " + this.getWheel();
    }
}

Structural Design Pattern

Structural design pattern is a blueprint of how different objects and classes are combined together to form a bigger structure for achieving multiple goals altogether. The patterns in structural designs show how unique pieces of a system can be combined together in an extensible and flexible manner.

Bridge

According to the definition of Gang of Four - Decouple an abstraction from its implementation so that the two can vary independently. image

Output

Output

Facade

Simply put, a facade encapsulates a complex subsystem behind a simple interface. It hides much of the complexity and makes the subsystem easy to use.
Besides a much simpler interface, there's one more benefit of using this design pattern. It decouples a client implementation from the complex subsystem.
It has three part-

  1. Complex Subsystem
  2. Facade
  3. Client Code
// Facade
class HomeTheaterFacade {
    private Amplifier amplifier;
    private DvdPlayer dvdPlayer;
    private Projector projector;

    public HomeTheaterFacade() {
        this.amplifier = new Amplifier();
        this.dvdPlayer = new DvdPlayer();
        this.projector = new Projector();
    }

    public void watchMovie(String movie) {
        System.out.println("Get ready to watch a movie...");
        amplifier.on();
        amplifier.setVolume(10);

        dvdPlayer.on();
        dvdPlayer.play(movie);

        projector.on();
        projector.setInput(dvdPlayer);
    }

    public void endMovie() {
        System.out.println("Shutting down the home theater...");
        amplifier.off();
        dvdPlayer.stop();
        dvdPlayer.off();
        projector.off();
    }
}

We've hid all the complexity in two methods: watchMovie() and endMovie().
Now the client code are:

// Client Code
public class Main {
    public static void main(String[] args) {
        HomeTheaterFacade homeTheater = new HomeTheaterFacade();
        // Start watching a movie
        homeTheater.watchMovie("The Avengers");
        System.out.println("\n");
        // End the movie session
        homeTheater.endMovie();
    }
}

Output:

Get ready to watch a movie...
Amplifier turned on
Setting amplifier volume to 10
DVD player turned on
Playing movie: The Avengers
Projector turned on
Setting input to DVD player

Shutting down the home theater...
Amplifier turned off
Movie stopped
DVD player turned off
Projector turned off

Benefits of Facade

  • Simplified Interface
  • Decoupling
  • Encapsulation
  • Improved Maintainability
  • Code Reusability

Adapter

When we need to connect to two interfaces that are not compatible to each other, we can use Adpter Design Pattern. This situation arises when a legacy code has to be integrated with new code. Let's dive into example...
Student.java

public interface Student {
    public String getName();
    public String getSurName();
    public String getEmail();
}

This interface is implemented by collegeStudent* class.
CollegeStudent.java

public class CollegeStudent implements Student{
    String name;
    String SurName;
    String email;

    public CollegeStudent(String name, String surname, String email){
        this.name = name;
        this.SurName = surname;
        this.email = email;
    }

    public String getName() {
        return name;
    }

    @Override
    public String getSurName() {
        return SurName;
    }

    @Override
    public String getEmail() {
        return email;
    }
}

Again, we have another class called SchoolStudent which does not implement Student interface.
SchoolStudent.java

public class SchoolStudent{
    private String firstName;
    private String lastName;
    private String emailAddress;

    SchoolStudent(String firstName, String lastName, String emailAddress){
        this.firstName = firstName;
        this.lastName = lastName;
        this.emailAddress = emailAddress;
    }
    public String getFirstName(){
        return firstName;
    }
    public String getLastName(){
        return lastName;
    }
    public String getEmailAddress(){
        return emailAddress;
    }
}

In the StudentClient class we are adding Student class that is adding CollegeStudent as it is implementing Student but SchoolStudent not implementing it. So we cannot add it students lists. So, we need a an adapter that will bind the SchoolStudent class info to the adapter which will again implement the Student interface. So, now can add it to students list.
SchoolStudentAdapter.java

public class SchoolStudentAdapter implements Student{
    private SchoolStudent schoolStudent;
    public SchoolStudentAdapter(SchoolStudent schoolStudent){
        this.schoolStudent = schoolStudent;
    }
    @Override
    public String getName() {
        return this.schoolStudent.getFirstName();
    }
    @Override
    public String getSurName() {
        return this.schoolStudent.getLastName();
    }
    @Override
    public String getEmail() {
        return this.schoolStudent.getEmailAddress();
    }   
}

StudentClient.java

public class StudentClient {
    public List<Student> getStudentList(){
        List<Student> students = new ArrayList<>();
        SchoolStudent schoolStudent = new SchoolStudent("x", "y", "z");
        CollegeStudent collegeStudent = new CollegeStudent("x", "y", "z");

        students.add(collegeStudent);
        students.add(new SchoolStudentAdapter(schoolStudent));

        return students;
    }
}

Proxy

Provide a class which will limit access to another class like when you want to control access i.e. database. For example, you would want to contorl the delete query available only for certain users like admin. The Proxy acts as an intermediary between the client and the real object, allowing the proxy to perform additional tasks before or after accessing the real object.

// Step 1: Create an interface for the real object and define its methods
interface Image {
    void display();
}

// Step 2: Create a concrete implementation of the real object
class RealImage implements Image {
    private String filename;

    public RealImage(String filename) {
        this.filename = filename;
        loadFromDisk(); // Simulating the time-consuming task of loading an image from disk
    }

    private void loadFromDisk() {
        System.out.println("Loading image from disk: " + filename);
    }

    public void display() {
        System.out.println("Displaying image: " + filename);
    }
}

// Step 3: Create a proxy class that implements the same interface as the real object
class ImageProxy implements Image {
    private String filename;
    private RealImage realImage;

    public ImageProxy(String filename) {
        this.filename = filename;
    }

    public void display() {
        if (realImage == null) {
            realImage = new RealImage(filename);
        }
        realImage.display();
    }
}

// Step 4: Demonstrate the usage of the proxy
public class Main {
    public static void main(String[] args) {
        // Create a proxy object
        Image image = new ImageProxy("image.jpg");

        // The real object is loaded only when the display() method is called
        image.display();

        // The real object is not loaded again as it has already been loaded
        image.display();
    }
}

Composite

The Composite Design Pattern is a structural design pattern to compose objects into tree structures to represent part-whole hierarchies. This pattern allows you to treat individual objects and compositions of objects uniformly.
Component: This is the base interface or abstract class for all objects in the composition. It declares the common operations that can be performed on both simple and complex objects.
Leaf: A Leaf is a basic element in the composition that does not have any children. It implements the Component interface, performing the operations defined in the Component.
Composite: This is a complex component that may have children. A Composite implements the Component interface and is capable of holding other components (either Leafs or other Composites). It delegates the operations to its children.
Client: The client interacts with the objects in the composition through the Component interface. It treats all objects (both simple and composite) uniformly.
If leaf node performs any operation then the same operation should be performed on composite node. Composite Design Pattern

About

This project contains some design pattern which will be useful for android developers as it has advantages such as reusability, mutability, transparency.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages