AICollection Help

Structural Patterns

Structural patterns are design patterns that ease the design by identifying a simple way to realize relationships between entities. They help ensure that if one part of a system changes, the entire system doesn't need to change. Here are some common structural patterns with examples in a generic language:

1. Adapter

Allows incompatible interfaces to work together by converting the interface of a class into another interface that a client expects.

// Target interface interface Target { func request() } // Adaptee class class Adaptee { func specificRequest() { // Implementation } } // Adapter class class Adapter: Target { var adaptee: Adaptee init(adaptee: Adaptee) { self.adaptee = adaptee } func request() { adaptee.specificRequest() } }

2. Bridge

Separates an object’s abstraction from its implementation so that the two can vary independently.

// Abstraction abstract class Shape { var color: Color init(color: Color) { self.color = color } abstract func applyColor() } // Implementor interface Color { func fill() } // Concrete Implementor class RedColor: Color { func fill() { // Fill with red color } } // Refined Abstraction class Circle: Shape { func applyColor() { color.fill() } }

3. Composite

Composes objects into tree structures to represent part-whole hierarchies, allowing clients to treat individual objects and compositions uniformly.

// Component interface Graphic { func draw() } // Leaf class Circle: Graphic { func draw() { // Draw circle } } // Composite class CompositeGraphic: Graphic { var graphics: [Graphic] = [] func add(graphic: Graphic) { graphics.append(graphic) } func remove(graphic: Graphic) { graphics.removeAll { $0 === graphic } } func draw() { for graphic in graphics { graphic.draw() } } }

4. Decorator

Adds additional responsibilities to an object dynamically, providing a flexible alternative to subclassing for extending functionality.

// Component interface Coffee { func cost() -> Double } // Concrete Component class SimpleCoffee: Coffee { func cost() -> Double { return 1.0 } } // Decorator abstract class CoffeeDecorator: Coffee { var decoratedCoffee: Coffee init(coffee: Coffee) { self.decoratedCoffee = coffee } func cost() -> Double { return decoratedCoffee.cost() } } // Concrete Decorator class MilkDecorator: CoffeeDecorator { func cost() -> Double { return super.cost() + 0.5 } }

5. Facade

Provides a simplified interface to a complex subsystem, making it easier to use.

class Facade { var subsystem1: Subsystem1 var subsystem2: Subsystem2 init() { self.subsystem1 = Subsystem1() self.subsystem2 = Subsystem2() } func operation() { subsystem1.operation1() subsystem2.operation2() } } class Subsystem1 { func operation1() { // Implementation } } class Subsystem2 { func operation2() { // Implementation } }

6. Flyweight

Reduces the cost of creating and manipulating a large number of similar objects by sharing common parts of the state between multiple objects.

class Flyweight { var intrinsicState: String init(intrinsicState: String) { self.intrinsicState = intrinsicState } func operation(extrinsicState: String) { // Use intrinsicState and extrinsicState } } class FlyweightFactory { var flyweights: [String: Flyweight] = [:] func getFlyweight(key: String) -> Flyweight { if flyweights[key] == nil { flyweights[key] = Flyweight(intrinsicState: key) } return flyweights[key]! } }

7. Proxy

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

// Subject interface interface Subject { func request() } // RealSubject class class RealSubject: Subject { func request() { // Implementation } } // Proxy class class Proxy: Subject { var realSubject: RealSubject? func request() { if realSubject == nil { realSubject = RealSubject() } realSubject?.request() } }

These patterns help in structuring code in a way that reduces complexity and increases flexibility and maintainability.

Last modified: 27 November 2024