Structural patterns: Adapter, Decorator, Facade
Sammensæt objekter, og forenkl interfaces med structural patterns.
Structural patterns: Adapter, Decorator, Facade er en gratis PHP Academy-lektion på CoddyKit. Dette er lektion 3 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i PHP Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. PHP Academy-kurset indeholder 4 lektioner i alt.
Sammensætning af objekter
Strukturelle mønstre beskriver, hvordan du kan sammensætte klasser og objekter til større strukturer og samtidig bevare fleksibiliteten. Vi gennemgår tre centrale mønstre:
- Adapter — gør en inkompatibel grænseflade anvendelig.
- Decorator — tilføjer adfærd uden underklassificering.
- Facade — præsenterer en enkel indgang til et komplekst delsystem.
Adapter: problemet
Du er afhængig af en PaymentGateway-grænseflade, men et SDK fra en tredjepart eksponerer chargeCard($amountInCents) med en anden form. Hvis du kalder SDK'et direkte, spredes dets API overalt. Nedenfor er de to grænseflader tydeligt inkompatible — netop denne uoverensstemmelse løser en adapter.
<?php
// What our app wants to depend on
interface PaymentGateway { public function pay(float $dollars): string; }
// What the vendor actually gives us (cents, array result)
final class StripeSdk {
public function chargeCard(int $cents): array {
return ['id' => 'ch_1', 'amount' => $cents];
}
}
// dollars vs cents, string vs array -> shapes don't line up
var_dump((new StripeSdk())->chargeCard(2000));
Adapter i kode
Adapteren holder det tilpassede objekt og implementerer din målgrænseflade, mens den konverterer argumenter og returværdier. Din applikationskode forbliver ren og uafhængig af leverandøren.
<?php
interface PaymentGateway { public function pay(float $dollars): string; }
// Third-party SDK with an incompatible API
final class StripeSdk {
public function chargeCard(int $cents): array {
return ['id' => 'ch_1', 'amount' => $cents];
}
}
final class StripeAdapter implements PaymentGateway {
public function __construct(private StripeSdk $sdk) {}
public function pay(float $dollars): string {
$res = $this->sdk->chargeCard((int) round($dollars * 100));
return "charged {$res['amount']}c -> {$res['id']}";
}
}
echo (new StripeAdapter(new StripeSdk()))->pay(20.0), PHP_EOL;
Decorator: idéen
En Decorator omkranser et objekt, der deler dens grænseflade, og tilføjer adfærd før eller efter videredelegeringen. I modsætning til arv kan decorators stables under kørsel, så du kan kombinere funktioner i vilkårlig rækkefølge uden en eksplosion af klasser. Her er den minimale grundstruktur: et omslag, der implementerer den samme grænseflade og holder den indre instans.
<?php
interface Coffee { public function cost(): float; }
final class Espresso implements Coffee {
public function cost(): float { return 2.0; }
}
final class WithMilk implements Coffee {
public function __construct(private Coffee $inner) {}
public function cost(): float { return $this->inner->cost() + 0.5; }
}
echo (new WithMilk(new Espresso()))->cost(), PHP_EOL; // 2.5
Decorator i kode
Hver decorator implementerer den samme grænseflade og holder en indre instans. Her omkranser vi en datakilde med caching og logning, som vi frit kan sammensætte.
<?php
interface DataSource { public function read(): string; }
final class FileSource implements DataSource {
public function read(): string { return 'raw-data'; }
}
final class UpperCaseDecorator implements DataSource {
public function __construct(private DataSource $inner) {}
public function read(): string { return strtoupper($this->inner->read()); }
}
final class ExclaimDecorator implements DataSource {
public function __construct(private DataSource $inner) {}
public function read(): string { return $this->inner->read() . '!!!'; }
}
$src = new ExclaimDecorator(new UpperCaseDecorator(new FileSource()));
echo $src->read(), PHP_EOL; // RAW-DATA!!!
Decorators i praksis
PSR-7-/PSR-15-middleware er i praksis decorator-mønsteret anvendt på HTTP-håndtering: Hver middleware omkranser den næste og tilføjer autentificering, logning eller caching omkring forespørgslen og svaret. Stream-omslag og PSR-6/16-cachelag bruger også ofte dekorering. Den afgørende egenskab er: omslaget kan bruges i stedet for det, det omkranser.
Decorator kontra arv
Arv fastlåser adfærden ved kompilering og tillader kun én basisklasse. Dekorering er dynamisk og kan sammensættes. Vælg decorators, når:
- kombinationerne af valgfrie funktioner vokser eksplosivt,
- adfærd skal kunne tilføjes eller fjernes under kørsel,
- du skal udvide en
final- eller tredjepartsklasse, som du ikke kan underklassificere.
Facade: idéen
En Facade tilbyder en enkelt, forenklet indgang til et komplekst delsystem med mange klasser. Den skjuler ikke delsystemet (du kan stadig tilgå det direkte), men tilbyder en praktisk API på højt niveau til det almindelige tilfælde. Sammenlign den omstændelige arbejdsgang gennem delsystemet nedenfor med facade-kaldet på én linje i den næste scene.
<?php
// Without a facade, the client wires every step itself
final class Cpu { public function boot(): string { return 'cpu '; } }
final class Disk { public function load(): string { return 'disk '; } }
final class Ram { public function check(): string { return 'ram'; } }
$out = (new Cpu())->boot() . (new Disk())->load() . (new Ram())->check();
echo $out, PHP_EOL; // cpu disk ram
Facade i kode
Facaden koordinerer flere samarbejdende objekter bag én metode. Klienter kalder place() i stedet for selv at forbinde lager, betaling og forsendelse.
<?php
final class Inventory { public function reserve(string $sku): bool { return true; } }
final class Payments { public function charge(float $amt): bool { return true; } }
final class Shipping { public function dispatch(string $sku): string { return 'tracking-99'; } }
final class OrderFacade {
public function __construct(
private Inventory $inv,
private Payments $pay,
private Shipping $ship
) {}
public function place(string $sku, float $amount): string {
if (!$this->inv->reserve($sku)) { return 'out of stock'; }
if (!$this->pay->charge($amount)) { return 'payment failed'; }
return 'shipped: ' . $this->ship->dispatch($sku);
}
}
echo (new OrderFacade(new Inventory(), new Payments(), new Shipping()))
->place('ABC', 49.99), PHP_EOL;
Sådan skelner du mellem de tre
- Adapter ændrer en grænseflade, så to eksisterende dele kan tale sammen; samme adfærd, forskellig form.
- Decorator bevarer grænsefladen, men tilføjer adfærd, der kan stables under kørsel.
- Facade indfører en ny, enklere grænseflade foran mange klasser.
En nyttig tommelfingerregel er: Adapter handler om kompatibilitet, Decorator om udvidelse og Facade om forenkling.
Bemærkning om Laravel-facader
Laravels "facades" er en statisk proxy-mekanisme, der understøttes af servicecontaineren, ikke GoF-mønsteret Facade. De deler målet om en praktisk indgang, men adskiller sig i implementeringen. Bland ikke rammeværkets terminologi sammen med det strukturelle mønster, når du overvejer udformningen.
Hurtigt tjek
Identificér mønsteret ud fra dets formål.
Opsummering
Du sammensatte objekter med tre strukturelle mønstre: Adapter til at forbinde inkompatible grænseflader (f.eks. et leverandør-SDK), Decorator til at stable adfærd under kørsel (grundlaget for PSR-15-middleware) og Facade til at tilbyde en enkel indgang til et komplekst delsystem. Hvert mønster mindsker koblingen, så din kode modstår leverandørlåsning og funktionsoppustning.
Lær PHP med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 49
- Lektioner
- 195
Ofte stillede spørgsmål
Er lektionen “Structural patterns: Adapter, Decorator, Facade” gratis?
Ja — hele teksten til “Structural patterns: Adapter, Decorator, Facade” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af PHP Academy-kurset, skal du opgradere til CoddyKit PRO. PHP Academy-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “Structural patterns: Adapter, Decorator, Facade”?
Sammensæt objekter, og forenkl interfaces med structural patterns. Du øver dig i PHP Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på PHP Academy?
Der kræves ingen tidligere erfaring. PHP Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 3 af 4.
Hvor lang tid tager lektionen “Structural patterns: Adapter, Decorator, Facade”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne PHP Academy-lektion?
Ja. Alle PHP Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- SOLID-principper i praksis
- Creational patterns: Factory, Builder, Singleton
- Structural patterns: Adapter, Decorator, Facade
- Behavioral patterns: Strategy, Observer, Command