Design Patterns (Creational, Structural, Behavioral)

Design patterns are categorized into three main types: Creational, Structural, and Behavioral. Each category addresses different aspects of software design and provides a set of proven solutions to common problems.


Creational Design Patterns

Creational patterns focus on the process of object creation, ensuring that objects are created in a manner suitable to the situation.


1. Singleton Pattern:

   - Ensures a class has only one instance and provides a global point of access to it.

   - Example:

     public class Singleton {
         private static Singleton instance;

         private Singleton() {}

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


2. Factory Method Pattern:

   - Defines an interface for creating an object but allows subclasses to alter the type of objects that will be created.

   - Example:

     public interface Product {
         void use();
     }

     public class ConcreteProductA implements Product {
         public void use() {
             System.out.println("Using Product A");
         }
     }

     public class ConcreteProductB implements Product {
         public void use() {
             System.out.println("Using Product B");
         }
     }

     public abstract class Creator {
         public abstract Product factoryMethod();

         public void someOperation() {
             Product product = factoryMethod();
             product.use();
         }
     }

     public class ConcreteCreatorA extends Creator {
         public Product factoryMethod() {
             return new ConcreteProductA();
         }
     }

     public class ConcreteCreatorB extends Creator {
         public Product factoryMethod() {
             return new ConcreteProductB();
         }
     }


3. Abstract Factory Pattern:

   - Provides an interface for creating families of related or dependent objects without specifying their concrete classes.

   - Example:

     public interface GUIFactory {
         Button createButton();
         Checkbox createCheckbox();
     }

     public class WinFactory implements GUIFactory {
         public Button createButton() {
             return new WinButton();
         }

         public Checkbox createCheckbox() {
             return new WinCheckbox();
         }
     }

     public class MacFactory implements GUIFactory {
         public Button createButton() {
             return new MacButton();
         }

         public Checkbox createCheckbox() {
             return new MacCheckbox();
         }
     }

     public class Application {
         private Button button;
         private Checkbox checkbox;

         public Application(GUIFactory factory) {
             button = factory.createButton();
             checkbox = factory.createCheckbox();
         }

         public void paint() {
             button.paint();
             checkbox.paint();
         }
     }


4. Builder Pattern:

   - Separates the construction of a complex object from its representation so that the same construction process can create different representations.

   - Example:

     public class Product {
         private String partA;
         private String partB;

         public void setPartA(String partA) {
             this.partA = partA;
         }

         public void setPartB(String partB) {
             this.partB = partB;
         }
     }

     public abstract class Builder {
         protected Product product = new Product();

         public abstract void buildPartA();
         public abstract void buildPartB();

         public Product getResult() {
             return product;
         }
     }

     public class ConcreteBuilder extends Builder {
         public void buildPartA() {
             product.setPartA("Part A");
         }

         public void buildPartB() {
             product.setPartB("Part B");
         }
     }

     public class Director {
         private Builder builder;

         public void setBuilder(Builder builder) {
             this.builder = builder;
         }

         public Product construct() {
             builder.buildPartA();
             builder.buildPartB();
             return builder.getResult();
         }
     }


5. Prototype Pattern:

   - Creates new objects by copying existing objects (prototypes).

   - Example:

     public abstract class Prototype implements Cloneable {
         public Prototype clone() throws CloneNotSupportedException {
             return (Prototype) super.clone();
         }
     }

     public class ConcretePrototype extends Prototype {
         private String field;

         public ConcretePrototype(String field) {
             this.field = field;
         }

         public String getField() {
             return field;
         }

         public void setField(String field) {
             this.field = field;
         }
     }

     public class Client {
         public static void main(String[] args) throws CloneNotSupportedException {
             ConcretePrototype prototype = new ConcretePrototype("Prototype");
             ConcretePrototype clone = (ConcretePrototype) prototype.clone();
             System.out.println(clone.getField());
         }
     }


Structural Design Patterns

Structural patterns deal with object composition, creating relationships between objects to form larger structures.


1. Adapter Pattern:

   - Allows incompatible interfaces to work together.

   - Example:

     public interface Target {
         void request();
     }

     public class Adaptee {
         public void specificRequest() {
             System.out.println("Specific request");
         }
     }

     public class Adapter implements Target {
         private Adaptee adaptee;

         public Adapter(Adaptee adaptee) {
             this.adaptee = adaptee;
         }

         public void request() {
             adaptee.specificRequest();
         }
     }

     public class Client {
         public static void main(String[] args) {
             Adaptee adaptee = new Adaptee();
             Target target = new Adapter(adaptee);
             target.request();
         }
     }


2. Composite Pattern:

   - Composes objects into tree structures to represent part-whole hierarchies.

   - Example:

     public interface Component {
         void operation();
     }

     public class Leaf implements Component {
         public void operation() {
             System.out.println("Leaf operation");
         }
     }

     public class Composite implements Component {
         private List<Component> children = new ArrayList<>();

         public void add(Component component) {
             children.add(component);
         }

         public void remove(Component component) {
             children.remove(component);
         }

         public void operation() {
             for (Component child : children) {
                 child.operation();
             }
         }
     }

     public class Client {
         public static void main(String[] args) {
             Leaf leaf1 = new Leaf();
             Leaf leaf2 = new Leaf();
             Composite composite = new Composite();
             composite.add(leaf1);
             composite.add(leaf2);
             composite.operation();
         }
     }


3. Decorator Pattern:

   - Adds behavior to objects dynamically by placing them inside special wrapper objects.

   - Example:

     public interface Component {
         void operation();
     }

     public class ConcreteComponent implements Component {
         public void operation() {
             System.out.println("ConcreteComponent operation");
         }
     }

     public class Decorator implements Component {
         protected Component component;

         public Decorator(Component component) {
             this.component = component;
         }

         public void operation() {
             component.operation();
         }
     }

     public class ConcreteDecorator extends Decorator {
         public ConcreteDecorator(Component component) {
             super(component);
         }

         public void operation() {
             super.operation();
             addedBehavior();
         }

         private void addedBehavior() {
             System.out.println("Added behavior");
         }
     }

     public class Client {
         public static void main(String[] args) {
             Component component = new ConcreteComponent();
             Component decoratedComponent = new ConcreteDecorator(component);
             decoratedComponent.operation();
         }
     }


4. Facade Pattern:

   - Provides a simplified interface to a complex subsystem.

   - Example:

     public class Subsystem1 {
         public void operation1() {
             System.out.println("Subsystem1 operation1");
         }
     }

     public class Subsystem2 {
         public void operation2() {
             System.out.println("Subsystem2 operation2");
         }
     }

     public class Facade {
         private Subsystem1 subsystem1;
         private Subsystem2 subsystem2;

         public Facade() {
             subsystem1 = new Subsystem1();
             subsystem2 = new Subsystem2();
         }

         public void operation() {
             subsystem1.operation1();
             subsystem2.operation2();
         }
     }

     public class Client {
         public static void main(String[] args) {
             Facade facade = new Facade();
             facade.operation();
         }
     }


5. Proxy Pattern:

   - Provides a surrogate or placeholder for another object to control access to it.

   - Example:

     public interface Subject {
         void request();
     }

     public class RealSubject implements Subject {
         public void request() {
             System.out.println("RealSubject request");
         }
     }

     public class Proxy implements Subject {
         private RealSubject realSubject;

         public void request() {
             if (realSubject == null) {
                 realSubject = new RealSubject();
             }
             realSubject.request();
         }
     }

     public class Client {
         public static void main(String[] args) {
             Subject proxy = new Proxy();
             proxy.request();
         }
     }


Behavioral Design Patterns

Behavioral patterns focus on communication between objects, making algorithms and the assignment of responsibilities among objects more flexible.


1. Strategy Pattern:

   - Defines a family of algorithms, encapsulates each one, and makes them interchangeable.

   - Example:

     public interface Strategy {
         int doOperation(int num1, int num2);
     }

     public class Addition implements Strategy {
         public int doOperation(int num1, int num2) {
             return num1 + num2;
         }
     }

     public class Subtraction implements Strategy {
         public int doOperation(int num1, int
 num2) {
             return num1 - num2;
         }
     }

     public class Multiplication implements Strategy {
         public int doOperation(int num1, int num2) {
             return num1 * num2;
         }
     }

     public class Context {
         private Strategy strategy;

         public Context(Strategy strategy) {
             this.strategy = strategy;
         }

         public int executeStrategy(int num1, int num2) {
             return strategy.doOperation(num1, num2);
         }
     }

     public class Client {
         public static void main(String[] args) {
             Context context = new Context(new Addition());
             System.out.println("10 + 5 = " + context.executeStrategy(10, 5));

             context = new Context(new Subtraction());
             System.out.println("10 - 5 = " + context.executeStrategy(10, 5));

             context = new Context(new Multiplication());
             System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
         }
     }


2. Observer Pattern:

   - Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

   - Example:

     import java.util.ArrayList;
     import java.util.List;

     public interface Observer {
         void update(String message);
     }

     public class ConcreteObserver implements Observer {
         private String name;

         public ConcreteObserver(String name) {
             this.name = name;
         }

         public void update(String message) {
             System.out.println(name + " received: " + message);
         }
     }

     public class Subject {
         private List<Observer> observers = new ArrayList<>();

         public void attach(Observer observer) {
             observers.add(observer);
         }

         public void detach(Observer observer) {
             observers.remove(observer);
         }

         public void notifyObservers(String message) {
             for (Observer observer : observers) {
                 observer.update(message);
             }
         }
     }

     public class Client {
         public static void main(String[] args) {
             Subject subject = new Subject();

             Observer observer1 = new ConcreteObserver("Observer 1");
             Observer observer2 = new ConcreteObserver("Observer 2");

             subject.attach(observer1);
             subject.attach(observer2);

             subject.notifyObservers("State changed");
         }
     }


3. Command Pattern:

   - Encapsulates a request as an object, thereby allowing users to parameterize clients with queues, requests, and operations.

   - Example:

     public interface Command {
         void execute();
     }

     public class Light {
         public void on() {
             System.out.println("Light is ON");
         }

         public void off() {
             System.out.println("Light is OFF");
         }
     }

     public class LightOnCommand implements Command {
         private Light light;

         public LightOnCommand(Light light) {
             this.light = light;
         }

         public void execute() {
             light.on();
         }
     }

     public class LightOffCommand implements Command {
         private Light light;

         public LightOffCommand(Light light) {
             this.light = light;
         }

         public void execute() {
             light.off();
         }
     }

     public class RemoteControl {
         private Command command;

         public void setCommand(Command command) {
             this.command = command;
         }

         public void pressButton() {
             command.execute();
         }
     }

     public class Client {
         public static void main(String[] args) {
             Light light = new Light();
             Command lightOn = new LightOnCommand(light);
             Command lightOff = new LightOffCommand(light);

             RemoteControl remote = new RemoteControl();

             remote.setCommand(lightOn);
             remote.pressButton();

             remote.setCommand(lightOff);
             remote.pressButton();
         }
     }


4. State Pattern:

   - Allows an object to alter its behavior when its internal state changes. The object will appear to change its class.

   - Example:

     public interface State {
         void handle(Context context);
     }

     public class ConcreteStateA implements State {
         public void handle(Context context) {
             System.out.println("State A handling request.");
             context.setState(new ConcreteStateB());
         }
     }

     public class ConcreteStateB implements State {
         public void handle(Context context) {
             System.out.println("State B handling request.");
             context.setState(new ConcreteStateA());
         }
     }

     public class Context {
         private State state;

         public Context(State state) {
             this.state = state;
         }

         public void setState(State state) {
             this.state = state;
         }

         public void request() {
             state.handle(this);
         }
     }

     public class Client {
         public static void main(String[] args) {
             Context context = new Context(new ConcreteStateA());
             context.request();
             context.request();
         }
     }


5. Template Method Pattern:

   - Defines the skeleton of an algorithm in a method, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.

   - Example:

     public abstract class AbstractClass {
         public final void templateMethod() {
             primitiveOperation1();
             primitiveOperation2();
             concreteOperation();
         }
         protected abstract void primitiveOperation1();
         protected abstract void primitiveOperation2();

         private void concreteOperation() {
             System.out.println("Concrete operation");
         }
     }

     public class ConcreteClass extends AbstractClass {
         protected void primitiveOperation1() {
             System.out.println("Primitive operation 1");
         }

         protected void primitiveOperation2() {
             System.out.println("Primitive operation 2");
         }
     }

     public class Client {
         public static void main(String[] args) {
             AbstractClass abstractClass = new ConcreteClass();
             abstractClass.templateMethod();
         }
     }


These examples cover a range of design patterns across the three main categories. Each pattern provides a structured approach to solving common software design problems, promoting code reuse, and improving maintainability.

Nenhum comentário:

Postar um comentário

Internet of Things (IoT) and Embedded Systems

The  Internet of Things (IoT)  and  Embedded Systems  are interconnected technologies that play a pivotal role in modern digital innovation....