Dark mode
Programming Paradigms
แต่ละกระบวนทัศน์การเขียนโปรแกรม (Programming Paradigm) มีจุดแข็งและจุดอ่อนที่แตกต่างกันไป ตารางด้านล่างแสดงการเปรียบเทียบระหว่างกระบวนทัศน์หลักๆ ที่นิยมใช้ในปัจจุบัน
กระบวนทัศน์ | Imperative | Functional | Object-Oriented |
---|---|---|---|
แนวคิดหลัก | เน้นการสั่งคอมพิวเตอร์ว่า "ทำอย่างไร" โดยใช้คำสั่งที่เปลี่ยนแปลงสถานะของโปรแกรม | เน้นการคำนวณผ่านการประเมินฟังก์ชันโดยไม่เปลี่ยนแปลงสถานะ | มองทุกอย่างเป็นวัตถุที่มีข้อมูลและพฤติกรรม |
จุดแข็ง | - เข้าใจง่าย - ประสิทธิภาพสูง - ควบคุมการทำงานได้ละเอียด | - ทดสอบง่าย - ลดบั๊กที่เกิดจากสถานะ - เหมาะกับการประมวลผลแบบขนาน | - เหมาะสำหรับระบบขนาดใหญ่ - ส่งเสริมการนำกลับมาใช้ใหม่ - ใกล้เคียงกับโลกจริง |
จุดอ่อน | - ยากต่อการดีบัก - ยากต่อการทดสอบ - มีโอกาสเกิดบั๊กสูง | - โค้ดอาจดูซับซ้อน - การเรียนรู้ยากกว่า - อาจมีประสิทธิภาพต่ำในบางกรณี | - อาจมีความซับซ้อนเกินจำเป็น - การออกแบบที่ดีต้องใช้ประสบการณ์ - มีโอเวอร์เฮดในการทำงาน |
ภาษาที่นิยมใช้ | C, Pascal, BASIC | Haskell, Clojure, Scala | Java, C++, Python |
ตัวอย่างโค้ด
ts
// จุดเด่น: เข้าใจง่าย ตรงไปตรงมา ควบคุมการทำงานได้ละเอียด
// จุดด้อย: ยากต่อการทดสอบเพราะมีการเปลี่ยนแปลงสถานะ (state) ภายใน
function sumEvenNumbers(max: number): number {
let sum = 0;
for (let i = 1; i <= max; i++) {
if (i % 2 === 0) {
sum += i;
}
}
return sum;
}
// การทดสอบต้องทำโดยเรียกฟังก์ชันและตรวจสอบค่าที่ส่งคืน
const result = sumEvenNumbers(100);
console.log(result === 2550 ? "ผ่าน" : "ไม่ผ่าน"); // ผ่าน
ts
// จุดเด่น: ฟังก์ชันบริสุทธิ์ (pure functions) ทดสอบง่าย คาดเดาผลลัพธ์ได้แม่นยำ
// จุดด้อย: อาจซับซ้อนสำหรับผู้เริ่มต้น และอาจมีประสิทธิภาพต่ำกว่าในบางกรณี
const generateRange = (start: number, end: number): number[] =>
Array.from({ length: end - start + 1 }, (_, i) => start + i);
const isEven = (num: number): boolean => num % 2 === 0;
const sum = (numbers: number[]): number =>
numbers.reduce((acc, val) => acc + val, 0);
// ฟังก์ชันย่อยแต่ละส่วนสามารถทดสอบแยกกันได้อย่างอิสระ
const sumOfEvens = (max: number): number =>
sum(generateRange(1, max).filter(isEven));
// ทดสอบแต่ละฟังก์ชันแยกกันได้
console.log(isEven(2) === true ? "ผ่าน" : "ไม่ผ่าน"); // ผ่าน
console.log(sum([2, 4, 6]) === 12 ? "ผ่าน" : "ไม่ผ่าน"); // ผ่าน
console.log(sumOfEvens(100) === 2550 ? "ผ่าน" : "ไม่ผ่าน"); // ผ่าน
ts
// จุดเด่น: แยกข้อมูลและพฤติกรรมเป็นหมวดหมู่ ขยายฟังก์ชันได้ง่ายผ่านการสืบทอด
// จุดด้อย: อาจมีความซับซ้อนเกินจำเป็นสำหรับงานง่ายๆ ทดสอบยากกว่าเพราะต้องสร้าง objects
// สร้าง interface เพื่อง่ายต่อการทดสอบด้วย mock objects
interface NumberCollection {
getNumbers(): number[];
}
class NumberRange implements NumberCollection {
constructor(private start: number, private end: number) {}
getNumbers(): number[] {
return Array.from(
{ length: this.end - this.start + 1 },
(_, i) => this.start + i,
);
}
}
class NumberCalculator {
constructor(private collection: NumberCollection) {}
getSumOfEvens(): number {
return this.collection.getNumbers()
.filter(num => num % 2 === 0)
.reduce((acc, val) => acc + val, 0);
}
}
// ทดสอบโดยใช้ mock object
const mockCollection: NumberCollection = {
getNumbers: () => [1, 2, 3, 4, 5, 6],
};
const calculator = new NumberCalculator(mockCollection);
console.log(calculator.getSumOfEvens() === 12 ? "ผ่าน" : "ไม่ผ่าน"); // ผ่าน
// ทดสอบกับข้อมูลจริง
const realCalculator = new NumberCalculator(new NumberRange(1, 100));
console.log(realCalculator.getSumOfEvens() === 2550 ? "ผ่าน" : "ไม่ผ่าน"); // ผ่าน
Comparison
Testing
ts
// จุดเด่น: เข้าใจง่าย ตรงไปตรงมา ควบคุมการทำงานได้ละเอียด
// จุดด้อย: ยากต่อการทดสอบเพราะมีการเปลี่ยนแปลงสถานะ (state) ภายใน
function sumEvenNumbers(max: number): number {
let sum = 0;
for (let i = 1; i <= max; i++) {
if (i % 2 === 0) {
sum += i;
}
}
return sum;
}
// การทดสอบต้องทำโดยเรียกฟังก์ชันและตรวจสอบค่าที่ส่งคืน
const result = sumEvenNumbers(100);
console.log(result === 2550 ? "ผ่าน" : "ไม่ผ่าน"); // ผ่าน
ts
// จุดเด่น: ฟังก์ชันบริสุทธิ์ (pure functions) ทดสอบง่าย คาดเดาผลลัพธ์ได้แม่นยำ
// จุดด้อย: อาจซับซ้อนสำหรับผู้เริ่มต้น และอาจมีประสิทธิภาพต่ำกว่าในบางกรณี
const generateRange = (start: number, end: number): number[] =>
Array.from({ length: end - start + 1 }, (_, i) => start + i);
const isEven = (num: number): boolean => num % 2 === 0;
const sum = (numbers: number[]): number =>
numbers.reduce((acc, val) => acc + val, 0);
// ฟังก์ชันย่อยแต่ละส่วนสามารถทดสอบแยกกันได้อย่างอิสระ
const sumOfEvens = (max: number): number =>
sum(generateRange(1, max).filter(isEven));
// ทดสอบแต่ละฟังก์ชันแยกกันได้
console.log(isEven(2) === true ? "ผ่าน" : "ไม่ผ่าน"); // ผ่าน
console.log(sum([2, 4, 6]) === 12 ? "ผ่าน" : "ไม่ผ่าน"); // ผ่าน
console.log(sumOfEvens(100) === 2550 ? "ผ่าน" : "ไม่ผ่าน"); // ผ่าน
ts
// จุดเด่น: แยกข้อมูลและพฤติกรรมเป็นหมวดหมู่ ขยายฟังก์ชันได้ง่ายผ่านการสืบทอด
// จุดด้อย: อาจมีความซับซ้อนเกินจำเป็นสำหรับงานง่ายๆ ทดสอบยากกว่าเพราะต้องสร้าง objects
// สร้าง interface เพื่อง่ายต่อการทดสอบด้วย mock objects
interface NumberCollection {
getNumbers(): number[];
}
class NumberRange implements NumberCollection {
constructor(private start: number, private end: number) {}
getNumbers(): number[] {
return Array.from(
{ length: this.end - this.start + 1 },
(_, i) => this.start + i,
);
}
}
class NumberCalculator {
constructor(private collection: NumberCollection) {}
getSumOfEvens(): number {
return this.collection.getNumbers()
.filter(num => num % 2 === 0)
.reduce((acc, val) => acc + val, 0);
}
}
// ทดสอบโดยใช้ mock object
const mockCollection: NumberCollection = {
getNumbers: () => [1, 2, 3, 4, 5, 6],
};
const calculator = new NumberCalculator(mockCollection);
console.log(calculator.getSumOfEvens() === 12 ? "ผ่าน" : "ไม่ผ่าน"); // ผ่าน
// ทดสอบกับข้อมูลจริง
const realCalculator = new NumberCalculator(new NumberRange(1, 100));
console.log(realCalculator.getSumOfEvens() === 2550 ? "ผ่าน" : "ไม่ผ่าน"); // ผ่าน
Debugging
ts
// จุดเด่น: ง่ายต่อการเพิ่ม log เพื่อติดตามการทำงานในแต่ละขั้นตอน
// จุดด้อย: ต้องเพิ่ม log หลายจุด และอาจทำให้โค้ดรกเมื่อต้องการดีบัก
function sumEvenNumbers(max: number): number {
let sum = 0;
console.log(`เริ่มต้นคำนวณผลรวมเลขคู่จาก 1 ถึง ${max}`);
for (let i = 1; i <= max; i++) {
console.log(`กำลังตรวจสอบ i = ${i}`);
if (i % 2 === 0) {
const oldSum = sum;
sum += i;
console.log(`${i} เป็นเลขคู่: ${oldSum} + ${i} = ${sum}`);
} else {
console.log(`${i} เป็นเลขคี่: ข้าม`);
}
}
console.log(`ผลรวมสุดท้าย: ${sum}`);
return sum;
}
sumEvenNumbers(10); // ลองกับตัวเลขเล็กๆ ก่อนเพื่อดีบัก
ts
// จุดเด่น: สามารถตรวจสอบข้อมูลโดยไม่เปลี่ยนแปลงโครงสร้างโค้ด ใช้ฟังก์ชัน debug helper
// จุดด้อย: อาจต้องสร้างฟังก์ชัน helper เพิ่มเติมสำหรับการดีบัก
// ฟังก์ชัน debug helper ที่ไม่เปลี่ยนแปลงข้อมูล
const debug = <T>(label: string, value: T): T => {
console.log(`${label}:`, value);
return value;
};
const sumOfEvens = (max: number): number =>
debug('ผลลัพธ์สุดท้าย',
Array.from({ length: max }, (_, i) => i + 1)
|> debug('สร้างช่วงตัวเลข', #)
|> #.filter(num =>
debug(`ตรวจสอบ ${num}`, num % 2 === 0 ? `${num} เป็นเลขคู่` : `${num} เป็นเลขคี่`)
&& num % 2 === 0
)
|> debug('กรองเฉพาะเลขคู่', #)
|> #.reduce((acc, val) =>
debug('การรวม', `${acc} + ${val} = ${acc + val}`), 0
)
);
sumOfEvens(10); // ลองกับตัวเลขเล็กๆ ก่อนเพื่อดีบัก