รูปแบบโครงสร้าง: Adapter, Decorator, Facade
ประกอบออบเจ็กต์และทำให้อินเทอร์เฟซเรียบง่ายด้วยรูปแบบโครงสร้าง
รูปแบบโครงสร้าง: Adapter, Decorator, Facade เป็นบทเรียน PHP Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน PHP Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส PHP Academy มีบทเรียนทั้งหมด 4 บทเรียน
การประกอบอ็อบเจกต์
รูปแบบโครงสร้างอธิบายวิธีประกอบคลาสและอ็อบเจกต์เป็นโครงสร้างขนาดใหญ่ขึ้นโดยยังคงความยืดหยุ่น เราจะครอบคลุมสามรูปแบบหลัก:
- อะแดปเตอร์ — ทำให้อินเทอร์เฟซที่เข้ากันไม่ได้สามารถใช้งานได้
- เดคอเรเตอร์ — เพิ่มพฤติกรรมโดยไม่สร้างคลาสย่อย
- ฟาซาด — นำเสนอจุดเชื่อมต่อที่เรียบง่ายให้กับระบบย่อยที่ซับซ้อน
อะแดปเตอร์: ปัญหา
คุณพึ่งพาอินเทอร์เฟซ PaymentGateway แต่ชุดพัฒนาซอฟต์แวร์จากผู้ให้บริการภายนอกเปิดเผย chargeCard($amountInCents) ที่มีรูปแบบแตกต่างกัน หากเรียกใช้ชุดพัฒนาซอฟต์แวร์โดยตรง ส่วนติดต่อของมันจะรั่วไหลไปทั่วทั้งโค้ด ด้านล่าง อินเทอร์เฟซทั้งสองเข้ากันไม่ได้อย่างชัดเจน ความไม่ตรงกันนี้คือสิ่งที่อะแดปเตอร์เข้ามาแก้ไข
<?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));
อะแดปเตอร์ในโค้ด
อะแดปเตอร์ถือครองอ็อบเจกต์ที่ถูกปรับให้เข้ากัน และใช้อินเทอร์เฟซเป้าหมาย โดยแปลงอาร์กิวเมนต์และค่าที่ส่งคืน โค้ดแอปพลิเคชันของคุณจึงสะอาดและไม่ผูกติดกับผู้จำหน่าย
<?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;
เดคอเรเตอร์: แนวคิด
เดคอเรเตอร์ห่อหุ้มอ็อบเจกต์ที่ใช้อินเทอร์เฟซเดียวกัน และเพิ่มพฤติกรรมก่อนหรือหลังการส่งต่อการทำงาน ต่างจากการสืบทอด เดคอเรเตอร์สามารถซ้อนกันขณะทำงานได้ ทำให้คุณรวมคุณลักษณะต่าง ๆ ได้ตามลำดับที่ต้องการโดยไม่ทำให้จำนวนคลาสเพิ่มขึ้นอย่างควบคุมไม่ได้ นี่คือโครงร่างพื้นฐานที่สุด: ตัวห่อหุ้มที่ใช้อินเทอร์เฟซเดียวกันและถือครองอินสแตนซ์ด้านใน
<?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
เดคอเรเตอร์ในโค้ด
เดคอเรเตอร์แต่ละตัวใช้อินเทอร์เฟซเดียวกันและถือครองอินสแตนซ์ด้านใน ที่นี่เราห่อหุ้มแหล่งข้อมูลด้วยการเก็บแคชและการบันทึกเหตุการณ์ แล้วประกอบทั้งสองอย่างได้อย่างอิสระ
<?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!!!
เดคอเรเตอร์ในโลกจริง
มิดเดิลแวร์ PSR-7 / PSR-15 คือการประยุกต์ใช้รูปแบบเดคอเรเตอร์กับการจัดการคำขอเอชทีทีพีโดยพื้นฐาน มิดเดิลแวร์แต่ละตัวห่อหุ้มตัวถัดไปเพื่อเพิ่มการยืนยันตัวตน การบันทึกเหตุการณ์ หรือการแคชรอบคำขอและการตอบกลับ ตัวห่อหุ้มสตรีมและชั้นแคช PSR-6/16 ก็มักใช้การตกแต่งเช่นกัน ลักษณะสำคัญคือตัวห่อหุ้มสามารถใช้แทนสิ่งที่มันห่อหุ้มได้
เดคอเรเตอร์กับการสืบทอด
การสืบทอดกำหนดพฤติกรรมไว้ตั้งแต่เวลาคอมไพล์และอนุญาตให้มีฐานได้เพียงหนึ่งฐาน ส่วนการตกแต่งมีความเป็นไดนามิกและประกอบร่วมกันได้ ควรเลือกใช้เดคอเรเตอร์เมื่อ:
- การผสมคุณลักษณะเสริมมีจำนวนเพิ่มขึ้นอย่างมาก
- ควรเพิ่มหรือลบพฤติกรรมขณะทำงาน
- คุณต้องขยายคลาส
finalหรือคลาสจากผู้ให้บริการภายนอกที่ไม่สามารถสร้างคลาสย่อยได้
ฟาซาด: แนวคิด
ฟาซาดจัดเตรียมจุดเข้าใช้งานเดียวที่เรียบง่ายให้กับระบบย่อยซับซ้อนซึ่งประกอบด้วยหลายคลาส ฟาซาดไม่ได้ซ่อนระบบย่อยนั้น (คุณยังเข้าถึงส่วนภายในได้) แต่มีส่วนติดต่อระดับสูงที่สะดวกสำหรับกรณีทั่วไป ลองเปรียบเทียบขั้นตอนอันยุ่งยากของระบบย่อยด้านล่างกับการเรียกใช้ฟาซาดเพียงบรรทัดเดียวในฉากถัดไป
<?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
ฟาซาดในโค้ด
ฟาซาดประสานงานอ็อบเจกต์ที่ทำงานร่วมกันหลายตัวไว้เบื้องหลังเมธอดเดียว ผู้ใช้เรียก place() แทนการเชื่อมต่อสินค้าคงคลัง การชำระเงิน และการจัดส่งด้วยตนเอง
<?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;
การแยกความแตกต่างของทั้งสามรูปแบบ
- อะแดปเตอร์เปลี่ยนอินเทอร์เฟซเพื่อให้ส่วนประกอบเดิมสองส่วนสื่อสารกันได้ พฤติกรรมเหมือนเดิมแต่รูปแบบต่างกัน
- เดคอเรเตอร์คงอินเทอร์เฟซเดิมไว้แต่เพิ่มพฤติกรรม และสามารถซ้อนกันขณะทำงานได้
- ฟาซาดสร้างอินเทอร์เฟซใหม่ที่เรียบง่ายกว่าไว้ด้านหน้าของหลายคลาส
วิธีจำที่เป็นประโยชน์คือ อะแดปเตอร์เกี่ยวกับความเข้ากันได้ เดคอเรเตอร์เกี่ยวกับการเพิ่มความสามารถ และฟาซาดเกี่ยวกับการทำให้ง่ายขึ้น
หมายเหตุเกี่ยวกับฟาซาดของลาราเวล
"ฟาซาด" ของลาราเวลเป็นกลไกพร็อกซีแบบสแตติกที่มีคอนเทนเนอร์บริการรองรับ ไม่ใช่รูปแบบฟาซาดของแก๊งออฟโฟร์ ทั้งสองมีเป้าหมายร่วมกันคือการจัดเตรียมจุดเชื่อมต่อด้านหน้าที่สะดวก แต่มีวิธีนำไปใช้งานแตกต่างกัน อย่านำคำศัพท์ของกรอบงานมาปะปนกับรูปแบบโครงสร้างเมื่อต้องพิจารณาการออกแบบ
ตรวจสอบอย่างรวดเร็ว
ระบุรูปแบบจากเจตนาของรูปแบบนั้น
สรุป
คุณประกอบอ็อบเจกต์ด้วยรูปแบบโครงสร้างสามรูปแบบ ได้แก่ อะแดปเตอร์เพื่อเชื่อมอินเทอร์เฟซที่เข้ากันไม่ได้ (เช่น ชุดพัฒนาซอฟต์แวร์ของผู้จำหน่าย) เดคอเรเตอร์เพื่อซ้อนพฤติกรรมขณะทำงาน (เป็นพื้นฐานของมิดเดิลแวร์ PSR-15) และฟาซาดเพื่อสร้างจุดเชื่อมต่อที่เรียบง่ายให้กับระบบย่อยที่ซับซ้อน แต่ละรูปแบบช่วยลดการผูกติด ทำให้โค้ดของคุณต้านทานการผูกติดกับผู้จำหน่ายและการเพิ่มคุณลักษณะที่มากเกินไป
คำถามที่พบบ่อย
บทเรียน “รูปแบบโครงสร้าง: Adapter, Decorator, Facade” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “รูปแบบโครงสร้าง: Adapter, Decorator, Facade” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส PHP Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส PHP Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “รูปแบบโครงสร้าง: Adapter, Decorator, Facade”
ประกอบออบเจ็กต์และทำให้อินเทอร์เฟซเรียบง่ายด้วยรูปแบบโครงสร้าง คุณปฏิบัติ PHP Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน PHP Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน PHP Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “รูปแบบโครงสร้าง: Adapter, Decorator, Facade” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน PHP Academy นี้ได้ไหม
ได้ บทเรียน PHP Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- หลักการ SOLID ในการใช้งานจริง
- รูปแบบการสร้าง: Factory, Builder, Singleton
- รูปแบบโครงสร้าง: Adapter, Decorator, Facade
- รูปแบบพฤติกรรม: Strategy, Observer, Command