Thuta Learning
ရှာဖွေရန်
ProjectsProgrammingintermediate

Mini Project: Task Manager - Part 3 (Generics & Polish)

စိတ်လျှော့ပါ။ ဒီခန်းကို စာအုပ်လိုမဟုတ်ဘဲ စကားပြောသလိုပဲ၊ နားလည်လွယ်အောင် ရှင်းပါမယ်။

ဒီခန်းပြီးရင် ဘာတတ်သွားမလဲ

  • Mini Project: Task Manager - Part 3 (Generics & Polish) ကို လက်တွေ့ project ထဲမှာ အသုံးချတတ်မယ်
  • ကိုယ်တိုင် code ရေးပြီး run ကြည့်တတ်မယ်
  • Project တစ်ခုလုံးကို အဆင့်လိုက် ဆောက်တတ်မယ်

ခဏလေး ဒီလိုပဲ စဉ်းစားကြည့်

Project ရဲ့ နောက်ဆုံးအဆင့်မှာ generics ကို အသုံးပြုပြီး code ကို ပိုပြီး flexible ဖြစ်အောင် refactor လုပ်ပါမယ်။ Task type အတွက်ချည်း အလုပ်လုပ်တဲ့ TaskManager အစား, ဘယ် type ကိုမဆို သိမ်းဆည်းနိုင်တဲ့ generic Repository<T> class တစ်ခု ဖန်တီးပါမယ်။ ဒါက real-world project တွေမှာ code duplication ကို ဘယ်လို လျှော့ချနိုင်လဲဆိုတာ ပြသပေးပါလိမ့်မယ်။ ထို့အပြင် tuple type ကို အသုံးပြုပြီး summary statistics (total count, done count) ကို ပြန်ပေးတဲ့ function တစ်ခုလည်း ထည့်ပါမယ်။ ဒီအဆင့်ပြီးရင် project တစ်ခုလုံးက setup, feature, polish ဆိုတဲ့ layer သုံးထပ်နှင့် ပြီးမြောက်သွားပါလိမ့်မယ်။

လက်တွေ့ ဆောက်ကြည့်မယ်

Repository<T> ဆိုတဲ့ generic class တစ်ခု ဖန်တီးပြီး private items: T[] = [], add(item: T): void, getAll(): T[], find(predicate: (item: T) => boolean): T | undefined ဆိုတဲ့ method များ implement လုပ်ပါ။ TaskManager class ကို Repository<Task> ကို internally အသုံးပြုအောင် ပြောင်းရေးပါ (composition အနေဖြင့်)။ getStats(): [number, number] ဆိုတဲ့ tuple ကို ပြန်ပေးတဲ့ function တစ်ခု ထည့်ပြီး၊ [total, doneCount] ပုံစံဖြင့် return ပြန်ပါ။ နောက်ဆုံးအနေဖြင့် error handling အနေနဲ့ updateStatus() ခေါ်တဲ့အခါ id မတွေ့ရင် console.error() ဖြင့် error message ပြသအောင် ထည့်ပြီး project ကို demo run လုပ်ကြည့်ပါ။

Code နမူနာ

typescript
class Repository<T> {
  private items: T[] = [];

  add(item: T): void {
    this.items.push(item);
  }

  getAll(): T[] {
    return this.items;
  }

  find(predicate: (item: T) => boolean): T | undefined {
    return this.items.find(predicate);
  }
}

function getStats(repo: Repository<Task>): [number, number] {
  const all = repo.getAll();
  const total = all.length;
  const doneCount = all.filter((t) => t.status === TaskStatus.Done).length;
  return [total, doneCount];
}

const taskRepo = new Repository<Task>();
taskRepo.add({ id: 1, title: "Learn generics", status: TaskStatus.Done, priority: "high" });
taskRepo.add({ id: 2, title: "Write tests", status: TaskStatus.Todo, priority: "medium" });

const [total, done] = getStats(taskRepo);
console.log(`Total: ${total}, Done: ${done}`);

const missing = taskRepo.find((t) => t.id === 99);
if (!missing) {
  console.error("Task not found: id 99");
}
You should see
"Total: 2, Done: 1" ဟု console တွင် ပြသပြီး၊ id 99 ရှာမတွေ့သောကြောင့် error message တစ်ကြောင်း ပြသပေးမည်။

၅ မိနစ် စမ်းကြည့်

Repository<T> class ကို string[] ကိစ္စ (e.g. tags list) အတွက်လည်း ပြန်လည်အသုံးပြုကြည့်ပြီး၊ generic class တစ်ခုတည်းကို data type မတူညီသော case နှစ်ခုတွင် သုံးနိုင်ကြောင်း စမ်းသပ်ကြည့်ပါ။

သတိလေးတစ်ချက်

Generic class တစ်ခုကို composition (class တစ်ခုအတွင်း property အဖြစ် ထည့်ခြင်း) ဖြင့် အသုံးပြုခြင်းက inheritance ထက် flexible ပြီး testing ပိုလွယ်ကူစေတတ်ကြောင်း project ကြီးများတွင် သတိပြုသင့်ပါသည်။

ဒီနေရာမှာ လူအများမှားတတ်တယ်

  • Repository<T> ကို instantiate လုပ်တဲ့အခါ type argument (new Repository<Task>()) ကို မထည့်ဘဲ any type အဖြစ် infer ဖြစ်သွားခြင်း
  • tuple return type [number, number] ကို function ရဲ့ return statement ထဲမှာ array literal အနေဖြင့်ချည်း ရေးပြီး element order ကို မှားထားခြင်း (total, doneCount နေရာ ပြောင်းရေးမိခြင်း)

အခု ကိုယ်တိုင် စမ်းကြည့်

Repository<T> class ကို string[] ကိစ္စ (e.g. tags list) အတွက်လည်း ပြန်လည်အသုံးပြုကြည့်ပြီး၊ generic class တစ်ခုတည်းကို data type မတူညီသော case နှစ်ခုတွင် သုံးနိုင်ကြောင်း စမ်းသပ်ကြည့်ပါ။

You'll know it worked when: "Total: 2, Done: 1" ဟု console တွင် ပြသပြီး၊ id 99 ရှာမတွေ့သောကြောင့် error message တစ်ကြောင်း ပြသပေးမည်။

Mini Project: Task Manager - Part 3 (Generics & Polish) | Thuta Learning