Design Pattern - Advanced

                                                             Design Pattern - Advanced

                                                                                



1. Composite Pattern:

The Composite pattern allows you to treat individual objects and groups of objects uniformly. It enables the creation of hierarchical structures, where a group of objects can be treated as a single object.


```java

import java.util.ArrayList;

import java.util.List;


interface Graphic {

    void draw();

}


class Circle implements Graphic {

    public void draw() {

        System.out.println("Drawing a circle");

    }

}


class CompositeGraphic implements Graphic {

    private List<Graphic> graphics = new ArrayList<>();


    public void add(Graphic graphic) {

        graphics.add(graphic);

    }


    public void draw() {

        for (Graphic graphic : graphics) {

            graphic.draw();

        }

    }

}


public class CompositePatternExample {

    public static void main(String[] args) {

        Circle circle1 = new Circle();

        Circle circle2 = new Circle();

        CompositeGraphic composite = new CompositeGraphic();

        composite.add(circle1);

        composite.add(circle2);


        composite.draw();

        // Output:

        // Drawing a circle

        // Drawing a circle

    }

}

```


Explanation: In this example, we have a `Graphic` interface that defines the `draw` method. The `Circle` class implements the `Graphic` interface, representing an individual object. The `CompositeGraphic` class also implements the `Graphic` interface and contains a list of `Graphic` objects. When the `draw` method is called on the `CompositeGraphic`, it invokes the `draw` method on each of its child `Graphic` objects.


2. Proxy Pattern:

The Proxy pattern provides a surrogate or placeholder for another object and controls access to it. It can be used to add additional functionality to an object or to control its instantiation.


```java

interface Image {

    void display();

}


class RealImage implements Image {

    private String filename;


    public RealImage(String filename) {

        this.filename = filename;

        loadFromDisk();

    }


    private void loadFromDisk() {

        System.out.println("Loading image: " + filename);

    }


    public void display() {

        System.out.println("Displaying image: " + filename);

    }

}


class ImageProxy implements Image {

    private String filename;

    private RealImage image;


    public ImageProxy(String filename) {

        this.filename = filename;

    }


    public void display() {

        if (image == null) {

            image = new RealImage(filename);

        }

        image.display();

    }

}


public class ProxyPatternExample {

    public static void main(String[] args) {

        Image image = new ImageProxy("image.jpg");

        image.display();

        // Output:

        // Loading image: image.jpg

        // Displaying image: image.jpg

    }

}

```


Explanation: In this example, the `Image` interface defines the `display` method. The `RealImage` class implements the `Image` interface and represents the real object that is expensive to create. The `ImageProxy` class also implements the `Image` interface and acts as a proxy to the `RealImage`. The `ImageProxy` is responsible for creating the `RealImage` object only when necessary, and delegates the `display` method to the `RealImage`.


3. Adapter Pattern:

The Adapter pattern allows objects with incompatible interfaces to work together by providing a common interface. It converts the interface of one class into another interface that clients expect.


```java

interface MediaPlayer {

    void play(String audioType, String filename);

}


interface AdvancedMediaPlayer {

    void playVlc(String filename);

    void playMp4(String filename);

}


class VlcPlayer implements AdvancedMediaPlayer {

    public void playVlc(String filename) {

        System.out.println


("Playing vlc file: " + filename);

    }


    public void playMp4(String filename) {

        // Do nothing

    }

}


class Mp4Player implements AdvancedMediaPlayer {

    public void playVlc(String filename) {

        // Do nothing

    }


    public void playMp4(String filename) {

        System.out.println("Playing mp4 file: " + filename);

    }

}


class MediaAdapter implements MediaPlayer {

    private AdvancedMediaPlayer mediaPlayer;


    public MediaAdapter(String audioType) {

        if (audioType.equalsIgnoreCase("vlc")) {

            mediaPlayer = new VlcPlayer();

        } else if (audioType.equalsIgnoreCase("mp4")) {

            mediaPlayer = new Mp4Player();

        }

    }


    public void play(String audioType, String filename) {

        if (audioType.equalsIgnoreCase("vlc")) {

            mediaPlayer.playVlc(filename);

        } else if (audioType.equalsIgnoreCase("mp4")) {

            mediaPlayer.playMp4(filename);

        }

    }

}


class AudioPlayer implements MediaPlayer {

    private MediaAdapter mediaAdapter;


    public void play(String audioType, String filename) {

        if (audioType.equalsIgnoreCase("mp3")) {

            System.out.println("Playing mp3 file: " + filename);

        } else if (audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")) {

            mediaAdapter = new MediaAdapter(audioType);

            mediaAdapter.play(audioType, filename);

        } else {

            System.out.println("Invalid media type: " + audioType);

        }

    }

}


public class AdapterPatternExample {

    public static void main(String[] args) {

        MediaPlayer audioPlayer = new AudioPlayer();

        audioPlayer.play("mp3", "song.mp3");

        audioPlayer.play("vlc", "video.vlc");

        audioPlayer.play("mp4", "video.mp4");

        // Output:

        // Playing mp3 file: song.mp3

        // Playing vlc file: video.vlc

        // Playing mp4 file: video.mp4

    }

}

```


Explanation: In this example, the `MediaPlayer` interface defines the `play` method. The `AdvancedMediaPlayer` interface provides specific methods for playing different types of media. The `VlcPlayer` and `Mp4Player` classes implement the `AdvancedMediaPlayer` interface. The `MediaAdapter` class implements the `MediaPlayer` interface and acts as an adapter between the `MediaPlayer` and `AdvancedMediaPlayer`. The `AudioPlayer` class implements the `MediaPlayer` interface and uses the `MediaAdapter` to play different types of media.

4. Decorator Pattern:

The Decorator pattern allows behavior to be added to an individual object dynamically, without affecting the behavior of other objects from the same class. It provides a flexible alternative to subclassing for extending functionality.


```java

interface Pizza {

    String getDescription();

    double getCost();

}


class MargheritaPizza implements Pizza {

    public String getDescription() {

        return "Margherita Pizza";

    }


    public double getCost() {

        return 8.99;

    }

}


abstract class PizzaDecorator implements Pizza {

    protected Pizza pizza;


    public PizzaDecorator(Pizza pizza) {

        this.pizza = pizza;

    }


    public String getDescription() {

        return pizza.getDescription();

    }


    public double getCost() {

        return pizza.getCost();

    }

}


class CheeseDecorator extends PizzaDecorator {

    public CheeseDecorator(Pizza pizza) {

        super(pizza);

    }


    public String getDescription() {

        return pizza.getDescription() + ", extra cheese";

    }


    public double getCost() {

        return pizza.getCost() + 2.50;

    }

}


public class DecoratorPatternExample {

    public static void main(String[] args) {

        Pizza margherita = new MargheritaPizza();

        Pizza margheritaWithCheese = new CheeseDecorator(margherita);


        System.out.println(margherita.getDescription() + " - Cost: $" + margherita.getCost());

        // Output: Margherita Pizza - Cost: $8.99


        System.out.println(margheritaWithCheese.getDescription() + " - Cost: $" + margheritaWithCheese.getCost());

        // Output: Margherita Pizza, extra cheese - Cost: $11.49

    }

}

```


Explanation: In this example, the `Pizza` interface defines the basic operations of a pizza. The `MargheritaPizza` class implements the `Pizza` interface, representing a concrete pizza. The `PizzaDecorator` is an abstract class that implements the `Pizza` interface and holds a reference to a `Pizza` object. The `CheeseDecorator` extends the `PizzaDecorator` and adds additional behavior (extra cheese) to the pizza. By using the decorator pattern, we can dynamically add new toppings to a pizza without modifying the original pizza class.


5. Strategy Pattern:

The Strategy pattern defines a family of interchangeable algorithms and encapsulates each one. It allows the algorithms to be selected at runtime and promotes flexibility and extensibility.


```java

interface SortingStrategy {

    void sort(int[] arr);

}


class BubbleSort implements SortingStrategy {

    public void sort(int[] arr) {

        // Bubble sort implementation

    }

}


class MergeSort implements SortingStrategy {

    public void sort(int[] arr) {

        // Merge sort implementation

    }

}


class SortingContext {

    private SortingStrategy strategy;


    public SortingContext(SortingStrategy strategy) {

        this.strategy = strategy;

    }


    public void setStrategy(SortingStrategy strategy) {

        this.strategy = strategy;

    }


    public void sortArray(int[] arr) {

        strategy.sort(arr);

    }

}


public class StrategyPatternExample {

    public static void main(String[] args) {

        int[] arr = {5, 2, 8, 1, 9};


        SortingContext context = new SortingContext(new BubbleSort());

        context.sortArray(arr);

        // Perform bubble sort


        context.setStrategy(new MergeSort());

        context.sortArray(arr);

        // Perform merge sort

    }

}

```


Explanation: In this example, the `SortingStrategy` interface defines the sort operation.


 The `BubbleSort` and `MergeSort` classes implement the `SortingStrategy` interface and provide different implementations of the sort algorithm. The `SortingContext` class encapsulates the selected sorting strategy and provides a method to perform the sorting operation. By changing the strategy at runtime, we can switch between different sorting algorithms without modifying the client code.


6. Builder Pattern:

The Builder pattern separates the construction of a complex object from its representation, allowing the same construction process to create different representations. It simplifies object creation and improves readability.


```java

class Car {

    private String brand;

    private String model;

    private int year;

    private String color;


    public Car(String brand, String model, int year, String color) {

        this.brand = brand;

        this.model = model;

        this.year = year;

        this.color = color;

    }


    // Getters and setters

}


class CarBuilder {

    private String brand;

    private String model;

    private int year;

    private String color;


    public CarBuilder setBrand(String brand) {

        this.brand = brand;

        return this;

    }


    public CarBuilder setModel(String model) {

        this.model = model;

        return this;

    }


    public CarBuilder setYear(int year) {

        this.year = year;

        return this;

    }


    public CarBuilder setColor(String color) {

        this.color = color;

        return this;

    }


    public Car build() {

        return new Car(brand, model, year, color);

    }

}


public class BuilderPatternExample {

    public static void main(String[] args) {

        Car car = new CarBuilder()

                .setBrand("Toyota")

                .setModel("Camry")

                .setYear(2022)

                .setColor("Blue")

                .build();


        // Use the constructed car object

    }

}

```


Explanation: In this example, the `Car` class represents a complex object that requires multiple attributes to be set during construction. The `CarBuilder` class provides methods to set each attribute and returns itself to enable method chaining. The `build` method creates a `Car` object with the provided attributes. This allows for a more readable and flexible way to construct objects, especially when there are many optional attributes.


7. MVC Pattern:

The MVC (Model-View-Controller) pattern separates the presentation, logic, and data components of an application. It enhances maintainability, reusability, and testability of the codebase.


```java

class Model {

    private String data;


    public void setData(String data) {

        this.data = data;

    }


    public String getData() {

        return data;

    }

}


class View {

    public void displayData(String data) {

        System.out.println("Data: " + data);

    }

}


class Controller {

    private Model model;

    private View view;


    public Controller(Model model, View view) {

        this.model = model;

        this.view = view;

    }


    public void updateData(String data) {

        model.setData(data);

    }


    public void displayData() {

        String data = model.getData();

        view.displayData(data);

    }

}


public class MVCPatternExample {

    public static void main(String[] args) {

        Model model = new Model();

        View view = new View();

        Controller controller = new Controller(model, view);


        controller.updateData("Hello, MVC!");

        controller.displayData();

        // Output: Data: Hello, MVC!

    }

}

```


Explanation: In this example, the `Model` represents the data and its associated operations. The `View` is responsible for rendering the data to the user. The `Controller` acts as an intermediary between the `Model` and `View`, handling user inputs and updating the `Model` accordingly. The MVC pattern allows for separation of concerns, making the code more modular and maintainable.


Comments

Popular posts from this blog

Data Analytics - Overview

Data Mining - Overview

MuleSoft