Sobes.tech
Middle

Provide examples of structural design patterns.

sobes.tech AI

Answer from AI

  • Adapter: Converts the interface of a class into another interface that clients expect. Allows classes to work together that couldn't otherwise because of incompatible interfaces.

Example:

// Target interface
interface Target {
    void request();
}

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

// Adapter implementing the target interface and containing the adaptee object
class Adapter implements Target {
    private Adaptee adaptee;

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

    @Override
    public void request() {
        adaptee.specificRequest(); // Call to adaptee's specific request
    }
}
  • Bridge: Decouples an abstraction from its implementation so that the two can vary independently. Prevents a tight coupling between abstraction and implementation.

Example:

// Implementation interface
interface Implementor {
    void operationImpl();
}

// Concrete implementation A
class ConcreteImplementorA implements Implementor {
    @Override
    public void operationImpl() {
        System.out.println("Concrete Implementor A operation");
    }
}

// Abstraction containing a reference to an implementor
abstract class Abstraction {
    protected Implementor implementor;

    public Abstraction(Implementor implementor) {
        this.implementor = implementor;
    }

    public abstract void operation();
}

// Refined abstraction using the implementation
class RefinedAbstraction extends Abstraction {
    public RefinedAbstraction(Implementor implementor) {
        super(implementor);
    }

    @Override
    public void operation() {
        System.out.println("Refined Abstraction operation");
        implementor.operationImpl(); // Delegating call to implementation
    }
}
  • Composite: Allows grouping objects into tree structures and working with them as if they were individual objects. Provides a uniform interface to individual objects and compositions.

Example:

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

// Component - common interface for leaves and composites
interface Component {
    void operation();
}

// Leaf - end object in the structure
class Leaf implements Component {
    private String name;

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

    @Override
    public void operation() {
        System.out.println("Leaf " + name + " operation");
    }
}

// Composite - contains components
class Composite implements Component {
    private String name;
    private List<Component> children = new ArrayList<>();

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

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

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

    @Override
    public void operation() {
        System.out.println("Composite " + name + " operation:");
        for (Component child : children) {
            child.operation(); // Recursive call for child elements
        }
    }
}
  • Decorator: Dynamically adds responsibilities to objects. An alternative to inheritance for extending functionality.

Example:

// Component - base interface
interface Component {
    void operation();
}

// Concrete component
class ConcreteComponent implements Component {
    @Override
    public void operation() {
        System.out.println("Concrete Component operation");
    }
}

// Base decorator
abstract class Decorator implements Component {
    protected Component component;

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

    @Override
    public void operation() {
        component.operation(); // Call to base component's operation
    }
}

// Concrete decorator adding new functionality
class ConcreteDecoratorA extends Decorator {
    public ConcreteDecoratorA(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        super.operation();
        addedBehavior(); // Add new behavior
    }

    private void addedBehavior() {
        System.out.println("Added behavior from Decorator A");
    }
}
  • Facade: Provides a unified interface to a group of subsystems. Defines a simpler interface to a complex subsystem.

Example:

// Subsystem part 1
class SubsystemA {
    public void operationA() {
        System.out.println("Subsystem A operation");
    }
}

// Subsystem part 2
class SubsystemB {
    public void operationB() {
        System.out.println("Subsystem B operation");
    }
}

// Facade providing a simple interface
class Facade {
    private SubsystemA subsystemA;
    private SubsystemB subsystemB;

    public Facade() {
        subsystemA = new SubsystemA();
        subsystemB = new SubsystemB();
    }

    public void operation() {
        System.out.println("Facade operation:");
        subsystemA.operationA();
        subsystemB.operationB();
    }
}
  • Flyweight: Used for efficiently supporting a large number of small objects. Shares common state among objects to save memory.

Example:

import java.util.HashMap;
import java.util.Map;

// Flyweight interface
interface Flyweight {
    void operation(String extrinsicState);
}

// Concrete flyweight (shared state)
class ConcreteFlyweight implements Flyweight {
    private String intrinsicState; // Internal shared state

    public ConcreteFlyweight(String intrinsicState) {
        this.intrinsicState = intrinsicState;
    }

    @Override
    public void operation(String extrinsicState) { // External state (unique)
        System.out.println("Concrete Flyweight with intrinsic state: " + intrinsicState +
                           ", extrinsic state: " + extrinsicState);
    }
}

// Flyweight factory
class FlyweightFactory {
    private Map<String, Flyweight> flyweights = new HashMap<>();

    public Flyweight getFlyweight(String key) {
        if (!flyweights.containsKey(key)) {
            flyweights.put(key, new ConcreteFlyweight(key));
        }
        return flyweights.get(key);
    }
}
  • Proxy: Provides a surrogate or placeholder for another object to control access to it. Can perform tasks like lazy initialization, access control, logging.

Example:

// Subject interface
interface Subject {
    void request();
}

// Real subject
class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("Real Subject handling request");
    }
}

// Proxy
class Proxy implements Subject {
    private RealSubject realSubject;

    @Override
    public void request() {
        if (realSubject == null) {
            realSubject = new RealSubject(); // Lazy initialization
        }
        System.out.println("Proxy handling request before Real Subject");
        realSubject.request();
        System.out.println("Proxy handling request after Real Subject");
    }
}
Provide examples of structural design patterns. — Java - sobes.tech