ออบเจ็กต์และโครงสร้างข้อมูลมีบทบาทสำคัญในการพัฒนาซอฟต์แวร์ และการปฏิบัติตามแนวทางปฏิบัติของโค้ดที่สะอาด เราจะสามารถเพิ่มความสามารถในการอ่าน การบำรุงรักษา และความยืดหยุ่นของโค้ดของเราได้ เราจะเจาะลึกเรื่องการห่อหุ้ม, ตัวดัดแปลงการเข้าถึง, วิธี getter และ setter, องค์ประกอบเหนือการสืบทอด, การลดสถานะที่ไม่แน่นอนให้เหลือน้อยที่สุด และ Single Responsibility Principle (SRP) มีเหตุผลที่เราเก็บตัวแปรของเราไว้เป็นส่วนตัว เราไม่ต้องการให้ใครพึ่งพาพวกเขา เราต้องการรักษาเสรีภาพในการเปลี่ยนแปลงประเภทหรือการนำไปใช้โดยไม่ได้ตั้งใจหรือตามแรงกระตุ้น
1. การห่อหุ้มข้อมูล
การห่อหุ้มหมายถึงการรวมข้อมูลและพฤติกรรมที่เกี่ยวข้องเข้าด้วยกันภายในคลาสหรืออินเทอร์เฟซ ช่วยให้เราสามารถควบคุมการเข้าถึงข้อมูลและซ่อนรายละเอียดการใช้งานภายในได้ ด้วยการห่อหุ้มข้อมูล เราสามารถจัดเตรียมอินเทอร์เฟซที่ชัดเจนสำหรับการโต้ตอบกับวัตถุได้
class Car { private brand: string; private model: string; constructor(brand: string, model: string) { this.brand = brand; this.model = model; } public getBrand(): string { return this.brand; } public getModel(): string { return this.model; } }
ในตัวอย่างนี้ เราสรุปคุณสมบัติ brand
และ model
ภายในคลาส Car
เราใช้ตัวแก้ไขการเข้าถึงส่วนตัวเพื่อจำกัดการเข้าถึงคุณสมบัติเหล่านี้โดยตรง แต่เราจัดเตรียมวิธีการรับสาธารณะ (getBrand()
และ getModel()
) เพื่อเข้าถึงค่า การห่อหุ้มนี้ช่วยให้แน่ใจว่ารายละเอียดภายในของคลาส Car
ถูกซ่อนอยู่ และเข้าถึงข้อมูลผ่านอินเทอร์เฟซที่มีการควบคุม
2. หลีกเลี่ยงวิธีการ Getter และ Setter
เมธอด getter และ setter แบบดั้งเดิมใช้เพื่อเข้าถึงและเปลี่ยนคุณสมบัติของอ็อบเจ็กต์ อย่างไรก็ตาม สิ่งเหล่านี้สามารถนำไปสู่การละเมิด Law of Demeter ส่งผลให้เกิดโค้ดที่เชื่อมโยงกันอย่างแน่นหนา แต่เราสามารถใช้คุณสมบัติซึ่งมีไวยากรณ์ที่สะอาดตาและส่งเสริมให้อ่านง่ายแทน
class Rectangle { private width: number; private height: number; constructor(width: number, height: number) { this.width = width; this.height = height; } public get area(): number { return this.width * this.height; } public setDimensions(width: number, height: number): void { this.width = width; this.height = height; } }
ในตัวอย่างนี้ เราใช้คุณสมบัติ area
เพื่อคำนวณพื้นที่ของสี่เหลี่ยมผืนผ้า แทนที่จะเรียกวิธีแยกเช่น calculateArea()
เราสามารถเข้าถึงพื้นที่ได้โดยตรงเหมือนกับเป็นทรัพย์สินปกติ นอกจากนี้ เรายังมีเมธอด setDimensions()
เพื่ออัปเดตขนาดของสี่เหลี่ยม ซึ่งช่วยให้ไม่จำเป็นต้องใช้เมธอด getter และ setter แยกกัน
3. ชอบองค์ประกอบมากกว่ามรดก
การสืบทอดช่วยให้เราสามารถสร้างวัตถุใหม่โดยการสืบทอดคุณสมบัติและพฤติกรรมจากวัตถุที่มีอยู่ อย่างไรก็ตาม อาจนำไปสู่การเชื่อมโยงที่แน่นแฟ้นระหว่างคลาสต่างๆ และทำให้โค้ดมีความยืดหยุ่นน้อยลง ในทางกลับกัน องค์ประกอบจะส่งเสริมโค้ดเบสที่ยืดหยุ่นและบำรุงรักษาได้มากขึ้นโดยการรวมออบเจ็กต์ที่เรียบง่ายกว่าเพื่อสร้างวัตถุที่ซับซ้อน
class Engine { public start(): void { console.log('Engine started'); } } class Car { private engine: Engine; constructor() { this.engine = new Engine(); } public startEngine(): void { this.engine.start(); } }
ในตัวอย่างนี้ เราให้ความสำคัญกับการเรียบเรียงมากกว่าการสืบทอด แทนที่จะสร้างคลาส Car
ที่ขยายคลาส Engine
เราสร้างคลาส Engine
แยกต่างหากและรวมไว้เป็นคุณสมบัติภายในคลาส Car
วิธีการจัดองค์ประกอบนี้ช่วยให้เราสลับการใช้งานเอ็นจิ้นที่แตกต่างกันได้อย่างง่ายดายโดยไม่ส่งผลกระทบต่อคลาส Car
4. การลดสถานะที่ไม่แน่นอนให้เหลือน้อยที่สุด
สถานะที่ไม่แน่นอนหมายถึงวัตถุหรือข้อมูลที่สามารถเปลี่ยนแปลงได้หลังจากการสร้าง แม้ว่าบางครั้งความผันแปรจะมีความจำเป็น แต่การลดสถานะที่ไม่แน่นอนให้เหลือน้อยที่สุดสามารถลดความซับซ้อนและปรับปรุงการบำรุงรักษาโค้ดได้ การชอบความไม่เปลี่ยนรูปทำให้โค้ดง่ายต่อการให้เหตุผลและช่วยป้องกันผลข้างเคียงที่ไม่ได้ตั้งใจ
function calculateTotalPrice(prices) { let totalPrice = 0; for (const price of prices) { totalPrice += price; } return totalPrice; } const prices = [10, 20, 30, 40]; const total = calculateTotalPrice(prices);
ในตัวอย่าง JavaScript นี้ เราคำนวณราคารวมโดยการรวมอาร์เรย์ของราคา ตัวแปร totalPrice
ถูกประกาศโดยใช้คีย์เวิร์ด let
เพื่อให้สามารถเปลี่ยนแปลงภายในลูปได้ อย่างไรก็ตาม อาร์เรย์ prices
ยังคงไม่เปลี่ยนรูป ด้วยการลดสถานะที่ไม่แน่นอนให้เหลือน้อยที่สุดและหลีกเลี่ยงการกลายพันธุ์ของตัวแปรที่ไม่จำเป็น เราจึงสร้างโค้ดที่สามารถคาดเดาและบำรุงรักษาได้มากขึ้น
5. การปฏิบัติตามหลักการความรับผิดชอบเดียว (SRP)
หลักการความรับผิดชอบเดี่ยว (SRP) ระบุว่าวัตถุหรือหน้าที่ควรมีความรับผิดชอบเดี่ยวหรือทำสิ่งใดสิ่งหนึ่งได้ดี ด้วยการยึดมั่นใน SRP เราจึงสร้างส่วนประกอบที่มีขนาดเล็กลงและเน้นมากขึ้น ซึ่งง่ายต่อการเข้าใจ ทดสอบ และบำรุงรักษา
class Logger { public logError(message: string): void { // Log the error message to a file or console } public logMetric(metric: string, value: number): void { // Log the metric and its value to a monitoring system } } class PaymentProcessor { private logger: Logger; constructor(logger: Logger) { this.logger = logger; } public processPayment(amount: number): void { try { // Process the payment logic } catch (error) { this.logger.logError('Payment processing failed'); } } }
ในตัวอย่างนี้ เราสาธิต SRP โดยการแยกข้อกังวลออกเป็นสองคลาส: Logger
และ PaymentProcessor
คลาส Logger
มีหน้าที่รับผิดชอบในการบันทึกข้อผิดพลาดและตัวชี้วัด ในขณะที่คลาส PaymentProcessor
มุ่งเน้นไปที่การประมวลผลการชำระเงินเพียงอย่างเดียว โดยการแยกความรับผิดชอบ แต่ละชั้นเรียนจะมีความสอดคล้องและเข้าใจได้ง่ายขึ้น
บทสรุป
ออบเจ็กต์และโครงสร้างข้อมูลเป็นองค์ประกอบพื้นฐานของการพัฒนาซอฟต์แวร์ ด้วยการใช้หลักการของโค้ดที่สะอาดกับออบเจ็กต์และโครงสร้างข้อมูล เราสามารถปรับปรุงความสามารถในการอ่าน การบำรุงรักษา และความยืดหยุ่นของโค้ดของเราได้ ตลอดบทนี้ เราได้สำรวจการห่อหุ้มข้อมูล การหลีกเลี่ยงวิธีการ getter และ setter นิยมองค์ประกอบมากกว่าการสืบทอด ลดสถานะที่ไม่แน่นอนให้เหลือน้อยที่สุด และยึดมั่นใน Single Responsibility Principle (SRP) ด้วยการปฏิบัติตามหลักการเหล่านี้และปรับให้เข้ากับข้อกำหนดเฉพาะของโครงการของเรา เราจะสามารถเขียนโค้ดที่สะอาดตาและแข็งแกร่งยิ่งขึ้นได้