ไทย

เชี่ยวชาญ JavaScript design patterns ด้วยคู่มือฉบับสมบูรณ์ของเรา เรียนรู้รูปแบบ creational, structural, และ behavioral พร้อมตัวอย่างโค้ดที่ใช้งานได้จริง

JavaScript Design Patterns: คู่มือการนำไปใช้งานฉบับสมบูรณ์สำหรับนักพัฒนายุคใหม่

บทนำ: พิมพ์เขียวสำหรับโค้ดที่แข็งแกร่ง

ในโลกของการพัฒนาซอฟต์แวร์ที่มีการเปลี่ยนแปลงอยู่เสมอ การเขียนโค้ดที่แค่ทำงานได้เป็นเพียงก้าวแรกเท่านั้น ความท้าทายที่แท้จริงและเป็นเครื่องหมายของนักพัฒนามืออาชีพ คือการสร้างโค้ดที่สามารถขยายขนาด (scalable), บำรุงรักษาได้ (maintainable) และง่ายต่อการทำความเข้าใจและทำงานร่วมกันของผู้อื่น นี่คือจุดที่ design patterns เข้ามามีบทบาท มันไม่ใช่ thuật toán หรือ library ที่เฉพาะเจาะจง แต่เป็นพิมพ์เขียวระดับสูงที่ไม่ขึ้นอยู่กับภาษาใดภาษาหนึ่ง สำหรับการแก้ปัญหาที่เกิดขึ้นซ้ำๆ ในสถาปัตยกรรมซอฟต์แวร์

สำหรับนักพัฒนา JavaScript การทำความเข้าใจและการประยุกต์ใช้ design patterns มีความสำคัญมากกว่าที่เคยเป็นมา เนื่องจากแอปพลิเคชันมีความซับซ้อนเพิ่มขึ้น ตั้งแต่ front-end framework ที่ซับซ้อนไปจนถึง backend service ที่ทรงพลังบน Node.js รากฐานทางสถาปัตยกรรมที่มั่นคงจึงเป็นสิ่งที่ขาดไม่ได้ Design patterns เป็นผู้มอบรากฐานนี้ โดยนำเสนอโซลูชันที่ผ่านการทดสอบมาแล้ว ซึ่งส่งเสริมการพึ่งพากันน้อย (loose coupling), การแบ่งแยกหน้าที่ (separation of concerns) และการนำโค้ดกลับมาใช้ใหม่ (code reusability)

คู่มือฉบับสมบูรณ์นี้จะพาคุณไปทำความรู้จักกับ design patterns ทั้งสามหมวดหมู่พื้นฐาน พร้อมคำอธิบายที่ชัดเจนและตัวอย่างการนำไปใช้งานด้วย JavaScript สมัยใหม่ (ES6+) ที่ใช้ได้จริง เป้าหมายของเราคือการมอบความรู้ให้คุณสามารถระบุได้ว่าควรใช้ pattern ใดสำหรับปัญหาที่กำหนด และจะนำไปใช้อย่างมีประสิทธิภาพในโปรเจกต์ของคุณได้อย่างไร

สามเสาหลักของ Design Patterns

โดยทั่วไป Design patterns จะถูกจัดแบ่งออกเป็นสามกลุ่มหลัก โดยแต่ละกลุ่มจะจัดการกับความท้าทายทางสถาปัตยกรรมที่แตกต่างกันไป:

เรามาเจาะลึกแต่ละหมวดหมู่พร้อมตัวอย่างที่ใช้งานได้จริงกัน


Creational Patterns: การสร้างอ็อบเจกต์อย่างเชี่ยวชาญ

Creational patterns นำเสนอกลไกการสร้างอ็อบเจกต์ที่หลากหลาย ซึ่งช่วยเพิ่มความยืดหยุ่นและการนำโค้ดที่มีอยู่กลับมาใช้ใหม่ ช่วยลดการผูกมัดของระบบกับวิธีการสร้าง, ประกอบ และแสดงผลอ็อบเจกต์

The Singleton Pattern

แนวคิด: Singleton pattern ทำให้แน่ใจว่าคลาสมีอินสแตนซ์เพียงหนึ่งเดียวและมีจุดเข้าถึงแบบ global เพียงจุดเดียว ไม่ว่าจะพยายามสร้างอินสแตนซ์ใหม่กี่ครั้ง ก็จะได้รับอินสแตนซ์เดิมกลับไปเสมอ

กรณีการใช้งานทั่วไป: รูปแบบนี้มีประโยชน์สำหรับการจัดการทรัพยากรหรือ state ที่ใช้ร่วมกัน ตัวอย่างเช่น database connection pool, ตัวจัดการการตั้งค่าส่วนกลาง (global configuration manager) หรือ logging service ที่ควรเป็นหนึ่งเดียวกันทั้งแอปพลิเคชัน

การนำไปใช้ใน JavaScript: JavaScript สมัยใหม่ โดยเฉพาะคลาสใน ES6 ทำให้การสร้าง Singleton เป็นเรื่องง่าย เราสามารถใช้ static property บนคลาสเพื่อเก็บอินสแตนซ์เดียวไว้ได้

ตัวอย่าง: Logger Service Singleton

class Logger { constructor() { if (Logger.instance) { return Logger.instance; } this.logs = []; Logger.instance = this; } log(message) { const timestamp = new Date().toISOString(); this.logs.push({ message, timestamp }); console.log(`${timestamp} - ${message}`); } getLogCount() { return this.logs.length; } } // แม้จะเรียกใช้ 'new' แต่ตรรกะใน constructor จะทำให้แน่ใจว่ามีเพียงอินสแตนซ์เดียว const logger1 = new Logger(); const logger2 = new Logger(); console.log("Are loggers the same instance?", logger1 === logger2); // true logger1.log("First message from logger1."); logger2.log("Second message from logger2."); console.log("Total logs:", logger1.getLogCount()); // 2

ข้อดีและข้อเสีย:

The Factory Pattern

แนวคิด: Factory pattern มีอินเทอร์เฟซสำหรับสร้างอ็อบเจกต์ใน superclass แต่ยอมให้ subclass เปลี่ยนแปลงประเภทของอ็อบเจกต์ที่จะถูกสร้างขึ้นได้ มันคือการใช้เมธอดหรือคลาส "factory" ที่ออกแบบมาโดยเฉพาะเพื่อสร้างอ็อบเจกต์โดยไม่ต้องระบุ concrete class ของมัน

กรณีการใช้งานทั่วไป: เมื่อคุณมีคลาสที่ไม่สามารถคาดเดาประเภทของอ็อบเจกต์ที่ต้องสร้างได้ หรือเมื่อคุณต้องการให้ผู้ใช้ library ของคุณสามารถสร้างอ็อบเจกต์ได้โดยไม่จำเป็นต้องรู้รายละเอียดการทำงานภายใน ตัวอย่างทั่วไปคือการสร้างผู้ใช้ประเภทต่างๆ (Admin, Member, Guest) ตามพารามิเตอร์

การนำไปใช้ใน JavaScript:

ตัวอย่าง: A User Factory

class RegularUser { constructor(name) { this.name = name; this.role = 'Regular'; } viewDashboard() { console.log(`${this.name} is viewing the user dashboard.`); } } class AdminUser { constructor(name) { this.name = name; this.role = 'Admin'; } viewDashboard() { console.log(`${this.name} is viewing the admin dashboard with full privileges.`); } } class UserFactory { static createUser(type, name) { switch (type.toLowerCase()) { case 'admin': return new AdminUser(name); case 'regular': return new RegularUser(name); default: throw new Error('Invalid user type specified.'); } } } const admin = UserFactory.createUser('admin', 'Alice'); const regularUser = UserFactory.createUser('regular', 'Bob'); admin.viewDashboard(); // Alice is viewing the admin dashboard... regularUser.viewDashboard(); // Bob is viewing the user dashboard. console.log(admin.role); // Admin console.log(regularUser.role); // Regular

ข้อดีและข้อเสีย:

The Prototype Pattern

แนวคิด: Prototype pattern คือการสร้างอ็อบเจกต์ใหม่โดยการคัดลอกอ็อบเจกต์ที่มีอยู่แล้ว ซึ่งเรียกว่า "prototype" แทนที่จะสร้างอ็อบเจกต์ตั้งแต่ต้น คุณจะสร้างโคลนของอ็อบเจกต์ที่กำหนดค่าไว้ล่วงหน้า นี่เป็นพื้นฐานของวิธีการทำงานของ JavaScript ผ่าน prototypal inheritance

กรณีการใช้งานทั่วไป: รูปแบบนี้มีประโยชน์เมื่อต้นทุนในการสร้างอ็อบเจกต์แพงหรือซับซ้อนกว่าการคัดลอกอ็อบเจกต์ที่มีอยู่ นอกจากนี้ยังใช้เพื่อสร้างอ็อบเจกต์ที่ประเภทถูกระบุในขณะ runtime

การนำไปใช้ใน JavaScript: JavaScript มีการสนับสนุนรูปแบบนี้ในตัวผ่าน `Object.create()`

ตัวอย่าง: Clonable Vehicle Prototype

const vehiclePrototype = { init: function(model) { this.model = model; }, getModel: function() { return `The model of this vehicle is ${this.model}`; } }; // สร้างอ็อบเจกต์รถยนต์ใหม่จาก vehicle prototype const car = Object.create(vehiclePrototype); car.init('Ford Mustang'); console.log(car.getModel()); // The model of this vehicle is Ford Mustang // สร้างอ็อบเจกต์อีกอัน เป็นรถบรรทุก const truck = Object.create(vehiclePrototype); truck.init('Tesla Cybertruck'); console.log(truck.getModel()); // The model of this vehicle is Tesla Cybertruck

ข้อดีและข้อเสีย:


Structural Patterns: การประกอบโค้ดอย่างชาญฉลาด

Structural patterns เกี่ยวข้องกับวิธีการรวมอ็อบเจกต์และคลาสเพื่อสร้างโครงสร้างที่ใหญ่และซับซ้อนขึ้น โดยเน้นการทำให้โครงสร้างง่ายขึ้นและระบุความสัมพันธ์

The Adapter Pattern

แนวคิด: Adapter pattern ทำหน้าที่เป็นสะพานเชื่อมระหว่างสองอินเทอร์เฟซที่เข้ากันไม่ได้ ประกอบด้วยคลาสเดียว (adapter) ที่เชื่อมต่อฟังก์ชันการทำงานของอินเทอร์เฟซที่ไม่ขึ้นต่อกันหรือเข้ากันไม่ได้ ลองนึกถึงอะแดปเตอร์ปลั๊กไฟที่ช่วยให้คุณเสียบอุปกรณ์ของคุณเข้ากับเต้ารับไฟฟ้าในต่างประเทศได้

กรณีการใช้งานทั่วไป: การรวม library ของบุคคลที่สามเข้ากับแอปพลิเคชันที่มีอยู่ที่คาดหวัง API ที่แตกต่างกัน หรือการทำให้ legacy code ทำงานกับระบบที่ทันสมัยโดยไม่ต้องเขียน legacy code ใหม่

การนำไปใช้ใน JavaScript:

ตัวอย่าง: การปรับ API ใหม่ให้เข้ากับอินเทอร์เฟซเก่า

// อินเทอร์เฟซเก่าที่แอปพลิเคชันของเราใช้งานอยู่ class OldCalculator { operation(term1, term2, operation) { switch (operation) { case 'add': return term1 + term2; case 'sub': return term1 - term2; default: return NaN; } } } // library ใหม่ที่มีอินเทอร์เฟซแตกต่างออกไป class NewCalculator { add(term1, term2) { return term1 + term2; } subtract(term1, term2) { return term1 - term2; } } // คลาส Adapter class CalculatorAdapter { constructor() { this.calculator = new NewCalculator(); } operation(term1, term2, operation) { switch (operation) { case 'add': // ปรับการเรียกใช้ให้เข้ากับอินเทอร์เฟซใหม่ return this.calculator.add(term1, term2); case 'sub': return this.calculator.subtract(term1, term2); default: return NaN; } } } // Client code สามารถใช้ adapter ได้ราวกับว่าเป็นเครื่องคิดเลขเก่า const oldCalc = new OldCalculator(); console.log("Old calculator result:", oldCalc.operation(10, 5, 'add')); // 15 const adaptedCalc = new CalculatorAdapter(); console.log("Adapted calculator result:", adaptedCalc.operation(10, 5, 'add')); // 15

ข้อดีและข้อเสีย:

The Decorator Pattern

แนวคิด: Decorator pattern ช่วยให้คุณสามารถเพิ่มพฤติกรรมหรือความรับผิดชอบใหม่ๆ ให้กับอ็อบเจกต์ได้แบบไดนามิกโดยไม่ต้องแก้ไขโค้ดดั้งเดิม ทำได้โดยการห่อหุ้มอ็อบเจกต์ดั้งเดิมด้วยอ็อบเจกต์ "decorator" พิเศษที่มีฟังก์ชันการทำงานใหม่

กรณีการใช้งานทั่วไป: การเพิ่มคุณสมบัติให้กับ UI component, การเพิ่มสิทธิ์ให้กับอ็อบเจกต์ผู้ใช้ หรือการเพิ่มพฤติกรรมการบันทึก/แคชให้กับ service เป็นทางเลือกที่ยืดหยุ่นแทนการทำ subclassing

การนำไปใช้ใน JavaScript: ฟังก์ชันเป็น first-class citizen ใน JavaScript ทำให้การสร้าง decorator เป็นเรื่องง่าย

ตัวอย่าง: การตกแต่งรายการสั่งกาแฟ

// ส่วนประกอบพื้นฐาน class SimpleCoffee { getCost() { return 10; } getDescription() { return 'Simple coffee'; } } // Decorator 1: นม function MilkDecorator(coffee) { const originalCost = coffee.getCost(); const originalDescription = coffee.getDescription(); coffee.getCost = function() { return originalCost + 2; }; coffee.getDescription = function() { return `${originalDescription}, with milk`; }; return coffee; } // Decorator 2: น้ำตาล function SugarDecorator(coffee) { const originalCost = coffee.getCost(); const originalDescription = coffee.getDescription(); coffee.getCost = function() { return originalCost + 1; }; coffee.getDescription = function() { return `${originalDescription}, with sugar`; }; return coffee; } // มาสร้างและตกแต่งกาแฟกัน let myCoffee = new SimpleCoffee(); console.log(myCoffee.getCost(), myCoffee.getDescription()); // 10, Simple coffee myCoffee = MilkDecorator(myCoffee); console.log(myCoffee.getCost(), myCoffee.getDescription()); // 12, Simple coffee, with milk myCoffee = SugarDecorator(myCoffee); console.log(myCoffee.getCost(), myCoffee.getDescription()); // 13, Simple coffee, with milk, with sugar

ข้อดีและข้อเสีย:

The Facade Pattern

แนวคิด: Facade pattern จัดเตรียมอินเทอร์เฟซระดับสูงที่เรียบง่ายให้กับระบบย่อยที่ซับซ้อนซึ่งประกอบด้วยคลาส, library หรือ API ต่างๆ ช่วยซ่อนความซับซ้อนที่อยู่เบื้องหลังและทำให้ระบบย่อยใช้งานง่ายขึ้น

กรณีการใช้งานทั่วไป: การสร้าง API ที่เรียบง่ายสำหรับชุดการทำงานที่ซับซ้อน เช่น กระบวนการชำระเงินใน e-commerce ที่เกี่ยวข้องกับระบบย่อยของสต็อกสินค้า, การชำระเงิน และการจัดส่ง อีกตัวอย่างหนึ่งคือเมธอดเดียวสำหรับเริ่มเว็บแอปพลิเคชันซึ่งภายในจะตั้งค่าเซิร์ฟเวอร์, ฐานข้อมูล และ middleware

การนำไปใช้ใน JavaScript:

ตัวอย่าง: A Mortgage Application Facade

// ระบบย่อยที่ซับซ้อน class BankService { verify(name, amount) { console.log(`Verifying sufficient funds for ${name} for amount ${amount}`); return amount < 100000; } } class CreditHistoryService { get(name) { console.log(`Checking credit history for ${name}`); // จำลองว่ามีคะแนนเครดิตดี return true; } } class BackgroundCheckService { run(name) { console.log(`Running background check for ${name}`); return true; } } // The Facade class MortgageFacade { constructor() { this.bank = new BankService(); this.credit = new CreditHistoryService(); this.background = new BackgroundCheckService(); } applyFor(name, amount) { console.log(`--- Applying for mortgage for ${name} ---`); const isEligible = this.bank.verify(name, amount) && this.credit.get(name) && this.background.run(name); const result = isEligible ? 'Approved' : 'Rejected'; console.log(`--- Application result for ${name}: ${result} ---\n`); return result; } } // Client code โต้ตอบกับ Facade ที่เรียบง่าย const mortgage = new MortgageFacade(); mortgage.applyFor('John Smith', 75000); // Approved mortgage.applyFor('Jane Doe', 150000); // Rejected

ข้อดีและข้อเสีย:


Behavioral Patterns: การควบคุมการสื่อสารของอ็อบเจกต์

Behavioral patterns เกี่ยวข้องกับวิธีที่อ็อบเจกต์สื่อสารกัน โดยเน้นการกำหนดความรับผิดชอบและการจัดการปฏิสัมพันธ์อย่างมีประสิทธิภาพ

The Observer Pattern

แนวคิด: Observer pattern กำหนดความสัมพันธ์แบบ one-to-many ระหว่างอ็อบเจกต์ เมื่ออ็อบเจกต์หนึ่ง (เรียกว่า "subject" หรือ "observable") เปลี่ยนสถานะ อ็อบเจกต์ทั้งหมดที่ขึ้นอยู่กับมัน (เรียกว่า "observers") จะได้รับการแจ้งเตือนและอัปเดตโดยอัตโนมัติ

กรณีการใช้งานทั่วไป: รูปแบบนี้เป็นรากฐานของการเขียนโปรแกรมเชิงเหตุการณ์ (event-driven programming) ใช้กันอย่างแพร่หลายในการพัฒนา UI (DOM event listeners), library การจัดการ state (เช่น Redux หรือ Vuex) และระบบส่งข้อความ

การนำไปใช้ใน JavaScript:

ตัวอย่าง: สำนักข่าวและผู้ติดตาม

// The Subject (Observable) class NewsAgency { constructor() { this.subscribers = []; } subscribe(subscriber) { this.subscribers.push(subscriber); console.log(`${subscriber.name} has subscribed.`); } unsubscribe(subscriber) { this.subscribers = this.subscribers.filter(sub => sub !== subscriber); console.log(`${subscriber.name} has unsubscribed.`); } notify(news) { console.log(`--- NEWS AGENCY: Broadcasting news: "${news}" ---`); this.subscribers.forEach(subscriber => subscriber.update(news)); } } // The Observer class Subscriber { constructor(name) { this.name = name; } update(news) { console.log(`${this.name} received the latest news: "${news}"`); } } const agency = new NewsAgency(); const sub1 = new Subscriber('Reader A'); const sub2 = new Subscriber('Reader B'); const sub3 = new Subscriber('Reader C'); agency.subscribe(sub1); agency.subscribe(sub2); agency.notify('Global markets are up!'); agency.subscribe(sub3); agency.unsubscribe(sub2); agency.notify('New tech breakthrough announced!');

ข้อดีและข้อเสีย:

The Strategy Pattern

แนวคิด: Strategy pattern กำหนดตระกูลของอัลกอริทึมที่สามารถสับเปลี่ยนกันได้ และห่อหุ้มแต่ละอัลกอริทึมไว้ในคลาสของตัวเอง ซึ่งช่วยให้อัลกอริทึมสามารถถูกเลือกและสลับได้ในขณะ runtime โดยไม่ขึ้นอยู่กับ client ที่ใช้งาน

กรณีการใช้งานทั่วไป: การ υλοποίηση อัลกอริทึมการเรียงลำดับที่แตกต่างกัน, กฎการตรวจสอบความถูกต้อง หรือวิธีการคำนวณค่าจัดส่งสำหรับเว็บไซต์ e-commerce (เช่น อัตราคงที่, ตามน้ำหนัก, ตามปลายทาง)

การนำไปใช้ใน JavaScript:

ตัวอย่าง: กลยุทธ์การคำนวณค่าจัดส่ง

// The Context class Shipping { constructor() { this.company = null; } setStrategy(company) { this.company = company; console.log(`Shipping strategy set to: ${company.constructor.name}`); } calculate(pkg) { if (!this.company) { throw new Error('Shipping strategy has not been set.'); } return this.company.calculate(pkg); } } // The Strategies class FedExStrategy { calculate(pkg) { // การคำนวณที่ซับซ้อนตามน้ำหนัก ฯลฯ const cost = pkg.weight * 2.5 + 5; console.log(`FedEx cost for package of ${pkg.weight}kg is $${cost}`); return cost; } } class UPSStrategy { calculate(pkg) { const cost = pkg.weight * 2.1 + 4; console.log(`UPS cost for package of ${pkg.weight}kg is $${cost}`); return cost; } } class PostalServiceStrategy { calculate(pkg) { const cost = pkg.weight * 1.8; console.log(`Postal Service cost for package of ${pkg.weight}kg is $${cost}`); return cost; } } const shipping = new Shipping(); const packageA = { from: 'New York', to: 'London', weight: 5 }; shipping.setStrategy(new FedExStrategy()); shipping.calculate(packageA); shipping.setStrategy(new UPSStrategy()); shipping.calculate(packageA); shipping.setStrategy(new PostalServiceStrategy()); shipping.calculate(packageA);

ข้อดีและข้อเสีย:


รูปแบบสมัยใหม่และข้อควรพิจารณาทางสถาปัตยกรรม

แม้ว่า design patterns แบบคลาสสิกจะอยู่เหนือกาลเวลา แต่ระบบนิเวศของ JavaScript ได้พัฒนาขึ้น ทำให้เกิดการตีความที่ทันสมัยและรูปแบบสถาปัตยกรรมขนาดใหญ่ซึ่งมีความสำคัญสำหรับนักพัฒนายุคปัจจุบัน

The Module Pattern

Module pattern เป็นหนึ่งในรูปแบบที่แพร่หลายที่สุดใน JavaScript ยุคก่อน ES6 สำหรับการสร้าง scope แบบ private และ public โดยใช้ closures เพื่อห่อหุ้ม state และ behavior ปัจจุบัน รูปแบบนี้ถูกแทนที่โดย ES6 Modules (`import`/`export`) ซึ่งเป็นระบบโมดูลมาตรฐานแบบไฟล์ การทำความเข้าใจ ES6 modules เป็นพื้นฐานสำหรับนักพัฒนา JavaScript สมัยใหม่ทุกคน เนื่องจากเป็นมาตรฐานสำหรับการจัดระเบียบโค้ดทั้งในแอปพลิเคชันฝั่ง front-end และ back-end

Architectural Patterns (MVC, MVVM)

สิ่งสำคัญคือต้องแยกความแตกต่างระหว่าง design patterns และ architectural patterns ในขณะที่ design patterns แก้ปัญหาเฉพาะจุด แต่ architectural patterns จะให้โครงสร้างระดับสูงสำหรับทั้งแอปพลิเคชัน

เมื่อทำงานกับเฟรมเวิร์กเช่น React, Vue หรือ Angular คุณกำลังใช้ architectural patterns เหล่านี้โดยธรรมชาติ ซึ่งมักจะผสมผสานกับ design patterns ขนาดเล็ก (เช่น Observer pattern สำหรับการจัดการ state) เพื่อสร้างแอปพลิเคชันที่แข็งแกร่ง


สรุป: การใช้ Patterns อย่างชาญฉลาด

JavaScript design patterns ไม่ใช่กฎที่ตายตัว แต่เป็นเครื่องมือที่ทรงพลังในคลังอาวุธของนักพัฒนา มันแสดงถึงภูมิปัญญาที่สั่งสมมาของชุมชนวิศวกรรมซอฟต์แวร์ ซึ่งนำเสนอโซลูชันที่สวยงามสำหรับปัญหาทั่วไป

กุญแจสำคัญในการเรียนรู้คือการไม่ท่องจำทุกรูปแบบ แต่ให้ทำความเข้าใจ ปัญหา ที่แต่ละรูปแบบแก้ไข เมื่อคุณเผชิญกับความท้าทายในโค้ดของคุณ ไม่ว่าจะเป็นการผูกมัดที่แน่นหนา, การสร้างอ็อบเจกต์ที่ซับซ้อน หรืออัลกอริทึมที่ไม่ยืดหยุ่น คุณก็จะสามารถเลือกใช้รูปแบบที่เหมาะสมเป็นโซลูชันที่กำหนดไว้อย่างดีได้

คำแนะนำสุดท้ายของเราคือ: เริ่มต้นด้วยการเขียนโค้ดที่ง่ายที่สุดที่ทำงานได้ เมื่อแอปพลิเคชันของคุณพัฒนาขึ้น ให้ refactor โค้ดของคุณไปสู่รูปแบบเหล่านี้ในจุดที่เหมาะสม อย่าบังคับใช้รูปแบบในที่ที่ไม่จำเป็น การนำไปใช้อย่างรอบคอบจะทำให้คุณเขียนโค้ดที่ไม่เพียงแต่ใช้งานได้ แต่ยังสะอาด, ขยายขนาดได้ และง่ายต่อการบำรุงรักษาไปอีกหลายปี