Magento 2 · Design Patterns

Strategy Pattern
in Magento 2

Das Strategy Pattern definiert eine Familie von Algorithmen, kapselt jeden einzelnen und macht sie austauschbar. In Magento 2 ist es überall zu finden: Steuerberechnung, Versandmethoden, Preisregeln, Bezahlmethoden — alle nutzen Strategy.

⏱ 11 Min. Lesezeit PHP 8.4 Magento 2.4.8

1. Das Strategy Pattern

Das Strategy Pattern (GoF) definiert eine Familie von Algorithmen hinter einem gemeinsamen Interface. Der Context kennt das Interface, nicht die konkrete Implementierung. Algorithmen können zur Laufzeit ausgetauscht werden:


// Strategy Interface
interface PriceCalculatorInterface
{
    public function calculate(float $basePrice, array $context): float;
}

// Konkrete Strategie 1
class StandardPriceCalculator implements PriceCalculatorInterface
{
    public function calculate(float $basePrice, array $context): float
    {
        return $basePrice;
    }
}

// Konkrete Strategie 2
class DiscountPriceCalculator implements PriceCalculatorInterface
{
    public function calculate(float $basePrice, array $context): float
    {
        $discount = $context['discount_percent'] ?? 0;
        return $basePrice * (1 - $discount / 100);
    }
}

// Context: nutzt Strategy ohne konkrete Implementierung zu kennen
class PriceContext
{
    public function __construct(
        private PriceCalculatorInterface $calculator
    ) {}

    public function getPrice(float $basePrice, array $context): float
    {
        return $this->calculator->calculate($basePrice, $context);
    }
}

2. Strategy in Magento 2: Wo es auftaucht

Das Strategy Pattern ist eines der am häufigsten verwendeten Patterns in Magento 2:

  • Tax CalculatorsTaxCalculatorInterface: verschiedene Steuerberechnungsalgorithmen (Row-based, Unit-based, Total-based)
  • Shipping MethodsAbstractCarrier: jede Versandmethode ist eine eigene Strategy
  • Payment MethodsMethodInterface: Kreditkarte, PayPal, Überweisung als austauschbare Strategies
  • Price Renderers — verschiedene Preisdarstellungen je Produkttyp
  • Search Adapters — MySQL vs Elasticsearch als austauschbare Such-Strategies

// Magento Tax Calculator Strategy (vereinfacht)
interface TaxCalculatorInterface
{
    /**
     * Calculate tax for the given item details.
     */
    public function calculateWithTaxInPrice(
        QuoteDetailsItemInterface $item,
        float $quantity,
        bool $round
    ): AppliedTaxRateInterface;
}

// Row-based Calculator — eine der Strategien
class RowBaseCalculator implements TaxCalculatorInterface
{
    public function calculateWithTaxInPrice(
        QuoteDetailsItemInterface $item,
        float $quantity,
        bool $round
    ): AppliedTaxRateInterface {
        // Steuerberechnung pro Zeile (Row)
        $price = $item->getUnitPrice() * $quantity;
        return $this->applyRates($price);
    }
}

3. Versandmethoden als Strategy

Versandmethoden sind das klarste Strategy-Beispiel in Magento 2. Jeder Carrier implementiert AbstractCarrier mit der collectRates()-Methode als Kernstrategie:


<?php
declare(strict_types=1);

namespace Mironsoft\Shipping\Model\Carrier;

use Magento\Quote\Model\Quote\Address\RateRequest;
use Magento\Quote\Model\Quote\Address\RateResult\ErrorFactory;
use Magento\Quote\Model\Quote\Address\RateResult\MethodFactory;
use Magento\Shipping\Model\Carrier\AbstractCarrier;
use Magento\Shipping\Model\Carrier\CarrierInterface;
use Magento\Shipping\Model\Rate\ResultFactory;

/**
 * Flat rate carrier strategy — returns fixed shipping rate.
 */
class FlatRate extends AbstractCarrier implements CarrierInterface
{
    protected string $_code = 'mironsoft_flatrate';

    public function __construct(
        private readonly ResultFactory $rateResultFactory,
        private readonly MethodFactory $rateMethodFactory,
        // Parent constructor parameters...
    ) {}

    /**
     * Collect shipping rates for this carrier strategy.
     */
    public function collectRates(RateRequest $request): ?\Magento\Shipping\Model\Rate\Result
    {
        if (!$this->getConfigFlag('active')) {
            return null;
        }

        $result = $this->rateResultFactory->create();
        $method = $this->rateMethodFactory->create();

        $method->setCarrier($this->_code);
        $method->setCarrierTitle($this->getConfigData('title'));
        $method->setMethod('standard');
        $method->setMethodTitle('Standard Shipping');
        $method->setPrice((float) $this->getConfigData('price'));

        $result->append($method);
        return $result;
    }

    public function getAllowedMethods(): array
    {
        return ['standard' => 'Standard Shipping'];
    }
}

4. Eigene Strategy implementieren

Ein praktisches Beispiel: verschiedene Export-Formate (CSV, XML, JSON) als austauschbare Strategies:


<?php
declare(strict_types=1);

namespace Mironsoft\Export\Api;

/**
 * Export formatter strategy interface.
 */
interface FormatterInterface
{
    /**
     * Format data array into export string.
     *
     * @param array<string, mixed> $data
     */
    public function format(array $data): string;

    public function getMimeType(): string;

    public function getFileExtension(): string;
}

<?php
declare(strict_types=1);

namespace Mironsoft\Export\Model\Formatter;

use Mironsoft\Export\Api\FormatterInterface;

/**
 * CSV export formatter strategy.
 */
class CsvFormatter implements FormatterInterface
{
    public function format(array $data): string
    {
        $output = '';
        foreach ($data as $row) {
            $output .= implode(',', array_map(
                fn($value) => '"' . str_replace('"', '""', (string) $value) . '"',
                $row
            )) . "\n";
        }
        return $output;
    }

    public function getMimeType(): string { return 'text/csv'; }
    public function getFileExtension(): string { return 'csv'; }
}

5. Strategy mit DI und Pools

Magento 2 nutzt oft einen Pool (Array von Strategies) kombiniert mit DI, um Strategies konfigurierbar zu machen:


<?php
declare(strict_types=1);

namespace Mironsoft\Export\Model;

use Mironsoft\Export\Api\FormatterInterface;

/**
 * Export service — uses strategy pool for format selection.
 */
class ExportService
{
    /** @param FormatterInterface[] $formatters */
    public function __construct(
        private readonly array $formatters
    ) {}

    public function export(array $data, string $format): string
    {
        $formatter = $this->formatters[$format]
            ?? throw new \InvalidArgumentException("Unknown format: $format");

        return $formatter->format($data);
    }

    /** @return string[] */
    public function getSupportedFormats(): array
    {
        return array_keys($this->formatters);
    }
}

<!-- di.xml: Strategy Pool konfigurieren -->
<type name="Mironsoft\Export\Model\ExportService">
    <arguments>
        <argument name="formatters" xsi:type="array">
            <item name="csv" xsi:type="object">Mironsoft\Export\Model\Formatter\CsvFormatter</item>
            <item name="xml" xsi:type="object">Mironsoft\Export\Model\Formatter\XmlFormatter</item>
            <item name="json" xsi:type="object">Mironsoft\Export\Model\Formatter\JsonFormatter</item>
        </argument>
    </arguments>
</type>

Mironsoft

Magento 2 Modulentwicklung & Architektur

Strategy Pattern für dein Magento 2 Projekt?

Wir entwickeln erweiterbare Magento 2 Module mit Strategy-Pool-Architektur — konfigurierbar über di.xml, testbar und ohne Core-Anpassungen. Shipping, Payment, Export und mehr.

Custom Carrier

Eigene Versandmethoden mit AbstractCarrier und Strategy-Architektur

Strategy Pools

Erweiterbare Algorithmen-Pools via di.xml — kein Core-Hacking

Interface Design

Service Contracts und Strategy Interfaces für upgrade-sichere Erweiterbarkeit

6. Zusammenfassung

Das Strategy Pattern ist eines der meistgenutzten GoF-Pattern in Magento 2. Es macht Algorithmen austauschbar ohne den Context-Code zu ändern. In Magento wird es durch DI-Pools in di.xml konfigurierbar — neue Strategien werden durch neue Klassen und di.xml-Einträge hinzugefügt, nicht durch Core-Änderungen.

Strategy Pattern — Das Wichtigste auf einen Blick

Strategy Interface

Gemeinsames Interface für alle Algorithmen. Context kennt nur das Interface. Concrete Strategies implementieren es — austauschbar ohne Context-Änderung.

Magento-Beispiele

Tax Calculators, Shipping Carriers, Payment Methods, Search Adapters. Alle folgen demselben Pattern: Interface + konkrete Implementierungen.

Strategy Pool via di.xml

argument name="strategies" xsi:type="array" — erweiterbar ohne Code-Änderung. Neue Strategy: neue Klasse + di.xml-Eintrag.

Strategy vs. Plugin

Plugins erweitern/überschreiben vorhandene Logik. Strategy ersetzt den gesamten Algorithmus. Für komplett andere Berechnungslogik: Strategy. Für Anpassung: Plugin.

7. FAQ: Strategy Pattern in Magento 2

1 Was ist das Strategy Pattern?
Familie von Algorithmen hinter einem gemeinsamen Interface. Context kennt nur das Interface — Algorithmen sind zur Laufzeit austauschbar. Neues Verhalten: neue Klasse, kein Context-Code ändern.
2 Wo verwendet Magento 2 Strategy?
Tax Calculators, Shipping Carriers, Payment Methods, Search Adapters, Price Renderers, Import/Export Handler. Das meistgenutzte GoF-Pattern in Magento 2.
3 Wie erstelle ich eine eigene Versandmethode?
AbstractCarrier extends + CarrierInterface implements. collectRates() ist die Strategy-Methode. In etc/config.xml registrieren. In system.xml Admin-Konfiguration.
4 Wie implementiert man einen Strategy Pool?
Interface definieren, konkrete Klassen implementieren. Service bekommt $strategies als Array per Constructor Injection. In di.xml als Array-Argument konfigurieren. Neue Strategy: neue Klasse + di.xml-Eintrag.
5 Wann Strategy statt Plugin?
Strategy = Algorithmus komplett ersetzen. Plugin = Methode modifizieren/erweitern. Für komplett andere Berechnungslogik: Strategy. Für Anpassung vorhandener Logik: Plugin.
6 Wie kann ich eine Magento-Strategy überschreiben?
Vollständige Ersetzung: preference in di.xml. Modifikation: Plugin auf die Strategy-Klasse. Eigene neue Implementierung registrieren ist oft stabiler als vorhandene zu überschreiben.
7 Wie testet man Strategy-Klassen?
Sehr einfach: konkrete Strategies direkt instanziieren und die Algorithmus-Methode mit bekannten Inputs testen. Interface mocken für Context-Tests. Strategy-Pattern macht Code durch Trennbarkeit sehr gut testbar.
8 Strategy vs. Template Method Pattern?
Template Method: Algorithmus-Skelett in Basisklasse, Hooks via Vererbung. Strategy: komplett austauschbares Objekt via Komposition. Magento nutzt beide — AbstractCarrier ist Template Method, Carrier-Pool ist Strategy.
9 Wie wählt Magento die richtige Tax-Strategy?
Über Admin-Konfiguration: Stores > Tax > Tax Calculation Method Based On. Der TaxCalculationService bekommt die gewählte Calculator-Strategie per DI injiziert.
10 Ist Strategy dasselbe wie Dependency Injection?
Verwandt, aber unterschiedlich. DI ist der Mechanismus. Strategy ist das Pattern. In Magento 2 wird DI genutzt um Strategy-Objekte zu injizieren — DI Pools (di.xml Arrays) machen Strategy-Wechsel ohne Code-Änderung möglich.