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");
}
}