Menu
Coddy logo textTech

תבנית המאגר

חלק מהיחידה תכנות מונחה עצמים במסלול ה-Dart של Coddy. שיעור 100 מתוך 110.

תבנית Repository מפרידה בין לוגיקת הגישה לנתונים לבין הלוגיקה העסקית באמצעות יצירת שכבת הפשטה בין היישום שלך לבין מקורות הנתונים. במקום שהמחלקות שלך יתקשרו ישירות עם מסדי נתונים, ממשקי API או קבצים, הן עובדות עם מאגר שמטפל בכל פעולות הנתונים.

התבנית מגדירה ממשק לפעולות נתונים, ומימושים קונקרטיים מטפלים במנגנון האחסון בפועל. כך אפשר להחליף בקלות מקורות נתונים בלי לשנות את הלוגיקה העסקית שלך:

// ישות
class User {
  final int id;
  final String name;
  User(this.id, this.name);
}

// ממשק מאגר
abstract class UserRepository {
  User? getById(int id);
  List<User> getAll();
  void save(User user);
  void delete(int id);
}

// מימוש בזיכרון
class InMemoryUserRepository implements UserRepository {
  final Map<int, User> _users = {};

  @override
  User? getById(int id) => _users[id];

  @override
  List<User> getAll() => _users.values.toList();

  @override
  void save(User user) => _users[user.id] = user;

  @override
  void delete(int id) => _users.remove(id);
}

void main() {
  UserRepository repo = InMemoryUserRepository();
  
  repo.save(User(1, 'Alice'));
  repo.save(User(2, 'Bob'));
  
  print(repo.getById(1)?.name);  // Alice
  print(repo.getAll().length);    // 2
}

הלוגיקה העסקית שלך תלויה רק בממשק UserRepository. בהמשך תוכל ליצור DatabaseUserRepository או ApiUserRepository שמממשים את אותו ממשק, ולהחליף בין המימושים בלי לשנות שום קוד שמשתמש במאגר. הדפוס הזה חיוני ליישומים שאפשר לבדוק ולתחזק, שבהם מקורות הנתונים עשויים להשתנות עם הזמן.

challenge icon

אתגר

קל

בואו נבנה מערכת מלאי מוצרים באמצעות תבנית Repository! תיצרו שכבת הפשטה שמפרידה בין אופן אחסון המוצרים לבין אופן השימוש בהם, וכך יהיה קל להחליף מימושי אחסון בלי לשנות את הלוגיקה העסקית.

תארגנו את הקוד בשני קבצים:

  • product_repository.dart: הקובץ הזה מכיל את מחלקות הישות והמאגר. התחילו במחלקה Product עם שדות final עבור id (int), name (String) ו-price (double). לאחר מכן הגדירו מחלקה מופשטת בשם ProductRepository שמצהירה על החוזה לפעולות נתונים: getById(int id) שמחזירה Product שיכול להיות null, getAll() שמחזירה רשימת מוצרים, save(Product product) לשמירת מוצר, ו-delete(int id) להסרת מוצר. לבסוף, צרו InMemoryProductRepository שמממשת את הממשק הזה באמצעות Map<int, Product> לאחסון.
  • main.dart: ייבאו את קובץ המאגר והדגימו את תבנית Repository בפעולה. צרו InMemoryProductRepository, אבל אחסנו אותו במשתנה מהסוג ProductRepository — כך תראו שהקוד שלכם תלוי בממשק ולא במימוש. שמרו שלושה מוצרים: Laptop (id: 1, price: 999.99), Mouse (id: 2, price: 29.99) ו-Keyboard (id: 3, price: 79.99). לאחר מכן שלפו והדפיסו את המוצר עם המזהה 2 בפורמט Found: [name] - $[price]. מחקו את המוצר עם המזהה 1. לבסוף, הדפיסו את מספר המוצרים שנותרו בפורמט Products in stock: [count].

היתרון של התבנית הזו הוא שהקוד הראשי שלכם מכיר רק את הממשק ProductRepository. בהמשך תוכלו ליצור DatabaseProductRepository או ApiProductRepository ולהחליף אליו בלי לשנות אף חלק מהלוגיקה העסקית!

פלט צפוי:

Found: Mouse - $29.99
Products in stock: 2

נסו בעצמכם

import 'product_repository.dart';

void main() {
  // צרו מאגר מוצרים - שימו לב שהטיפוס הוא הממשק, לא המימוש
  // TODO: צרו InMemoryProductRepository ושמרו אותו במשתנה מסוג ProductRepository
  
  // TODO: שמרו שלושה מוצרים:
  // - Laptop (id: 1, price: 999.99)
  // - Mouse (id: 2, price: 29.99)
  // - Keyboard (id: 3, price: 79.99)
  
  // TODO: אחזרו את המוצר עם id 2 והדפיסו: "Found: [name] - $[price]"
  
  // TODO: מחקו את המוצר עם id 1
  
  // TODO: הדפיסו את מספר המוצרים שנותרו: "Products in stock: [count]"
}
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר Dart אונליין