0Pricing
PHP Academy · บทเรียน

รูปแบบโครงสร้าง: 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. หลักการ SOLID ในการใช้งานจริง
  2. รูปแบบการสร้าง: Factory, Builder, Singleton
  3. รูปแบบโครงสร้าง: Adapter, Decorator, Facade
  4. รูปแบบพฤติกรรม: Strategy, Observer, Command
← กลับไปที่ PHP Academy