Table of Contents

Bridge Pattern API Reference

Complete API documentation for the Bridge pattern in PatternKit.

Namespace

using PatternKit.Structural.Bridge;

Bridge<TIn, TOut, TImpl>

Decouples abstraction from implementation with hooks and validation.

public sealed class Bridge<TIn, TOut, TImpl>

Type Parameters

Parameter Description
TIn Input type
TOut Output type
TImpl Implementation type

Delegates

public delegate TImpl Provider();
public delegate TImpl ProviderFrom(in TIn input);
public delegate TOut Operation(in TIn input, TImpl impl);
public delegate void Pre(in TIn input, TImpl impl);
public delegate TOut Post(in TIn input, TImpl impl, TOut result);
public delegate string? Validate(in TIn input, TImpl impl);
public delegate string? ValidateResult(in TIn input, TImpl impl, in TOut result);
Delegate Description
Provider Obtains implementation without input
ProviderFrom Obtains implementation based on input
Operation Core work using the implementation
Pre Before hook (preparation/logging)
Post After hook (can transform result)
Validate Pre-validation, returns error or null
ValidateResult Post-validation on result

Static Methods

Method Returns Description
Create(Provider provider) Builder Create with static provider
Create(ProviderFrom providerFrom) Builder Create with input-aware provider

Instance Methods

Method Returns Description
Execute(in TIn input) TOut Execute, throws on validation failure
TryExecute(in TIn input, out TOut output, out string? error) bool Safe execution

Exceptions

Method Exception Condition
Execute InvalidOperationException Validation fails
Build InvalidOperationException Operation not configured

Bridge<TIn, TOut, TImpl>.Builder

Builder for configuring the bridge.

public sealed class Builder

Methods

Method Returns Description
Operation(Operation op) Builder Set the core operation (required)
Before(Pre hook) Builder Add before hook
After(Post hook) Builder Add after hook
Require(Validate v) Builder Add pre-validation
RequireResult(ValidateResult v) Builder Add post-validation
Build() Bridge<TIn, TOut, TImpl> Build immutable bridge

Semantics

  • Operation required: Must be set before Build()
  • Hooks ordered: Before/After run in registration order
  • First failure wins: Validators short-circuit on first error
  • Post can transform: After hooks receive and return TOut

Execution Flow

sequenceDiagram
    participant C as Caller
    participant B as Bridge
    participant P as Provider
    participant V as Validators
    participant H as Hooks
    participant O as Operation

    C->>B: Execute(input)
    B->>P: Get implementation
    P-->>B: TImpl

    loop Each Require
        B->>V: Validate(input, impl)
        alt Returns error
            V-->>B: Error message
            B-->>C: Throw/Return false
        end
    end

    loop Each Before
        B->>H: Pre(input, impl)
    end

    B->>O: Operation(input, impl)
    O-->>B: Result

    loop Each After
        B->>H: Post(input, impl, result)
        H-->>B: Transformed result
    end

    loop Each RequireResult
        B->>V: ValidateResult(input, impl, result)
        alt Returns error
            V-->>B: Error message
            B-->>C: Throw/Return false
        end
    end

    B-->>C: Return result

Thread Safety

Component Thread-Safe
Builder No - single-threaded configuration
Bridge<TIn, TOut, TImpl> Yes - immutable after build
Execute Yes - but TImpl must be thread-safe if shared
TryExecute Yes - but TImpl must be thread-safe if shared

Implementation Notes

  • Delegates compiled to arrays at Build() time
  • in parameters avoid struct copies
  • No LINQ or reflection in execution path
  • TryExecute catches and returns exceptions as errors

Complete Example

using PatternKit.Structural.Bridge;

// Define types
public record DocumentRequest(string Content, string Format, string? Template = null);
public record Document(string Content, string MimeType, byte[] Data);

public interface IDocumentRenderer
{
    string Name { get; }
    bool CanRender(string format);
    byte[] Render(string content, string? template);
    string GetMimeType();
}

// Create bridge
public class DocumentBridge
{
    private readonly Bridge<DocumentRequest, Document, IDocumentRenderer> _bridge;

    public DocumentBridge(IRendererFactory factory)
    {
        _bridge = Bridge<DocumentRequest, Document, IDocumentRenderer>
            .Create((in DocumentRequest r) => factory.GetRenderer(r.Format))
            // Pre-validation
            .Require(static (in DocumentRequest r, IDocumentRenderer _) =>
                string.IsNullOrEmpty(r.Content) ? "Content required" : null)
            .Require(static (in DocumentRequest r, IDocumentRenderer renderer) =>
                !renderer.CanRender(r.Format) ? $"Cannot render {r.Format}" : null)
            // Before hooks
            .Before(static (in DocumentRequest r, IDocumentRenderer renderer) =>
                Console.WriteLine($"Rendering {r.Format} with {renderer.Name}"))
            // Core operation
            .Operation(static (in DocumentRequest r, IDocumentRenderer renderer) =>
                new Document(
                    Content: r.Content,
                    MimeType: renderer.GetMimeType(),
                    Data: renderer.Render(r.Content, r.Template)))
            // After hooks
            .After(static (in DocumentRequest r, IDocumentRenderer renderer, Document doc) =>
            {
                Console.WriteLine($"Rendered {doc.Data.Length} bytes");
                return doc;
            })
            // Post-validation
            .RequireResult(static (in DocumentRequest _, IDocumentRenderer __, in Document doc) =>
                doc.Data.Length > 10_000_000 ? "Document exceeds 10MB limit" : null)
            .Build();
    }

    public Document Render(DocumentRequest request) =>
        _bridge.Execute(request);

    public bool TryRender(DocumentRequest request, out Document? document, out string? error) =>
        _bridge.TryExecute(request, out document, out error);
}

// Usage
var bridge = new DocumentBridge(rendererFactory);

// Success case
var doc = bridge.Render(new DocumentRequest("<h1>Hello</h1>", "pdf"));

// With error handling
if (!bridge.TryRender(new DocumentRequest("", "pdf"), out var result, out var error))
{
    Console.WriteLine($"Failed: {error}");
}

Comparison with Other Patterns

Pattern When to Use
Bridge Separate abstraction from implementation with hooks
Adapter Convert one interface to another
Strategy Select algorithm by predicate
Factory Create instances by key

See Also