What Design Patterns Are Used in Wand Enhancer? A Technical Architecture Breakdown

Wand Enhancer implements eight core software design patterns—including MVVM, Command, Singleton, and Bridge—to separate UI concerns from business logic and ensure maintainable cross-platform patch management for the Wand client.

Wand Enhancer is an open-source patcher for the Wand desktop client that combines a WPF native interface with a modern Electron-based remote panel. Understanding what design patterns are used in Wand Enhancer reveals how the project maintains clean separation between platform-specific logic and UI components while handling complex ASAR file operations. The architecture deliberately applies classic software engineering patterns to create a modular, testable, and extensible codebase.

Model-View-ViewModel (MVVM) and Observer Patterns

The MVVM pattern forms the architectural backbone of the WPF desktop application, implemented through base classes in WandEnhancer/ReactiveUICore/ObservableObject.cs. This pattern separates the XAML views from the underlying business logic, enabling data-binding and testable UI code.

The Observer pattern enables this separation via INotifyPropertyChanged. When properties change in the ViewModel, the Observer implementation notifies the view to update automatically:

// Base implementation in ObservableObject.cs
public class ObservableObject : INotifyPropertyChanged {
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName) {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

ViewModel classes in WandEnhancer/View/MainWindow/ inherit from this base, exposing bindable properties that keep the UI synchronized with underlying data without tight coupling.

Command Pattern for UI Actions

User interactions are encapsulated using the Command pattern through RelayCommand.cs and AsyncRelayCommand.cs. This allows the XAML view to bind button clicks and menu actions to handlers without knowing the concrete implementation:

public class MainWindowVm : ObservableObject {
    public RelayCommand OpenSettingsCommand { get; }

    public MainWindowVm() {
        OpenSettingsCommand = new RelayCommand(_ => OpenSettings());
    }

    private void OpenSettings() {
        // Logic that opens the Settings popup
    }
}

By treating user actions as objects, the Command pattern enables the view to remain declarative while the ViewModel maintains all execution logic and state.

Singleton Pattern for Global Services

Configuration and localization services are managed as Singletons to ensure a single, globally accessible instance throughout the application lifecycle. The SettingsManager.cs and LocalizationManager.cs in Core/Services/ use lazy initialization:

public sealed class SettingsManager {
    private static readonly Lazy<SettingsManager> _instance = 
        new(() => new SettingsManager(), true);

    public static SettingsManager Instance => _instance.Value;

    private SettingsManager() { 
        /* load persisted settings */ 
    }
}

The true parameter passed to Lazy<T> enables thread-safety, ensuring that even if multiple threads access Instance simultaneously, only one instance is created.

Bridge Pattern for Cross-Process Communication

The Electron-based remote panel communicates with the native Wand client through the Bridge pattern. Defined in web-panel/bridge/src/websocket-codec.ts, this abstraction decouples the Electron main process from renderer scripts:

// Protocol definition in websocket-codec.ts
export interface BridgeMessage {
  op: string;
  data: unknown;
}

This well-defined IPC layer allows the remote web panel to exchange messages with the native client without either side knowing the other's implementation details, enabling independent evolution of the frontend and backend components.

Factory and Builder Patterns for Archive Management

ASAR file operations—critical for patch injection—are handled using Factory and Builder patterns. The AsarCreator.cs and AsarExtractor.cs classes in the AsarSharp namespace construct and read archives while hiding low-level file system complexity:

// AsarCreator.cs – Factory method for creating archives
public static void Create(string sourceDir, string outputAsar) {
    // Implementation hides low-level file system handling
    // Returns a constructed ASAR archive without exposing internals
}

This encapsulation allows the rest of the application to work with high-level archive operations without managing the intricate details of the ASAR format.

Strategy Pattern for Script Loading

The web-panel supports different runtime environments through the Strategy pattern. Files like web-panel/bridge/scripts/default/installed-apps-sync.js and the storage abstraction in web-panel/src/shared/storage.ts allow different script implementations—such as development mocks versus production scripts—to be swapped at runtime while presenting a uniform API to the rest of the panel.

Decorator Pattern for Data Conversion

WPF value converters extend functionality using a lightweight Decorator pattern. Classes like BaseBooleanConverter.cs and ToVisibilityConverter.cs in WandEnhancer/Converters/ wrap existing conversion logic to add behavior without modifying the original converter classes, enabling flexible data transformation for XAML bindings.

Summary

  • MVVM and Observer patterns in ObservableObject.cs provide clean separation between WPF UI and business logic through data-binding and property notification.
  • Command pattern via RelayCommand.cs encapsulates user actions as objects, keeping views declarative and ViewModels testable.
  • Singleton pattern in SettingsManager.cs ensures thread-safe, global access to configuration services using lazy initialization.
  • Bridge pattern in web-panel/bridge/src/websocket-codec.ts decouples the Electron main process from renderer scripts, enabling isolated IPC communication.
  • Factory/Builder patterns in AsarCreator.cs and AsarExtractor.cs abstract ASAR file construction and extraction, simplifying patch injection.
  • Strategy pattern allows runtime swapping of script implementations in the web panel while maintaining consistent interfaces.
  • Decorator pattern extends WPF converter functionality without altering original classes.

Frequently Asked Questions

Why does Wand Enhancer use MVVM instead of MVC for the WPF interface?

Wand Enhancer uses MVVM because it provides tighter integration with WPF's data-binding capabilities through INotifyPropertyChanged, allowing the ViewModel in WandEnhancer/View/MainWindow/ to act as a specialized model for the view while remaining independent of the UI framework. This separation enables automated UI testing and allows designers to work with XAML without touching C# code, whereas MVC typically requires more manual synchronization between controllers and views.

How does the Bridge pattern facilitate communication between the Electron panel and the native Wand client?

The Bridge pattern defines a protocol in web-panel/bridge/src/websocket-codec.ts that standardizes messages between the Electron main process and the renderer, creating an abstraction layer that prevents the web panel from depending on specific native implementation details. This decoupling allows the remote panel to communicate with the WPF backend through WebSocket messages without either component knowing the other's internal structure, making it possible to update the web interface independently of the native patcher.

Are the Singleton implementations in Wand Enhancer thread-safe for concurrent access?

Yes, both SettingsManager.cs and LocalizationManager.cs use Lazy<T> with the true parameter for thread-safety, ensuring that the singleton instance is created exactly once even if multiple threads simultaneously access the Instance property. This lazy initialization approach prevents race conditions during application startup while deferring object creation until first use.

Which design pattern handles the extraction and creation of ASAR archive files during patching?

The Factory and Builder patterns handle ASAR operations through AsarCreator.cs and AsarExtractor.cs, which encapsulate the complex file system logic required to construct and read ASAR archives. These classes present simple static methods like Create() to the rest of the application while internally managing the low-level byte manipulation and header construction specific to the ASAR format.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →