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.
Inhaltsverzeichnis
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 Calculators —
TaxCalculatorInterface: verschiedene Steuerberechnungsalgorithmen (Row-based, Unit-based, Total-based) - Shipping Methods —
AbstractCarrier: jede Versandmethode ist eine eigene Strategy - Payment Methods —
MethodInterface: 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?
2 Wo verwendet Magento 2 Strategy?
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?
$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?
6 Wie kann ich eine Magento-Strategy überschreiben?
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?
8 Strategy vs. Template Method Pattern?
AbstractCarrier ist Template Method, Carrier-Pool ist Strategy.9 Wie wählt Magento die richtige Tax-Strategy?
TaxCalculationService bekommt die gewählte Calculator-Strategie per DI injiziert.